Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Witam, nazywam się Evgeniy. Pracuję w infrastrukturze wyszukiwania Yandex.Market. Chcę opowiedzieć społeczności Habr o wewnętrznej kuchni Rynku – a mam wiele do opowiedzenia. Przede wszystkim o tym jak działa wyszukiwarka Market, procesy i architektura. Jak radzimy sobie w sytuacjach awaryjnych: co się stanie, jeśli jeden serwer ulegnie awarii? A co jeśli takich serwerów będzie 100?

Dowiesz się także jak wdrażamy nową funkcjonalność na kilku serwerach jednocześnie. I jak testujemy złożone usługi bezpośrednio w produkcji, nie powodując przy tym żadnych niedogodności dla użytkowników. Ogólnie jak działa wyszukiwarka Market, żeby wszyscy dobrze się bawili.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Trochę o nas: jaki problem rozwiązujemy

Gdy wpiszesz tekst, wyszukasz produkt według parametrów lub porównasz ceny w różnych sklepach, wszystkie zapytania trafiają do usługi wyszukiwania. Wyszukiwanie to największa usługa na rynku.

Przetwarzamy wszystkie żądania wyszukiwania: ze stron market.yandex.ru, beru.ru, usługi Supercheck, Yandex.Advisor, aplikacji mobilnych. Oferty produktów uwzględniamy również w wynikach wyszukiwania na yandex.ru.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Przez usługę wyszukiwania mam na myśli nie tylko samo wyszukiwanie, ale także bazę danych zawierającą wszystkie oferty znajdujące się na Rynku. Skala jest następująca: dziennie przetwarzanych jest ponad miliard żądań wyszukiwania. A wszystko powinno działać szybko, bez zakłóceń i zawsze dawać pożądany efekt.

Co jest co: Architektura rynku

Opiszę pokrótce obecną architekturę Rynku. Można to z grubsza opisać na poniższym schemacie:
Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii
Załóżmy, że przychodzi do nas sklep partnerski. Mówi, że chcę sprzedać zabawkę: tego złego kota z piszczałką. I kolejny wściekły kot bez piszczałki. I tylko kot. Następnie sklep musi przygotować oferty, których szuka Market. Sklep generuje specjalny plik XML z ofertami i podaje ścieżkę do tego pliku XML poprzez interfejs partnerski. Następnie indeksator okresowo pobiera ten plik XML, sprawdza błędy i zapisuje wszystkie informacje w ogromnej bazie danych.

Istnieje wiele takich zapisanych plików XML. Na podstawie tej bazy danych tworzony jest indeks wyszukiwania. Indeks jest przechowywany w formacie wewnętrznym. Po utworzeniu indeksu usługa Layout przesyła go na serwery wyszukiwania.

W rezultacie w bazie danych pojawia się wściekły kot z piszczącym głosem, a na serwerze pojawia się indeks kota.

Jak szukamy kota opowiem w części o architekturze wyszukiwania.

Architektura wyszukiwania rynku

Żyjemy w świecie mikrousług: każde przychodzące żądanie market.yandex.ru powoduje powstawanie wielu podzapytań, a w ich przetwarzanie zaangażowane są dziesiątki usług. Diagram pokazuje tylko kilka:

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii
Uproszczony schemat przetwarzania żądań

Każda usługa ma w sobie coś wspaniałego - swój własny balanser o unikalnej nazwie:

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Balancer daje nam większą elastyczność w zarządzaniu usługą: można np. wyłączyć serwery, co często jest wymagane przy aktualizacjach. Balancer widzi, że serwer jest niedostępny i automatycznie przekierowuje żądania do innych serwerów lub centrów danych. Podczas dodawania lub usuwania serwera obciążenie jest automatycznie redystrybuowane pomiędzy serwerami.

