
Wszystko dobrze!
Nazywam się Nikita i jestem liderem zespołu inżynierów Cian. Jednym z moich obowiązków w firmie jest ograniczenie do zera liczby incydentów związanych z infrastrukturą produkcyjną.
To, co nastąpiło później, sprawiło nam wiele bólu i celem tego artykułu jest powstrzymanie innych przed powtarzaniem naszych błędów, a przynajmniej zminimalizowanie ich wpływu.
Preambuła
Dawno temu, gdy Cian składał się z monolitów i nie było śladu mikrousług, dostępność zasobów ocenialiśmy, sprawdzając 3–5 stron.
Odbierają - wszystko w porządku, jeśli nie odbierają przez dłuższy czas - alarm. O tym, jak długo musieli być nieobecni w pracy, aby uznać to za incydent, decydowali ludzie na spotkaniach. W badaniu incydentu zawsze brał udział zespół inżynierów. Po zakończeniu śledztwa sporządzono raport z sekcji zwłok – rodzaj raportu przesyłanego pocztą elektroniczną w następującej formie: co się wydarzyło, jak długo to trwało, co zrobiono w tej chwili, co zrobimy w przyszłości.
Główne strony serwisu, czyli jak rozumiemy, że osiągnęliśmy dno
Aby zrozumieć priorytet błędu, zidentyfikowaliśmy strony o najważniejszym znaczeniu dla funkcjonalności biznesowej witryny. Używamy ich do zliczania liczby pomyślnych/niepomyślnych żądań oraz przekroczeń limitu czasu. W ten sposób mierzymy czas sprawności.
Załóżmy, że odkryliśmy, że na stronie jest kilka niezwykle ważnych sekcji, które odpowiadają za główną usługę — wyszukiwanie i zamieszczanie reklam. Jeśli liczba nieodebranych żądań przekroczy 1%, jest to incydent krytyczny. Jeżeli w ciągu 15 minut w czasie największej oglądalności wskaźnik błędów przekroczy 0,1%, zdarzenie to również uznaje się za incydent krytyczny. Kryteria te obejmują większość incydentów, reszta wykracza poza zakres tego artykułu.

