Jak przetrwaliśmy 10-krotny wzrost obciążenia pracą zdalnie i jakie wyciągnęliśmy wnioski

Hej Habra! Przez ostatnie kilka miesięcy żyliśmy w bardzo ciekawej sytuacji i chciałbym podzielić się naszą historią skalowania infrastruktury. W tym czasie SberMarket czterokrotnie zwiększył zamówienia i uruchomił usługę w 4 nowych miastach. Gwałtowny wzrost popytu na dostawę artykułów spożywczych wymagał od nas skalowania naszej infrastruktury. Przeczytaj o najciekawszych i najbardziej przydatnych wnioskach pod wycięciem.

Jak przetrwaliśmy 10-krotny wzrost obciążenia pracą zdalnie i jakie wyciągnęliśmy wnioski

Nazywam się Dima Bobylev, jestem dyrektorem technicznym SberMarket. Ponieważ jest to pierwszy wpis na naszym blogu, powiem kilka słów o sobie i firmie. Jesienią ubiegłego roku brałem udział w konkursie dla młodych liderów Runetu. Do konkursu I napisał krótką historię o tym, jak postrzegamy kulturę wewnętrzną i podejście do rozwoju usług w SberMarket. I choć nie udało mi się wygrać konkursu, sformułowałem sobie podstawowe zasady rozwoju ekosystemu IT.

Podczas zarządzania zespołem ważne jest, aby zrozumieć i znaleźć równowagę między potrzebami biznesowymi a potrzebami poszczególnych programistów. Teraz SberMarket rośnie 13 razy w roku, co wpływa na produkt, wymagając ciągłego zwiększania wolumenu i tempa rozwoju. Mimo to poświęcamy programistom wystarczająco dużo czasu na wstępną analizę i wysokiej jakości kodowanie. Wykształcone podejście pomaga nie tylko w stworzeniu działającego produktu, ale także w jego dalszym skalowaniu i rozwoju. W wyniku tego wzrostu SberMarket stał się już liderem wśród usług dostawy artykułów spożywczych: dostarczamy około 18 3500 zamówień dziennie, podczas gdy na początku lutego było ich około XNUMX.

Jak przetrwaliśmy 10-krotny wzrost obciążenia pracą zdalnie i jakie wyciągnęliśmy wnioski
Pewnego dnia klient poprosił kuriera SberMarket, aby dostarczył mu zakupy spożywcze bezdotykowo — bezpośrednio na balkon.

Ale przejdźmy do konkretów. W ciągu ostatnich kilku miesięcy aktywnie skalowaliśmy infrastrukturę naszej firmy. Potrzeba ta została wyjaśniona czynnikami zewnętrznymi i wewnętrznymi. Równolegle z rozwojem bazy klientów wzrosła liczba podłączonych sklepów z 90 na początku roku do ponad 200 w połowie maja. Oczywiście przygotowaliśmy się, zarezerwowaliśmy główną infrastrukturę i liczyliśmy na możliwość pionowego i poziomego skalowania wszystkich maszyn wirtualnych hostowanych w chmurze Yandex. Jednak praktyka pokazała: „Wszystko, co może pójść źle, pójdzie źle”. A dzisiaj chcę podzielić się najciekawszymi sytuacjami, które wydarzyły się w ciągu tych tygodni. Mam nadzieję, że nasze doświadczenie będzie dla Ciebie przydatne.

Niewolnik w pełnej gotowości bojowej

Jeszcze przed rozpoczęciem pandemii mieliśmy do czynienia ze wzrostem liczby zapytań do naszych serwerów backendowych. Trend zamawiania artykułów spożywczych z dostawą do domu zaczął nabierać rozpędu, a wraz z wprowadzeniem pierwszych środków samoizolacji w związku z COVID-19, obciążenie przez cały dzień dramatycznie rosło na naszych oczach. Zaistniała potrzeba szybkiego odciążenia serwerów głównych głównej bazy danych i przeniesienia części żądań odczytu na serwery replik (slave).

Przygotowywaliśmy się do tego kroku z wyprzedzeniem, a 2 serwery podrzędne już działały na taki manewr. Pracowali głównie nad zadaniami wsadowymi do generowania kanałów informacyjnych do wymiany danych z partnerami. Te procesy stworzyły dodatkowe obciążenie i całkiem słusznie zostały wyjęte z nawiasu kilka miesięcy wcześniej. 

