Niedostępność Post Mortem na Quay.io

Notatka. przeł.: na początku sierpnia Red Hat publicznie mówił o rozwiązaniu problemów z dostępnością, z którymi borykali się użytkownicy jego usługi w poprzednich miesiącach Quay.io (opiera się na rejestrze obrazów kontenerów, który firma otrzymała wraz z zakupem CoreOS). Niezależnie od zainteresowania tą usługą jako taką, droga, jaką przeszli inżynierowie SRE firmy, aby zdiagnozować i wyeliminować przyczyny wypadku, jest pouczająca.

Niedostępność Post Mortem na Quay.io

19 maja wczesnym rankiem (czasu wschodniego, EDT) doszło do awarii usługi quay.io. Wypadek dotknął zarówno konsumentów quay.io, jak i projekty Open Source wykorzystujące quay.io jako platformę do tworzenia i dystrybucji oprogramowania. Red Hat ceni zaufanie obu stron.

Natychmiast zaangażował się zespół inżynierów SRE, który starał się jak najszybciej ustabilizować funkcjonowanie Quay. Jednak robiąc to, klienci stracili możliwość przesyłania nowych obrazów i tylko czasami byli w stanie pobrać istniejące. Z nieznanego powodu baza danych quay.io została zablokowana po przeskalowaniu usługi do pełnej wydajności.

«Co się zmieniło?„ – to pierwsze pytanie, które zwykle zadaje się w takich przypadkach. Zauważyliśmy, że na krótko przed problemem klaster OpenShift Dedicated (na którym działa quay.io) rozpoczął aktualizację do wersji 4.3.19. Ponieważ quay.io działa na Red Hat OpenShift Dedicated (OSD), regularne aktualizacje były rutynowe i nigdy nie powodowały problemów. Ponadto w ciągu ostatnich sześciu miesięcy kilkukrotnie modernizowaliśmy klastry Quay bez żadnych przerw w świadczeniu usług.

Podczas gdy my próbowaliśmy przywrócić usługę, inni inżynierowie zaczęli przygotowywać nowy klaster OSD z poprzednią wersją oprogramowania, aby w razie gdyby coś się stało, mogli wszystko na nim wdrożyć.

Analiza przyczyn

Głównym objawem awarii była lawina dziesiątek tysięcy połączeń z bazami danych, która skutecznie uniemożliwiła działanie instancji MySQL. Utrudniało to zdiagnozowanie problemu. Ustaliliśmy limit maksymalnej liczby połączeń od klientów, aby pomóc zespołowi SRE ocenić problem. Nie zauważyliśmy żadnego nietypowego ruchu w bazie danych: w rzeczywistości większość żądań została odczytana, a tylko kilka zostało zapisanych.

Próbowaliśmy także zidentyfikować wzorzec w ruchu w bazie danych, który mógłby spowodować tę lawinę. Jednak w logach nie znaleźliśmy żadnych wzorców. Czekając, aż nowy klaster z OSD 4.3.18 będzie gotowy, kontynuowaliśmy próby uruchomienia podów quay.io. Za każdym razem, gdy klaster osiągnął pełną pojemność, baza danych zawieszała się. Oznaczało to, że oprócz wszystkich podów quay.io konieczne było ponowne uruchomienie instancji RDS.

Do wieczora ustabilizowaliśmy usługę w trybie tylko do odczytu i wyłączyliśmy jak najwięcej nieistotnych funkcji (na przykład wyrzucanie elementów bezużytecznych przestrzeni nazw), aby zmniejszyć obciążenie bazy danych. Zamrożenia ustały ale przyczyny nigdy nie znaleziono. Nowy klaster OSD był gotowy, przeprowadziliśmy migrację usługi, połączonego ruchu i kontynuowaliśmy monitorowanie.

Quay.io działało stabilnie na nowym klastrze OSD, więc wróciliśmy do logów bazy danych, ale nie znaleźliśmy korelacji, która wyjaśniałaby blokady. Inżynierowie OpenShift współpracowali z nami, aby zrozumieć, czy zmiany w Red Hat OpenShift 4.3.19 mogą powodować problemy z Quay. Jednak nic nie znaleziono i Odtworzenie problemu w warunkach laboratoryjnych nie było możliwe.