Unikalna nazwa balansera nie jest zależna od centrum danych. Gdy usługa A wysyła żądanie do B, moduł równoważący B domyślnie przekierowuje żądanie do bieżącego centrum danych. Jeżeli usługa jest niedostępna lub nie istnieje w aktualnym data center, wówczas żądanie zostaje przekierowane do innych data center.

Pojedyncza nazwa FQDN dla wszystkich centrów danych umożliwia usłudze A całkowite wyodrębnienie się z lokalizacji. Jego prośba o usługę B będzie zawsze rozpatrywana. Wyjątkiem jest sytuacja, gdy usługa zlokalizowana jest we wszystkich centrach danych.

Ale nie wszystko jest tak różowe z tym balanserem: mamy dodatkowy element pośredni. Balancer może działać niestabilnie i ten problem rozwiązują redundantne serwery. Występuje również dodatkowe opóźnienie pomiędzy usługami A i B. Jednak w praktyce jest ono mniejsze niż 1 ms i dla większości usług nie jest to krytyczne.

Radzenie sobie z nieoczekiwanym: równoważenie i odporność usług wyszukiwania

Wyobraź sobie, że następuje załamanie: musisz znaleźć kota z piszczałką, ale serwer ulega awarii. Lub 100 serwerów. Jak się wydostać? Czy naprawdę zostawimy użytkownika bez kota?

Sytuacja jest przerażająca, ale jesteśmy na nią przygotowani. Powiem ci po kolei.

Infrastruktura wyszukiwania zlokalizowana jest w kilku centrach danych:

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Projektując uwzględniamy możliwość wyłączenia jednego centrum danych. Życie jest pełne niespodzianek - na przykład koparka może przeciąć podziemny kabel (tak, tak się stało). Pojemność pozostałych centrów danych powinna być wystarczająca, aby wytrzymać obciążenie szczytowe.

Rozważmy pojedyncze centrum danych. Każde centrum danych ma ten sam schemat działania balansera:

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii
Jeden balanser to co najmniej trzy serwery fizyczne. Ta redundancja ma na celu zapewnienie niezawodności. Balancery działają na HAProxie.

Wybraliśmy HAProx ze względu na jego wysoką wydajność, niskie wymagania dotyczące zasobów i szeroką funkcjonalność. Nasze oprogramowanie do wyszukiwania działa na każdym serwerze.

Prawdopodobieństwo awarii jednego serwera jest niskie. Jeśli jednak masz wiele serwerów, wzrasta prawdopodobieństwo, że co najmniej jeden ulegnie awarii.

Tak właśnie dzieje się w rzeczywistości: awaria serwerów. Dlatego konieczne jest ciągłe monitorowanie stanu wszystkich serwerów. Jeśli serwer przestanie odpowiadać, zostanie automatycznie odłączony od ruchu. W tym celu HAProxy posiada wbudowaną kontrolę stanu. Raz na sekundę trafia do wszystkich serwerów z żądaniem HTTP „/ping”.

Kolejna funkcja HAProxy: sprawdzanie agentów umożliwia równomierne ładowanie wszystkich serwerów. W tym celu HAProxy łączy się ze wszystkimi serwerami, które zwracają swoją wagę w zależności od aktualnego obciążenia od 1 do 100. Waga wyliczana jest na podstawie ilości żądań w kolejce do przetworzenia oraz obciążenia procesora.

Teraz o znalezieniu kota. Wynikiem wyszukiwania są żądania takie jak: /search?text=zły+kot. Aby wyszukiwanie było szybkie, cały indeks cat musi zmieścić się w pamięci RAM. Nawet odczyt z dysku SSD nie jest wystarczająco szybki.

Dawno, dawno temu baza ofert była niewielka i wystarczała na to pamięć RAM jednego serwera. W miarę powiększania się bazy ofert wszystko przestało się mieścić w tej pamięci RAM i dane zostały podzielone na dwie części: shard 1 i shard 2.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii
Ale tak się zawsze dzieje: każde rozwiązanie, nawet dobre, rodzi inne problemy.