Ponieważ replikacja odbywała się na Slave, trzymaliśmy się koncepcji, że aplikacje mogą z nimi pracować tylko w trybie tylko do odczytu. Plan Disaster Recovery zakładał, że w przypadku katastrofy możemy po prostu zamontować Slave w miejsce Master i przełączyć wszystkie żądania zapisu i odczytu na Slave. Chcieliśmy jednak również wykorzystać repliki na potrzeby działu analityki, więc serwery nie były do ​​końca ustawione w status tylko do odczytu, a każdy host miał swój własny zestaw użytkowników, a niektórzy mieli uprawnienia zapisu do zapisywania pośrednich wyników obliczeń.

Do pewnego poziomu obciążenia mieliśmy wystarczającą ilość mastera zarówno do zapisu, jak i odczytu podczas przetwarzania żądań http. W połowie marca, kiedy Sbermarket zdecydował się całkowicie przejść na pracę zdalną, zaczęliśmy multiplikować wzrost RPS. Coraz więcej naszych klientów przechodziło na samoizolację lub pracę zdalną, co znalazło odzwierciedlenie we wskaźnikach obciążenia.

Wydajność „mastera” już nie wystarczała, więc część najcięższych żądań odczytu zaczęliśmy przenosić do repliki. Aby w przejrzysty sposób kierować żądania zapisu do urządzenia nadrzędnego i żądania odczytu do urządzenia podrzędnego, użyliśmy rubinowego klejnotu „Ośmiornica". Stworzyliśmy specjalnego użytkownika z postfiksem _readonly bez uprawnień do zapisu. Ale z powodu błędu w konfiguracji jednego z hostów część żądań zapisu trafiła do serwera podrzędnego w imieniu użytkownika, który miał odpowiednie uprawnienia.

Problem nie objawił się od razu, bo. zwiększone obciążenie zwiększyło zaległości niewolników. Niespójność danych została odkryta rano, kiedy po nocnych importach niewolnicy nie „dogonili” pana. Tłumaczyliśmy to dużym obciążeniem samego serwisu oraz importami związanymi z uruchamianiem nowych sklepów. Ale niedopuszczalne było podawanie danych z wielogodzinnym opóźnieniem i przerzuciliśmy procesy na drugiego analitycznego niewolnika, bo miałоWiększe zasoby i nie był obciążony żądaniami odczytu (tak tłumaczyliśmy sobie brak opóźnienia replikacji).

Kiedy odkryliśmy przyczyny „rozprzestrzeniania się” głównego niewolnika, analityczny już zawiódł z tego samego powodu. Pomimo obecności dwóch dodatkowych serwerów, na które planowaliśmy przenieść obciążenie w przypadku awarii mastera, w wyniku niefortunnego błędu okazało się, że w krytycznym momencie nie ma ani jednego.

Ale ponieważ nie tylko zrzuciliśmy bazę danych (przywracanie trwało wtedy około 5 godzin), ale także migawkę serwera głównego, udało nam się uruchomić replikę w ciągu 2 godzin. To prawda, po tym oczekiwano od nas długiego przewijania dziennika replikacji (ponieważ proces odbywa się w trybie jednowątkowym, ale to zupełnie inna historia).

Wnioski: Po takim incydencie stało się jasne, że należy porzucić praktykę ograniczania zapisu dla użytkowników i zadeklarować cały serwer jako readonly. Dzięki takiemu podejściu masz pewność, że repliki będą dostępne w krytycznym momencie.

Optymalizacja nawet jednego ciężkiego zapytania może przywrócić bazę danych do życia

Chociaż stale aktualizujemy katalog na stronie, żądania, które skierowaliśmy do serwerów Slave, pozwoliły na niewielkie opóźnienie w stosunku do Master. Czas, w którym odkryliśmy i wyeliminowaliśmy problem „nagle zboczonych” niewolników był czymś więcej niż „barierą psychologiczną” (w tym czasie ceny mogły być aktualizowane, a klienci widzieli nieaktualne dane) i byliśmy zmuszeni do zmiany wszystkie zapytania do głównego serwera bazy danych. W rezultacie strona działała wolno… ale przynajmniej działała. A gdy Slave wracał do zdrowia, nie pozostało nam nic innego, jak tylko optymalizacja. 