Druga porażka

28 maja, krótko przed południem EDT, quay.io uległo ponownej awarii z tym samym objawem: baza danych została zablokowana. I znowu włożyliśmy wszystkie siły w dochodzenie. Przede wszystkim konieczne było przywrócenie usługi. Jednakże tym razem ponowne uruchomienie RDS i ponowne uruchomienie strąków quay.io nic nie dało: kolejna lawina połączeń zalała bazę. Ale dlaczego?

Quay jest napisany w Pythonie i każdy pod działa jak pojedynczy, monolityczny kontener. Środowisko wykonawcze kontenera obsługuje jednocześnie wiele zadań równoległych. Korzystamy z biblioteki gevent pod gunicorn do przetwarzania żądań internetowych. Kiedy żądanie wpływa do Quay (przez nasze własne API lub poprzez API Dockera), zostaje mu przypisany pracownik gevent. Zwykle ten pracownik powinien skontaktować się z bazą danych. Po pierwszej awarii odkryliśmy, że pracownicy gevent łączyli się z bazą danych przy użyciu ustawień domyślnych.

Biorąc pod uwagę znaczną liczbę podów Quay i tysiące przychodzących żądań na sekundę, duża liczba połączeń z bazą danych może teoretycznie przeciążyć instancję MySQL. Dzięki monitoringowi wiadomo było, że Quay przetwarza średnio 5 tysięcy żądań na sekundę. Liczba połączeń z bazą danych była w przybliżeniu taka sama. 5 tysięcy połączeń mieściło się w granicach możliwości naszej instancji RDS (czego nie można powiedzieć o dziesiątkach tysięcy). Z jakiegoś powodu wystąpiły nieoczekiwane skoki liczby połączeń, nie zaobserwowaliśmy jednak żadnej korelacji z przychodzącymi żądaniami.

Tym razem byliśmy zdeterminowani znaleźć i wyeliminować źródło problemu, a nie ograniczać się do ponownego uruchomienia. Do bazy kodu Quay wprowadzono zmiany mające na celu ograniczenie liczby połączeń z bazą danych dla każdego pracownika wydarzenie. Liczba ta stała się parametrem w konfiguracji: stała się możliwa zmiana jej na bieżąco, bez konieczności budowania nowego obrazu kontenera. Aby dowiedzieć się, ile połączeń można realistycznie obsłużyć, przeprowadziliśmy kilka testów w środowisku testowym, ustawiając różne wartości, aby zobaczyć, jak wpłynie to na scenariusze testów obciążeniowych. W rezultacie odkryto, że Quay zaczyna wyrzucać błędy 502, gdy liczba połączeń przekroczy 10 tys.

Natychmiast wdrożyliśmy tę nową wersję na produkcję i rozpoczęliśmy monitorowanie harmonogramu połączeń z bazą danych. W przeszłości baza była zamykana po około 20 minutach. Po 30 minutach bezproblemowych mieliśmy nadzieję, a godzinę później pewność siebie. Przywróciliśmy ruch na stronie i rozpoczęliśmy analizę pośmiertną.

Udało nam się ominąć problem powodujący blokadę, nie poznaliśmy jego prawdziwych powodów. Potwierdzono, że nie ma to związku z jakimikolwiek zmianami w OpenShift 4.3.19, gdyż to samo stało się na wersji 4.3.18, która wcześniej współpracowała z Quay bez żadnych problemów.

W gromadzie najwyraźniej czaiło się coś jeszcze.

Szczegółowe badanie

Quay.io korzystało z domyślnych ustawień, aby połączyć się z bazą danych przez sześć lat bez żadnych problemów. Co się zmieniło? Widać, że przez cały ten czas ruch na quay.io stale rośnie. W naszym przypadku wyglądało to tak, jakby osiągnięto jakąś wartość progową, co wywołało lawinę połączeń. Po drugiej awarii kontynuowaliśmy badanie dzienników bazy danych, ale nie znaleźliśmy żadnych wzorców ani oczywistych zależności.

