Jak niskim kosztem obsłużyć DUŻY ruch webowy? 🤔
Kilkaset tysięcy UNIQ dziennie za... 11zł/miesiąc.
Case-study serwisu sejm.stream
Wątek 🧵 ↓
W połowie stycznia 2024 zauważyłem podejrzanie dziwny skok ruchu na jednym z serwerów webowych w mojej firmie hostingowej.
Mam na myśli zwiększenie ruchu o jakieś 10 tysięcy razy 😱
Czyżby atak DDoS? Nie tym razem! 😏
Jeden z użytkowników uruchomił na Mikrusie (mikr.us) portal, który miał służyć łatwemu oglądaniu transmisji sejmowych z wielu kamer jednocześnie.
Właściciel nie przewidział jednak, z jak wielkim zainteresowaniem spotka się jego rozwiązanie.
Aplikacja wylądowała z płomieniem na głównej stronie Wykopu.
Zwiększony ruch był widoczny w statystykach, ale niespecjalnie przeszkadzało to komukolwiek.
Spoko... Wykop odpieraliśmy już wiele razy na stronach userów Mikrusa. Można liczyć na ruch rzędu jakichś 20-40 tysięcy wejść na dzień.
Tylko info o stronie podało jeszcze Radio RMF FM.
Ruch wzrastał. Autor strony wrzucił ją dodatkowo na Linkedin, gdzie zyskała 920+ lajków.
Temat podchwyciła redakcja GeekWeek i portal został wspomniany na głównej stronie Interii. Zaczynało być gorąco, a działo się to w zaledwie kilka godzin od odpalenia projektu.
Gwoździem do trumny było podanie linka przez najbardziej opiniotwórcze medium w naszym kraju... 😉😃
😱 Make_Life_harder wrzuciło URL-a na swoje storiski na IG 😱
🔥 Serwery zaczęły płonąć 🔥
🧉 To ten moment, gdy poszedłem po dolewkę Yerba Mate.
Aplikacja "sejm.stream" napisana jest w Pythonie, a konkretniej mówiąc we frameworku Django. To, co widzisz na domenie teraz, to już wersja zoptymalizowana.
Całość została zdeployowana na Mikrusa 3.0:
2GB RAM + 25GB dysku za 130zł/rok (~11zł/msc)
Użytkownicy Mikrusa mogą przepuszczać cały ruch bezpośrednio do swojego serwera albo mogą skorzystać z naszej 'tarczy' zwanej Cytrusem.
Użytkownik, spodziewając się zwiększonego ruchu, zawczasu aktywował tarczę 🛡️
Tajemnicza 'tarcza' to zwykły, lekko stuningowany Nginx odpalony na dość mocnej maszynie posiadającej dziesiątki razy więcej RAM-u niż VPS użytkownika.
Odfiltrowuje on skanery, boty z Chin, dziwne połączenia z automatów oraz kolejkuje połączenia do backendu.
Początkowo, każdy odwiedzający 'Sejmflix' generował kilka requestów, co przemnożone przez liczbę odwiedzających dawało kilka milionów zapytań, które musiały zostać dostarczone do pierwotnego backendu.
Obsługa ruchu z sejmflixa konsumowała około 12 GB RAM.
Wraz z adminami mamy gotowe scenariusze na obsłużenie takich akcji.
Pierwszy krok to analiza requestów i wybranie tego, co możemy zaklasyfikować jako statyczny content.
Nie ma sensu statycznych plików podawać wprost z backendu, więc skorzystaliśmy z cache na Nginx.
Ustawienie cache składało się z dwóch kroków.
Pierwszym było ustawienie strefy cache dla Nginx.
Krok drugi to oczywiście przepuszczenie ruchu przez utworzoną strefę z uwzględnieniem odpowiednich nagłówków cachujących.
Zwróć uwagę na cachowanie nie tylko poprawnych odpowiedzi, ale także errorów 404.
Może dziwić Cię cache ustawiony na 5 sekund, bo dlaczego nie 5 minut, albo i na godzinę?!
Autor serwisu stale rozbudowywał go i modyfikował kod. Na miejscu dewelopera nie chciałbym, aby moje zmiany były widoczne na produkcji z opóźnieniem np. 60 minut.
Taka technika microcachingu jest PRAWIE niezauważalna dla właściciela strony (ideałem byłoby ustawienie cache np. na 1s), ale sprawia to, że backend otrzymuje uderzenie tylko raz na 5 sekund, co drastycznie odciąża aplikację w Django.
Kolejnym krokiem było dorzucenie zapasowego upstreama dla serwisu. Zawierał tylko informację 'proszę czekać...' i przekierowanie na główną stronę po kilku sekundach. Pojawiał się, gdy backend nie wyrabiał.
Doczytaj, czym jest keepalive w kontekście upstream!
Autor serwisu bardzo sprytnie zbudował stronę w taki sposób, aby pliki CSS i JS ładowane były z publicznych CDN-ów, co też przyczyniło się do zmniejszenia obciążenia. Na serwerze zostały tylko dwa elementy, które niepotrzebnie bombardowały backend.
Oba poszły do cache 😎
Ta garstka poprawek zmniejszyła znacząco liczbę requestów do backendu.
Kolejne kroki optymalizujące wymagały nawiązania współpracy z autorem serwisu.
Dolewka Yerby, szybki telefon do Mateusza Górskiego (autora) i Sejmflix schowany został za usługą Cloudflare.
Aby Cloudflare działał optymalnie, warto też powiedzieć mu, co i na jak długo może cachować. Tutaj pomogło dodanie nagłówków cachujących.
Jako że na stronie zostały już tylko pliki SVG i ICO, to one poszły do mocnego, 4-godzinnego cache.
Zaprezentowane tutaj rozwiązania, to nie jest jakiś rocket science, a jedynie podstawy konfiguracji serwera webowego.
Wykorzystana 'tarcza' (Cytrus) ułatwiła życie autorowi, bo kwestia optymalizacji została przeniesiona na adminów Mikrusa. Nie było to niezbędne rozwiązanie.
Te same rozwiązania dałoby się zastosować na pojedynczym serwerze z około 4-8GB pamięci RAM.
Dodatkowo warto byłoby na przyszłość przemyśleć renderowanie tego, co podaje Django do statycznych plików, tak aby dynamiczny backend nie był wcale potrzebny.