Podczas gdy serwery Slave dochodziły do ​​siebie, minuty powoli dłużyły się, Master pozostawał przeciążony, a my włożyliśmy wszystkie nasze wysiłki w optymalizację aktywnych zadań zgodnie z Regułą Pareto: wybraliśmy zapytania TOP, które dają większość obciążenia i przystąpiliśmy do strojenia. To było zrobione w locie.

Ciekawym efektem było to, że załadowany po uszy MySQL reagował na nawet niewielkie usprawnienie procesów. Optymalizacja kilku zapytań, które dały tylko 5% całkowitego obciążenia, wykazała już zauważalne odciążenie procesora. W rezultacie byliśmy w stanie zapewnić akceptowalną rezerwę zasobów dla Mastera do pracy z bazą danych i uzyskać niezbędny czas na odtworzenie replik. 

Wnioski: Nawet niewielka optymalizacja pozwala „przeżyć” przeciążenie przez kilka godzin. To wystarczyło, abyśmy przywrócili serwery z replikami. Przy okazji omówimy techniczną stronę optymalizacji zapytań w jednym z kolejnych wpisów. Więc subskrybuj nasz blog, jeśli może ci się przydać.

Zorganizuj monitorowanie kondycji usług partnerskich

Przetwarzamy zamówienia od klientów, dlatego nasze usługi stale wchodzą w interakcje z interfejsami API innych firm - są to bramki do wysyłania SMS-ów, platformy płatnicze, systemy trasowania, geokoder, Federalna Służba Podatkowa i wiele innych systemów. A kiedy obciążenie zaczęło gwałtownie rosnąć, zaczęliśmy napotykać ograniczenia API naszych usług partnerskich, o których wcześniej nawet nie myśleliśmy.

Nieoczekiwane przekroczenie limitów usług partnerów może spowodować przestój w działaniu. Wiele interfejsów API blokuje klientów, którzy przekraczają limity, aw niektórych przypadkach nadmiar żądań może przeciążyć produkcję partnera. 

Na przykład w momencie wzrostu liczby dostaw służby towarzyszące nie radziły sobie z zadaniami ich dystrybucji i wyznaczania tras. W rezultacie okazało się, że zamówienia zostały wykonane, ale usługa, która utworzyła trasę, nie działa. Muszę powiedzieć, że nasi logistycy dokonali rzeczy prawie niemożliwej w tych warunkach, a klarowna interakcja zespołu pomogła zrekompensować chwilowe awarie usług. Ale nierealne jest ręczne przetwarzanie takiej ilości wniosków przez cały czas, a po pewnym czasie napotkalibyśmy niedopuszczalną lukę między zleceniami a ich wykonaniem. 

Podjęto szereg działań organizacyjnych, a dobrze skoordynowana praca zespołu pozwoliła zyskać czas na uzgodnienie nowych warunków i oczekiwanie na modernizację usług niektórych partnerów. Istnieją inne interfejsy API, które oferują wysoką wytrzymałość i bezbożne stawki w przypadku dużego ruchu. Na przykład na początku używaliśmy jednego dobrze znanego mapującego API do określenia adresu punktu dostawy. Ale pod koniec miesiąca otrzymali okrągły rachunek za prawie 2 miliony rubli. Po tym postanowiliśmy szybko go wymienić. Nie będę zajmował się reklamą, ale powiem, że nasze wydatki znacznie spadły.
Jak przetrwaliśmy 10-krotny wzrost obciążenia pracą zdalnie i jakie wyciągnęliśmy wnioski

Wnioski: Konieczne jest monitorowanie warunków pracy wszystkich usług partnerskich i pamiętanie o nich. Nawet jeśli dziś wydaje się, że są one dla Ciebie „z dużą przewagą”, nie oznacza to, że jutro nie staną się przeszkodą we wzroście. I oczywiście lepiej wcześniej uzgodnić warunki finansowe zwiększonych próśb o usługę. 

Czasami okazuje się, żePotrzebujesz więcej złota„(c) nie pomaga

Jesteśmy przyzwyczajeni do „kneblowania” w głównej bazie danych czy na serwerach aplikacyjnych, ale przy skalowaniu mogą pojawić się kłopoty tam, gdzie się ich nie spodziewaliśmy.Do wyszukiwania pełnotekstowego w serwisie wykorzystujemy silnik Apache Solr. Wraz ze wzrostem obciążenia zauważyliśmy spadek czasu odpowiedzi, a obciążenie procesora serwera osiągnęło 100%. Co może być prostszego - daj kontenerowi Solr więcej zasobów.