W międzyczasie zespół SRE pracował nad ulepszeniami w zakresie obserwowalności żądań Quay i ogólnego stanu usług. Wdrożono nowe wskaźniki i dashboardy, pokazujące, które części Nabrzeża cieszą się największym zainteresowaniem klientów.

Quay.io działało dobrze do 9 czerwca. Dziś rano (EDT) ponownie zaobserwowaliśmy znaczny wzrost liczby połączeń z bazami danych. Tym razem nie było przestojów, ponieważ nowy parametr ograniczył ich liczbę i nie pozwolił na przekroczenie przepustowości MySQL. Jednak przez około pół godziny wielu użytkowników zauważyło powolne działanie quay.io. Szybko zebraliśmy wszystkie możliwe dane, korzystając z dodanych narzędzi monitorujących. Nagle pojawił się pewien wzór.

Tuż przed gwałtownym wzrostem liczby połączeń do interfejsu App Registry API wysłano dużą liczbę żądań. Rejestr aplikacji to mało znana funkcja quay.io. Umożliwia przechowywanie takich rzeczy, jak wykresy Helm i kontenery z bogatymi metadanymi. Większość użytkowników quay.io nie korzysta z tej funkcji, ale Red Hat OpenShift aktywnie z niej korzysta. OperatorHub w ramach OpenShift przechowuje wszystkich operatorów w Rejestrze aplikacji. Operatorzy ci stanowią podstawę ekosystemu obciążeń OpenShift i modelu operacyjnego skoncentrowanego na partnerach (operacje dnia 2).

Każdy klaster OpenShift 4 wykorzystuje operatory z wbudowanego OperatorHub do publikowania katalogu operatorów dostępnych do instalacji i zapewniania aktualizacji już zainstalowanych. Wraz z rosnącą popularnością OpenShift 4 wzrosła także liczba działających na nim klastrów na całym świecie. Każdy z tych klastrów pobiera zawartość operatora w celu uruchomienia wbudowanego OperatorHub, korzystając z rejestru aplikacji w quay.io jako zaplecza. W poszukiwaniu źródła problemu przeoczyliśmy fakt, że wraz ze stopniowym wzrostem popularności OpenShift wzrosło również obciążenie jednej z rzadko używanych funkcji quay.io..

Przeprowadziliśmy analizę ruchu związanego z żądaniami rejestru aplikacji i sprawdziliśmy kod rejestru. Natychmiast ujawniono niedociągnięcia, przez które zapytania do bazy danych nie były formowane optymalnie. Gdy obciążenie było małe, nie sprawiały kłopotów, natomiast przy większym obciążeniu stawały się źródłem problemów. Okazało się, że App Registry ma dwa problematyczne punkty końcowe, które nie reagują dobrze na rosnące obciążenie: pierwszy udostępnia listę wszystkich pakietów w repozytorium, drugi zwraca wszystkie obiekty BLOB dla pakietu.

Eliminacja przyczyn

Przez kolejny tydzień optymalizowaliśmy kod samego Rejestru aplikacji i jego otoczenia. Przerobiono wyraźnie nieefektywne zapytania SQL i wyeliminowano niepotrzebne wywołania poleceń tar (było uruchamiane za każdym razem, gdy pobierano obiekty BLOB), tam, gdzie było to możliwe, dodano buforowanie. Następnie przeprowadziliśmy szeroko zakrojone testy wydajności i porównaliśmy szybkość rejestru aplikacji przed i po zmianach.

Żądania API, które wcześniej zajmowały do ​​pół minuty, są teraz realizowane w milisekundach. W następnym tygodniu wdrożyliśmy zmiany na produkcję i od tego czasu quay.io działa stabilnie. W tym czasie wystąpiło kilka gwałtownych wzrostów ruchu w punkcie końcowym App Registry, ale wprowadzone ulepszenia zapobiegły awariom bazy danych.