Balancer nadal trafiał na dowolny serwer. Ale na komputerze, z którego przyszło żądanie, była tylko połowa indeksu. Reszta była na innych serwerach. Dlatego serwer musiał udać się do jakiejś sąsiedniej maszyny. Po otrzymaniu danych z obu serwerów wyniki zostały połączone i ponownie uszeregowane.

Ponieważ moduł równoważący równomiernie rozdziela żądania, wszystkie serwery były zaangażowane w zmianę rankingu, a nie tylko w wysyłanie danych.

Problem występował, gdy sąsiedni serwer był niedostępny. Rozwiązaniem było określenie kilku serwerów o różnych priorytetach jako serwera „sąsiadującego”. Najpierw żądanie zostało wysłane do serwerów w bieżącej szafie. W przypadku braku odpowiedzi żądanie zostało wysłane do wszystkich serwerów w tym centrum danych. Na koniec żądanie trafiło do innych centrów danych.
W miarę wzrostu liczby propozycji dane podzielono na cztery części. Ale to nie był limit.

Obecnie używana jest konfiguracja ośmiu fragmentów. Dodatkowo, aby zaoszczędzić jeszcze więcej pamięci, indeks został podzielony na część wyszukiwania (która służy do wyszukiwania) i część fragmentu (która nie bierze udziału w wyszukiwaniu).

Jeden serwer zawiera informacje tylko dla jednego fragmentu. Dlatego, aby przeszukać pełny indeks, należy przeszukać osiem serwerów zawierających różne fragmenty.

Serwery są pogrupowane w klastry. Każdy klaster zawiera osiem wyszukiwarek i jeden serwer fragmentów.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii
Serwer fragmentów uruchamia bazę danych klucz-wartość zawierającą dane statyczne. Są potrzebne do wystawienia dokumentów np. opisu kota z piszczałką. Dane są specjalnie przenoszone na osobny serwer, aby nie obciążać pamięci serwerów wyszukiwania.

Ponieważ identyfikatory dokumentów są unikalne tylko w ramach jednego indeksu, może wystąpić sytuacja, w której we fragmentach nie będzie żadnych dokumentów. No albo że dla jednego ID będzie inna treść. Dlatego też, aby wyszukiwanie zadziałało i zwróciło wyniki, potrzebna była spójność w całym klastrze. Poniżej opowiem Ci, jak monitorujemy spójność.

Samo wyszukiwanie ma następującą strukturę: żądanie wyszukiwania może dotrzeć do dowolnego z ośmiu serwerów. Załóżmy, że przyszedł do serwera 1. Serwer ten przetwarza wszystkie argumenty i rozumie, czego i jak szukać. W zależności od przychodzącego żądania serwer może wysyłać dodatkowe żądania do usług zewnętrznych o niezbędne informacje. Po jednym żądaniu może nastąpić maksymalnie dziesięć żądań do usług zewnętrznych.

Po zebraniu niezbędnych informacji rozpoczyna się wyszukiwanie w bazie ofert. W tym celu podzapytania są kierowane do wszystkich ośmiu serwerów w klastrze.

Po otrzymaniu odpowiedzi wyniki są łączone. Ostatecznie do wygenerowania wyników może być potrzebnych kilka dodatkowych podzapytań skierowanych do serwera fragmentów.

Zapytania wyszukiwania w klastrze wyglądają następująco: /shard1?text=zły+kot. Ponadto podzapytania formularza są stale wykonywane pomiędzy wszystkimi serwerami w klastrze raz na sekundę: /status.

Zapytanie /status wykrywa sytuację, w której serwer jest niedostępny.

Kontroluje również, czy wersja wyszukiwarki i wersja indeksu są takie same na wszystkich serwerach, w przeciwnym razie dane w klastrze będą niespójne.