Zamiast oczekiwanego wzrostu wydajności, serwer po prostu „umarł”. Natychmiast załadował się w 100% i reagował jeszcze wolniej. Początkowo mieliśmy 2 rdzenie i 2 GB RAM. Postanowiliśmy zrobić to, co zwykle pomaga – daliśmy serwerowi 8 rdzeni i 32 GB. Wszystko stało się znacznie gorsze (dokładnie jak i dlaczego powiemy Ci w osobnym poście). 

W ciągu kilku dni odkryliśmy zawiłości tego problemu i osiągnęliśmy optymalną wydajność przy 8 rdzeniach i 32 GB. Taka konfiguracja pozwala nam na dalsze zwiększanie obciążenia dzisiaj, co jest bardzo ważne, ponieważ wzrost dotyczy nie tylko klientów, ale także liczby podłączonych sklepów – w ciągu 2 miesięcy ich liczba podwoiła się. 

Wnioski: Standardowe metody, takie jak „dodaj więcej żelaza”, nie zawsze działają. Skalując więc jakąkolwiek usługę, trzeba dobrze zrozumieć, w jaki sposób wykorzystuje ona zasoby i wcześniej przetestować jej działanie w nowych warunkach. 

Bezstanowość jest kluczem do prostego skalowania poziomego

Ogólnie rzecz biorąc, nasz zespół trzyma się dobrze znanego podejścia: usługi nie powinny mieć stanu wewnętrznego (bezstanowego) i powinny być niezależne od środowiska uruchomieniowego. To pozwoliło nam przetrwać wzrost obciążenia dzięki prostemu skalowaniu w poziomie. Ale mieliśmy jeden wyjątek w usłudze — program obsługi długich zadań w tle. Zajmował się wysyłaniem e-maili i sms-ów, przetwarzaniem zdarzeń, generowaniem kanałów, importowaniem cen i stanów magazynowych oraz przetwarzaniem obrazów. Tak się złożyło, że zależało to od lokalnego magazynu plików i znajdowało się w jednym egzemplarzu. 

Kiedy liczba zadań w kolejce procesora rosła (a to naturalnie działo się wraz ze wzrostem liczby zleceń), czynnikiem ograniczającym stała się wydajność hosta obsługującego procesor i przechowywanie plików. W rezultacie aktualizacja asortymentu i cen, wysyłanie powiadomień do użytkowników i wiele innych krytycznych funkcji utknęło w kolejce. Zespół Ops szybko przeprowadził migrację pamięci masowej plików do sieciowej pamięci masowej podobnej do S3, co pozwoliło nam zbudować kilka potężnych maszyn do skalowania obsługi zadań w tle.

Wnioski: Zasada Stateless musi być przestrzegana dla wszystkich komponentów bez wyjątku, nawet jeśli wydaje się, że „na pewno tu nie spoczniemy”. Lepiej poświęcić trochę czasu na poprawną organizację pracy wszystkich systemów, niż w pośpiechu przepisywać kod i naprawiać przeciążoną usługę.

7 zasad intensywnego rozwoju