Najlepsze incydenty z cyjanem
Zatem na pewno nauczyliśmy się ustalać fakt wystąpienia zdarzenia.
Teraz każdy incydent jest szczegółowo opisany i odzwierciedlony w epiku Jira. Przy okazji: w tym celu stworzyliśmy osobny projekt, nazwaliśmy go FAIL - można w nim tworzyć wyłącznie eposy.
Jeśli zbierzesz wszystkie porażki z ostatnich kilku lat, liderami są:
- incydenty związane z MSSQL;
- zdarzenia spowodowane czynnikami zewnętrznymi;
- błędy administracyjne.
Przyjrzyjmy się bliżej błędom administratorów oraz innym ciekawym wpadkom.
Piąte miejsce - „Uporządkujmy sprawy w DNS”
Był ponury wtorek. Postanowiliśmy uporządkować sprawy w klastrze DNS.
Chciałem przenieść wewnętrzne serwery DNS z bind do powerdns, przydzielając do tego celu zupełnie oddzielne serwery, na których nie będzie nic poza DNS.
Umieściliśmy po jednym serwerze DNS w każdej lokalizacji naszego kontrolera domeny, a następnie nadszedł czas na przeniesienie stref z bind do powerdns i przełączenie infrastruktury na nowe serwery.
Wśród przeprowadzek, ze wszystkich ludzi serwerySpośród serwerów określonych w lokalnych powiązaniach buforowania, pozostał tylko jeden – ten w centrum danych w Sankt Petersburgu. Początkowo to centrum danych zostało uznane za niekrytyczne dla nas, ale nagle stało się pojedynczym punktem awarii.
To właśnie w tym okresie przejściowym kanał między Moskwą a Petersburgiem uległ awarii. W efekcie przez pięć minut byliśmy bez DNS i odzyskaliśmy łączność, gdy… gospodarz rozwiązano problemy.
Wnioski:
Jeśli wcześniej zaniedbywaliśmy czynniki zewnętrzne podczas przygotowań do pracy, to teraz znalazły się one również na liście rzeczy, do których się przygotowujemy. I teraz dążymy do tego, aby wszystkie komponenty były zarezerwowane n-2, a w trakcie pracy możemy obniżyć ten poziom do n-1.
- Tworząc plan działania, zwróć uwagę na punkty, w których usługa może zawieść i z wyprzedzeniem przemyśl scenariusz, w którym sytuacja pójdzie „najgorzej”.
- Rozłóż wewnętrzne serwery DNS w różnych lokalizacjach geograficznych/centrach danych/stojakach/przełącznikach/wejściach.
- Na każdym serwerze zainstaluj lokalny serwer buforujący DNS, który przekierowuje żądania do głównych serwerów DNS, a jeśli jest niedostępny, będzie odpowiadał z pamięci podręcznej.
Czwarte miejsce – „Sprzątanie Nginx”
Pewnego dnia nasz zespół uznał, że „dość” i rozpoczął proces refaktoryzacji konfiguracji nginx. Głównym celem jest zapewnienie intuicyjnej struktury konfiguracji. Wcześniej wszystko było „ustalone historycznie” i nie miało żadnej logiki. Teraz każda nazwa_serwera została przeniesiona do pliku o tej samej nazwie, a wszystkie konfiguracje zostały rozmieszczone w folderach. Nawiasem mówiąc, konfiguracja zawiera 253949 linii lub 7836520 znaków i zajmuje prawie 7 megabajtów. Struktura najwyższego poziomu:
Struktura Nginx
├── access
│ ├── allow.list
...
│ └── whitelist.conf
├── geobase
│ ├── exclude.conf
...
│ └── geo_ip_to_region_id.conf
├── geodb
│ ├── GeoIP.dat
│ ├── GeoIP2-Country.mmdb
│ └── GeoLiteCity.dat
├── inc
│ ├── error.inc
...
│ └── proxy.inc
├── lists.d
│ ├── bot.conf
...
│ ├── dynamic
│ └── geo.conf
├── lua
│ ├── cookie.lua
│ ├── log
│ │ └── log.lua
│ ├── logics
│ │ ├── include.lua
│ │ ├── ...
│ │ └── utils.lua
│ └── prom
│ ├── stats.lua
│ └── stats_prometheus.lua
├── map.d
│ ├── access.conf
│ ├── ..
│ └── zones.conf
├── nginx.conf
├── robots.txt
├── server.d
│ ├── cian.ru
│ │ ├── cian.ru.conf
│ │ ├── ...
│ │ └── my.cian.ru.conf
├── service.d
│ ├── ...
│ └── status.conf
└── upstream.d
├── cian-mcs.conf
├── ...
└── wafserver.confSytuacja znacznie się poprawiła, ale w procesie zmiany nazw i dystrybucji konfiguracji, niektóre z nich miały niewłaściwe rozszerzenia i nie zostały uwzględnione w dyrektywie include *.conf. W rezultacie niektórzy hostowie stali się niedostępni i zwrócili kod 301 do strony głównej. Ponieważ kod odpowiedzi nie był 5xx/4xx, nie zauważono go od razu, lecz dopiero rano. Następnie zaczęliśmy pisać testy sprawdzające komponenty infrastruktury.
Wnioski:
- Uporządkuj prawidłowo swoje konfiguracje (nie tylko nginx) i przemyśl strukturę już na wczesnym etapie projektu. Dzięki temu staną się one bardziej zrozumiałe dla zespołu, co z kolei skróci czas potrzebny do wdrożenia (TTM).
- Napisz testy dla niektórych komponentów infrastruktury. Na przykład: sprawdzenie, czy wszystkie klucze server_name zwracają poprawny status + treść odpowiedzi. Wystarczy mieć pod ręką kilka skryptów sprawdzających najważniejsze funkcje komponentu, dzięki czemu o trzeciej w nocy nie będziesz musiał gorączkowo przypominać sobie, co jeszcze trzeba sprawdzić.
Trzecie miejsce – „Nagle zabrakło mi miejsca w Cassandrze”
Dane rosły systematycznie i wszystko szło dobrze aż do momentu, gdy naprawa dużych przestrzeni kluczy w klastrze Cassandra zaczęła zawodzić, ponieważ nie można było na nich przeprowadzić kompresji.
Pewnego deszczowego dnia gromada ta niemal zamieniła się w dynię, a mianowicie:
- w klastrze pozostało łącznie około 20% wolnego miejsca;
- nie jest możliwe pełne dodanie węzłów, ponieważ czyszczenie nie odbywa się po dodaniu węzła z powodu braku miejsca na partycjach;
- wydajność stopniowo spada, ponieważ zagęszczanie nie działa;
- Klaster pracuje w trybie awaryjnym.