Pomimo tego, że jeden serwer fragmentów przetwarza żądania z ośmiu wyszukiwarek, jego procesor jest bardzo lekko obciążony. Dlatego teraz przenosimy dane fragmentu do osobnej usługi.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Do przenoszenia danych wprowadziliśmy uniwersalne klucze do dokumentów. Niemożliwa jest teraz sytuacja, w której za pomocą jednego klucza zwracana jest treść z innego dokumentu.

Jednak przejście na inną architekturę nie jest jeszcze zakończone. Teraz chcemy pozbyć się dedykowanego serwera fragmentów. A następnie całkowicie odejdź od struktury klastrowej. Umożliwi nam to łatwe dalsze skalowanie. Dodatkowym bonusem jest znaczna oszczędność żelaza.

A teraz przerażające historie ze szczęśliwym zakończeniem. Rozważmy kilka przypadków niedostępności serwera.

Stało się coś strasznego: jeden serwer jest niedostępny

Załóżmy, że jeden serwer jest niedostępny. Następnie pozostałe serwery w klastrze będą mogły nadal odpowiadać, ale wyniki wyszukiwania będą niekompletne.

Poprzez sprawdzenie statusu /status sąsiednie serwery rozumieją, że jeden jest niedostępny. Dlatego, aby zachować kompletność, wszystkie serwery w klastrze na żądanie /świst zaczynają reagować na balanser, że również są niedostępne. Okazuje się, że wszystkie serwery w klastrze padły (co nie jest prawdą). To jest główna wada naszego schematu klastrowego – dlatego chcemy od niego uciec.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Żądania zakończone niepowodzeniem z powodu błędu są ponownie wysyłane przez moduł równoważący na inne serwery.
Balancer przestaje również wysyłać ruch użytkowników do martwych serwerów, ale nadal sprawdza ich status.

Kiedy serwer staje się dostępny, zaczyna odpowiadać /świst. Gdy tylko zaczną pojawiać się normalne odpowiedzi na pingi z martwych serwerów, moduły równoważące zaczynają wysyłać tam ruch użytkowników. Działanie klastra zostało przywrócone, hurra.

Co gorsza: wiele serwerów jest niedostępnych

Znaczna część serwerów w centrum danych jest wyłączona. Co robić, gdzie biegać? Balanser znów przychodzi na ratunek. Każdy balanser stale przechowuje w pamięci aktualną liczbę aktywnych serwerów. Stale oblicza maksymalny ruch, jaki może obsłużyć bieżące centrum danych.

Kiedy wiele serwerów w centrum danych ulegnie awarii, moduł równoważący zdaje sobie sprawę, że to centrum danych nie jest w stanie przetworzyć całego ruchu.

Następnie nadmiar ruchu zaczyna być losowo rozdzielany do innych centrów danych. Wszystko działa, wszyscy są zadowoleni.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Jak to robimy: publikacje wydawnicze

Porozmawiajmy teraz o tym, jak publikujemy zmiany wprowadzone w usłudze. Tutaj poszliśmy drogą upraszczania procesów: wdrażanie nowej wersji jest prawie całkowicie zautomatyzowane.
Kiedy w projekcie zgromadzi się określona liczba zmian, automatycznie tworzona jest nowa wersja i rozpoczyna się jej kompilacja.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Następnie usługa przekazywana jest do testów, podczas których sprawdzana jest stabilność działania.

Jednocześnie uruchamiane są automatyczne testy wydajnościowe. Zajmuje się tym specjalny serwis. Nie będę teraz o tym mówić – jego opis zasługuje na osobny artykuł.

Jeśli publikacja w testach przebiegnie pomyślnie, automatycznie rozpocznie się publikacja wydania w prestable. Prestable to specjalny klaster, do którego kierowany jest normalny ruch użytkowników. Jeśli zwróci błąd, moduł wyważający ponownie wysyła żądanie do produkcji.