Pomimo dostępności dodatkowych mocy produkcyjnych, w procesie wzrostu nadepnęliśmy na kilka zgrabiarek. W tym czasie liczba zamówień wzrosła ponad 4-krotnie. Obecnie dostarczamy już ponad 17 000 zamówień dziennie w 62 miastach i planujemy dalsze rozszerzanie zasięgu geograficznego – w pierwszej połowie 2020 roku usługa ma zostać uruchomiona w całej Rosji. Aby poradzić sobie z rosnącym obciążeniem pracą, biorąc pod uwagę już pełne wyboje, wyprowadziliśmy dla siebie 7 podstawowych zasad pracy w środowisku ciągłego wzrostu:

  1. Zarządzanie incydentami. Stworzyliśmy tablicę w Jirze, na której każdy incydent jest odzwierciedlony w postaci zgłoszenia. Pomoże Ci to w ustalaniu priorytetów i wykonywaniu zadań związanych z incydentami. Rzeczywiście, w istocie popełnianie błędów nie jest straszne - straszne jest popełnianie błędów dwa razy przy tej samej okazji. W przypadkach, gdy incydenty powtarzają się, zanim przyczyna zostanie usunięta, należy przygotować instrukcje postępowania, ponieważ przy dużym obciążeniu ważna jest błyskawiczna reakcja.
  2. Monitorowanie wymagane dla wszystkich elementów infrastruktury bez wyjątku. To dzięki niemu byliśmy w stanie przewidzieć wzrost obciążenia i właściwie dobrać „wąskie gardła” do priorytetyzacji eliminacji. Najprawdopodobniej pod dużym obciążeniem wszystko, o czym nawet nie pomyślałeś, zepsuje się lub zacznie zwalniać. Dlatego najlepiej jest tworzyć nowe alerty natychmiast po wystąpieniu pierwszych incydentów, aby je monitorować i przewidywać.
  3. Popraw alerty po prostu potrzebne przy gwałtownym wzroście obciążenia. Po pierwsze, muszą dokładnie zgłosić, co jest zepsute. Po drugie, nie powinno być wielu alertów, ponieważ obfitość alertów niekrytycznych prowadzi do ignorowania wszystkich alertów w ogóle.
  4. Aplikacje muszą być bezstanowe. Zadbaliśmy o to, aby nie było wyjątków od tej reguły. Potrzebujesz pełnej niezależności od środowiska uruchomieniowego. W tym celu możesz przechowywać udostępnione dane w bazie danych lub np. bezpośrednio w S3. Jeszcze lepiej, przestrzegaj zasad. https://12factor.net. Podczas gwałtownego wzrostu czasu po prostu nie ma sposobu na optymalizację kodu, a będziesz musiał poradzić sobie z obciążeniem, bezpośrednio zwiększając zasoby obliczeniowe i skalowanie poziome.
  5. Limity i wykonanie usług zewnętrznych. Przy szybkim wzroście problem może pojawić się nie tylko w Twojej infrastrukturze, ale również w usłudze zewnętrznej. Najbardziej irytujące jest to, że dzieje się tak nie z powodu awarii, ale z powodu osiągnięcia kwot lub limitów. Usługi zewnętrzne powinny więc skalować się tak dobrze, jak Ty sam. 
  6. Oddzielne procesy i kolejki. To bardzo pomaga, gdy na jednej z bramek pojawi się wtyczka. Nie mielibyśmy opóźnień w transmisji danych, gdyby zapełnione kolejki do wysyłania SMS-ów nie zakłócały wymiany powiadomień między systemami informatycznymi. I łatwiej byłoby zwiększyć liczbę pracowników, gdyby pracowali oddzielnie.
  7. realia finansowe. Kiedy następuje gwałtowny wzrost przepływów danych, nie ma czasu na myślenie o taryfach i abonamentach. Ale trzeba o nich pamiętać, zwłaszcza jeśli jesteś małą firmą. Duży rachunek może ustawić właściciel dowolnego interfejsu API, a także dostawca usług hostingowych. Dlatego uważnie czytaj umowy.

wniosek

Nie bez strat, ale przeżyliśmy ten etap i dziś staramy się trzymać wszystkich znalezionych zasad, a każda maszyna ma możliwość łatwego zwiększenia wydajności x4, aby poradzić sobie z niektórymi niespodziankami. 

W kolejnych wpisach podzielimy się naszym doświadczeniem w badaniu spadków wydajności w Apache Solr, a także porozmawiamy o optymalizacji zapytań oraz o tym, jak interakcja z Federalną Służbą Podatkową pomaga firmie zaoszczędzić pieniądze. Subskrybuj naszego bloga, aby niczego nie przegapić i napisz w komentarzach, czy podczas wzrostu ruchu miałeś podobne problemy.

Jak przetrwaliśmy 10-krotny wzrost obciążenia pracą zdalnie i jakie wyciągnęliśmy wnioski

W ankiecie mogą brać udział tylko zarejestrowani użytkownicy. Zaloguj się, Proszę.

Czy kiedykolwiek miałeś spowolnienie/spadek usługi z powodu gwałtownego wzrostu obciążenia z powodu:

  • 55,6%Brak możliwości szybkiego dodania zasobów obliczeniowych10

  • 16,7%Ograniczenia infrastruktury dostawcy usług hostingowych3

  • 33,3%Limity API6 stron trzecich

  • 27,8%Naruszenia zasad bezpaństwowości ich zastosowań5

  • 88,9%Nieoptymalny kod usług własnych16

Głosowało 18 użytkowników. 6 użytkowników wstrzymało się od głosu.

Źródło: www.habr.com

Dodaj komentarz