Rozwiązaniem było dodanie 5 kolejnych węzłów bez czyszczenia, po czym zaczęto je systematycznie usuwać z klastra i ponownie wprowadzać jako puste węzły, którym zabrakło miejsca. Spędziłem tam znacznie więcej czasu, niż bym chciał. Istniało ryzyko częściowej lub całkowitej niedostępności klastra.
Wnioski:
- Żaden z serwerów Cassandra nie powinien mieć zajętego więcej niż 60% przestrzeni na każdej partycji.
- Nie powinny one obciążać procesora w stopniu większym niż 50%.
- Nie należy zapominać o planowaniu pojemności; musisz to dokładnie przemyśleć dla każdego komponentu, biorąc pod uwagę jego specyfikę.
- Im więcej węzłów w klastrze, tym lepiej. Serwery zawierające niewielką ilość danych zapełniają się szybciej, a taki klaster jest łatwiejszy do reanimacji.
Drugie miejsce – „Dane zniknęły z magazynu kluczy i wartości konsularnych”
Do wyszukiwania usług, my, podobnie jak wielu innych, używamy konsulatu. Ale używamy również tej pary klucz-wartość do niebiesko-zielonego układu monolitu. Przechowuje informacje o aktywnych i nieaktywnych strumieniach, które zmieniają swoje miejsca podczas wdrażania. W tym celu napisano usługę wdrażania, która współpracowała z KV. W pewnym momencie dane z KV zniknęły. Przywrócono z pamięci, ale z wieloma błędami. W rezultacie obciążenie serwerów źródłowych podczas wdrażania było nierównomiernie rozłożone, a z powodu przeciążenia procesora procesora wystąpiło wiele błędów 502. W efekcie przeszliśmy z konsula KV na postgres, skąd nie jest już tak łatwo je usunąć.
Wnioski:
- Usługi nieobjęte autoryzacją nie powinny zawierać danych mających krytyczne znaczenie dla działania serwisu. Na przykład, jeśli nie masz autoryzacji w ES, lepiej będzie zabronić dostępu na poziomie sieci wszędzie tam, gdzie nie jest on potrzebny, pozostawić tylko niezbędne osoby i ustawić action.destructive_requires_name: true.
- Zawczasu przećwicz mechanizm tworzenia kopii zapasowych i odzyskiwania danych. Na przykład utwórz wcześniej skrypt (np. w Pythonie), który będzie umożliwiał zarówno tworzenie kopii zapasowej, jak i jej przywracanie.
Pierwsze miejsce – „Kapitan Oczywisty”
W pewnym momencie zauważyliśmy nierównomierne rozłożenie obciążenia na serwerach upstream nginx w przypadkach, gdy w zapleczu znajdowało się ponad 10 serwerów. Ponieważ metoda round-robin kierowała żądania od 1 do ostatniego serwera nadrzędnego w kolejności, a nginx rozpoczynał każde przeładowanie od początku, pierwsze serwery nadrzędne zawsze miały więcej żądań niż pozostałe. W rezultacie działały wolniej i cała witryna ucierpiała. Stawało się to coraz bardziej zauważalne w miarę wzrostu natężenia ruchu. Prosta aktualizacja nginx w celu włączenia losowości nie zadziałała — trzeba było przepisać sporo kodu LUA, który nie działał w wersji 1.15 (w tamtym czasie). Musieliśmy zaktualizować nasz nginx 1.14.2, aby dodać obsługę losowości. To rozwiązało problem. Ten błąd wygrywa nagrodę „Kapitana Oczywistego”.
Wnioski:
Badanie tego błędu było bardzo interesujące i ekscytujące).
- Skonfiguruj monitorowanie, które pomoże Ci szybko wykryć takie wahania. Na przykład możesz użyć ELK do monitorowania rps dla każdego zaplecza każdego źródła, monitorując ich czasy odpowiedzi z perspektywy nginx. W tym przypadku to właśnie pomogło nam zidentyfikować problem.
W rezultacie większości błędów można by uniknąć, gdybyś wykazał się większą starannością w podejmowanych działaniach. Należy zawsze pamiętać o prawie Murphy'ego: Wszystko co może pójść źle, pójdzie źle. i budować na jego podstawie komponenty.
Źródło: www.habr.com