W wersji pretable mierzone są czasy reakcji i porównywane z poprzednią wersją produkcyjną. Jeśli wszystko jest w porządku, osoba się łączy: sprawdza wykresy i wyniki testów obciążeniowych, a następnie rozpoczyna wdrażanie do produkcji.

Wszystko, co najlepsze, należy do użytkownika: testy A/B

Nie zawsze jest oczywiste, czy zmiany w usłudze przyniosą realne korzyści. Aby zmierzyć przydatność zmian, ludzie wymyślili testy A/B. Opowiem ci trochę o tym, jak to działa w wyszukiwarce Yandex.Market.

Wszystko zaczyna się od dodania nowego parametru CGI, który umożliwia nową funkcjonalność. Niech naszym parametrem będzie: market_new_functionity=1. Następnie w kodzie włączamy tę funkcjonalność, jeśli flaga jest obecna:

If (cgi.experiments.market_new_functionality) {
// enable new functionality
}

Nowa funkcjonalność jest wdrażana w środowisku produkcyjnym.

Aby zautomatyzować testy A/B, dostępna jest dedykowana usługa zawierająca szczegółowe informacje opisane tutaj. W serwisie tworzony jest eksperyment. Udział ruchu jest ustawiony na przykład na 15%. Procenty są ustalane nie dla zapytań, ale dla użytkowników. Wskazany jest również czas trwania eksperymentu, na przykład tydzień.

Można przeprowadzić kilka eksperymentów jednocześnie. W ustawieniach możesz określić, czy możliwe jest skrzyżowanie z innymi eksperymentami.

W rezultacie usługa automatycznie dodaje argument market_new_functionity=1 do 15% użytkowników. Automatycznie oblicza również wybrane metryki. Po zakończeniu eksperymentu analitycy przyglądają się wynikom i wyciągają wnioski. Na podstawie ustaleń podejmowana jest decyzja o wdrożeniu do produkcji lub udoskonaleniu.

Zręczna ręka rynku: testowanie w produkcji

Często zdarza się, że musisz przetestować działanie nowej funkcjonalności w produkcji, ale nie masz pewności, jak będzie się ona zachowywać w warunkach „bojowych” pod dużym obciążeniem.

Jest na to rozwiązanie: flagi w parametrach CGI można wykorzystać nie tylko do testów A/B, ale także do testowania nowych funkcjonalności.

Stworzyliśmy narzędzie, które pozwala na błyskawiczną zmianę konfiguracji na tysiącach serwerów bez narażania serwisu na ryzyko. Nazywa się to Stop Tap. Pierwotnym pomysłem była możliwość szybkiego wyłączenia niektórych funkcji bez układu. Następnie narzędzie rozszerzyło się i stało się bardziej złożone.

Schemat przepływu usług przedstawiono poniżej:

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Wartości flag ustawia się poprzez API. Usługa zarządzania przechowuje te wartości w bazie danych. Wszystkie serwery łączą się z bazą danych raz na dziesięć sekund, wypompowują wartości flag i stosują te wartości do każdego żądania.

W dotknięciu Stop możesz ustawić dwa rodzaje wartości:

1) Wyrażenia warunkowe. Zastosuj, gdy jedna z wartości jest prawdziwa. Na przykład:

{
	"condition":"IS_DC1",
	"value":"3",
}, 
{
	"condition": "CLUSTER==2 and IS_BERU", 
	"value": "4!" 
}

Wartość „3” zostanie zastosowana, gdy żądanie zostanie przetworzone w lokalizacji DC1. Wartość wynosi „4”, gdy żądanie jest przetwarzane w drugim klastrze dla witryny beru.ru.

2) Wartości bezwarunkowe. Zastosuj domyślnie, jeśli żaden z warunków nie jest spełniony. Na przykład:

wartość, wartość!

Jeśli wartość kończy się wykrzyknikiem, ma wyższy priorytet.

Parser parametrów CGI analizuje adres URL. Następnie stosuje wartości z Stop Tap.