Czego się nauczyliśmy?

Oczywiste jest, że każda usługa stara się unikać przestojów. W naszym przypadku uważamy, że ostatnie awarie pomogły ulepszyć quay.io. Wyciągnęliśmy kilka kluczowych wniosków, którymi chcielibyśmy się podzielić:

  1. Dane o tym, kto i w jaki sposób korzysta z Twoich usług, nigdy nie są zbędne. Ponieważ Quay „po prostu działał”, nigdy nie musieliśmy tracić czasu na optymalizację ruchu i zarządzanie obciążeniem. Wszystko to stwarzało fałszywe poczucie bezpieczeństwa, że ​​usługę można skalować w nieskończoność.
  2. Kiedy usługa przestaje działać, przywrócenie go do stanu używalności jest najwyższym priorytetem.. Ponieważ podczas pierwszej przerwy w działaniu Quay nadal występowała blokada bazy danych, nasze standardowe procedury nie przyniosły zamierzonego efektu i nie mogliśmy przy ich użyciu przywrócić usługi. Doprowadziło to do sytuacji, w której trzeba było poświęcić czas na analizę i zbieranie danych w nadziei na znalezienie pierwotnej przyczyny – zamiast skupiać wszystkie wysiłki na przywróceniu funkcjonalności.
  3. Oceń wpływ każdej funkcji usługi. Klienci rzadko korzystali z App Registry, więc nie było to priorytetem dla naszego zespołu. Kiedy niektóre funkcje produktu są rzadko używane, ich błędy rzadko się pojawiają, a programiści przestają monitorować kod. Łatwo paść ofiarą błędnego przekonania, że ​​tak właśnie powinno być – aż nagle ta funkcja znajdzie się w centrum poważnego zdarzenia.

Co dalej?

Praca nad zapewnieniem stabilności serwisu nigdy się nie kończy i stale go udoskonalamy. Ponieważ natężenie ruchu na quay.io stale rośnie, zdajemy sobie sprawę, że mamy obowiązek zrobić wszystko, co w naszej mocy, aby sprostać zaufaniu naszych klientów. W związku z tym aktualnie pracujemy nad następującymi zadaniami:

  1. Wdrażaj repliki baz danych tylko do odczytu, aby pomóc usłudze obsługiwać odpowiedni ruch w przypadku problemów z podstawową instancją RDS.
  2. Aktualizowanie instancji RDS. Sama aktualna wersja nie jest problemem. Raczej chcemy po prostu usunąć fałszywy trop (którym podążaliśmy podczas niepowodzenia); Aktualizowanie oprogramowania wyeliminuje kolejny czynnik w przypadku przyszłych przestojów.
  3. Dodatkowe buforowanie w całym klastrze. Nadal szukamy obszarów, w których buforowanie może zmniejszyć obciążenie bazy danych.
  4. Dodanie zapory aplikacji internetowej (WAF), aby zobaczyć, kto łączy się z quay.io i dlaczego.
  5. Począwszy od następnej wersji klastry Red Hat OpenShift porzucą App Registry na rzecz katalogów operatorów opartych na obrazach kontenerów dostępnych na quay.io.
  6. Długoterminowym zamiennikiem App Registry może być obsługa specyfikacji artefaktów Open Container Initiative (OCI). Jest obecnie zaimplementowana jako natywna funkcjonalność Quay i będzie dostępna dla użytkowników po sfinalizowaniu samej specyfikacji.

Wszystko to stanowi część ciągłych inwestycji firmy Red Hat w quay.io w związku z przechodzeniem z małego zespołu w stylu start-upu do dojrzałej platformy opartej na SRE. Wiemy, że wielu naszych klientów polega na quay.io w swojej codziennej pracy (w tym Red Hat!), dlatego staramy się zachować jak największą przejrzystość w zakresie ostatnich awarii i ciągłych wysiłków zmierzających do poprawy.

PS od tłumacza

Przeczytaj także na naszym blogu:

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

Dodaj komentarz