Stosowane są wartości o następujących priorytetach:

  1. Ze zwiększonym priorytetem od Stop Tap (wykrzyknik).
  2. Wartość z żądania.
  3. Wartość domyślna z opcji Zatrzymaj kran.
  4. Wartość domyślna w kodzie.

Istnieje wiele flag wskazanych w wartościach warunkowych - wystarczą one dla wszystkich znanych nam scenariuszy:

  • Centrum danych.
  • Środowisko: produkcja, testowanie, cień.
  • Miejsce: rynek, beru.
  • Numer klastra.

Dzięki temu narzędziu możesz włączyć nową funkcjonalność na określonej grupie serwerów (np. tylko w jednym centrum danych) i przetestować działanie tej funkcjonalności bez szczególnego ryzyka dla całej usługi. Nawet jeśli popełniłeś gdzieś poważny błąd, wszystko zaczęło paść i całe data center przestało działać, balansery będą przekierowywać żądania do innych data center. Użytkownicy końcowi niczego nie zauważą.

Jeśli zauważysz problem, możesz natychmiast przywrócić poprzednią wartość flagi, a zmiany zostaną cofnięte.

Ta usługa ma również swoje wady: programiści bardzo ją uwielbiają i często próbują wcisnąć wszystkie zmiany do Stop Tap. Staramy się zwalczać nadużycia.

Podejście Stop Tap sprawdza się dobrze, gdy masz już stabilny kod gotowy do wdrożenia w środowisku produkcyjnym. Jednocześnie nadal masz wątpliwości i chcesz sprawdzić kod w warunkach „bojowych”.

Jednak Stop Tap nie nadaje się do testowania w trakcie programowania. Dla programistów istnieje oddzielny klaster zwany „klasterem cieni”.

Tajne testy: Gromada Cieni

Żądania z jednego z klastrów są duplikowane do klastra cienia. Jednak moduł równoważący całkowicie ignoruje odpowiedzi z tego klastra. Schemat jego działania przedstawiono poniżej.

Jak działa wyszukiwarka Yandex.Market i co się stanie, jeśli jeden z serwerów ulegnie awarii

Otrzymujemy klaster testowy znajdujący się w rzeczywistych warunkach „bojowych”. Kieruje się tam normalny ruch użytkowników. Sprzęt w obu klastrach jest taki sam, więc można porównać wydajność i błędy.

A ponieważ moduł równoważący całkowicie ignoruje odpowiedzi, użytkownicy końcowi nie zobaczą odpowiedzi z klastra cienia. Dlatego nie bój się popełnić błędu.

odkrycia

Jak zatem zbudowaliśmy wyszukiwarkę Market?

Aby wszystko przebiegało sprawnie, rozdzielamy funkcjonalność na osobne usługi. W ten sposób możemy skalować tylko te komponenty, których potrzebujemy i upraszczać je. Łatwo jest przypisać osobny komponent innemu zespołowi i podzielić się obowiązkami za pracę nad nim. A znaczne oszczędności w żelazie dzięki takiemu podejściu są oczywistym plusem.

Klaster cienia również nam pomaga: możemy rozwijać usługi, testować je w trakcie i nie przeszkadzać użytkownikowi.

Cóż, oczywiście testy w produkcji. Chcesz zmienić konfigurację na tysiącach serwerów? To proste, użyj przycisku Stop Tap. W ten sposób możesz natychmiast wdrożyć gotowe, złożone rozwiązanie i w razie problemów powrócić do wersji stabilnej.

Mam nadzieję, że udało mi się pokazać, jak dzięki stale rosnącej bazie ofert sprawiamy, że Rynek jest szybki i stabilny. Jak rozwiązujemy problemy z serwerem, radzimy sobie z ogromną liczbą żądań, poprawiamy elastyczność usługi i robimy to bez zakłócania procesów pracy.

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

Dodaj komentarz