Jak przestać się martwić i zacząć żyć bez monolitu

Jak przestać się martwić i zacząć żyć bez monolitu

Wszyscy kochamy historie. Lubimy siadać przy ognisku i rozmawiać o naszych przeszłych zwycięstwach, bitwach lub po prostu o naszym doświadczeniu zawodowym.

Dziś jest właśnie taki dzień. I nawet jeśli nie siedzisz teraz przy ognisku, mamy dla Ciebie historię. Historia tego, jak rozpoczęliśmy pracę nad pamięcią masową w Tarantoolu.

Dawno, dawno temu nasza firma miała kilka „monolitów” i jeden „sufit” dla wszystkich, do którego te monolity powoli, ale pewnie się zbliżały, ograniczając ucieczkę naszej firmy, nasz rozwój. I było jasne zrozumienie: pewnego dnia mocno uderzymy w ten sufit.

Obecnie panuje ideologia oddzielania wszystkiego i wszystkich, od sprzętu po logikę biznesową. W rezultacie mamy na przykład dwa DC, które są praktycznie niezależne na poziomie sieci. A potem wszystko było zupełnie inne.

Obecnie istnieje mnóstwo narzędzi i narzędzi do wprowadzania zmian w postaci CI/CD, K8S itp. W czasach „monolitu” nie potrzebowaliśmy tylu obcych słów. Wystarczyło po prostu poprawić „przechowywanie” w bazie danych.

Czas jednak płynął do przodu, a wraz z nim liczba żądań, czasami przekraczając nasze możliwości w przypadku RPS. Wraz z wejściem na rynek krajów WNP obciążenie procesora bazy danych pierwszego monolitu nie spadło poniżej 90%, a RPS utrzymało się na poziomie 2400. I nie były to tylko małe selektory, ale potężne zapytania z kilka kontroli i JOIN, które mogłyby uruchomić prawie połowę danych na tle dużego IO.

Kiedy na scenie zaczęły pojawiać się pełnoprawne wyprzedaże z okazji Czarnego Piątku – a Wildberries jako jedna z pierwszych zorganizowała je w Rosji – sytuacja stała się całkowicie smutna. Przecież obciążenie w takie dni wzrasta trzykrotnie.
Ach, te „monolityczne czasy”! Jestem pewien, że doświadczyłeś czegoś podobnego i nadal nie możesz zrozumieć, jak mogło ci się to przytrafić.

Co możesz zrobić - moda jest nieodłącznym elementem technologii. Około 5 lat temu musieliśmy przemyśleć jeden z tych modów w postaci istniejącej witryny na serwerze .NET i MS SQL, który starannie zapisał całą logikę samej witryny. Trzymałem go na tyle starannie, że piłowanie takiego monolitu okazało się długą i wcale niełatwą przyjemnością.
Mała dygresja.

Na różnych wydarzeniach mówię: „jeśli nie widziałeś monolitu, to nie urosłeś!” Ciekaw jestem Twojej opinii w tej kwestii, napisz ją w komentarzach.

Dźwięk grzmotu

Wróćmy do naszego „ogniska”. Aby rozłożyć obciążenie „monolityczną” funkcjonalnością, postanowiliśmy podzielić system na mikroserwisy oparte na technologiach open source. Ponieważ są co najmniej tańsze w skalowaniu. I mieliśmy 100% zrozumienia, że ​​będziemy musieli skalować (i to dużo). Przecież już wtedy można było wejść na rynki sąsiadujących krajów, a liczba rejestracji, a także liczba zamówień zaczęła jeszcze mocniej rosnąć.

Po przeanalizowaniu pierwszych kandydatów do odejścia od monolitu na rzecz mikroserwisów zdaliśmy sobie sprawę, że 80% tekstu w nich pochodzi z systemów back office, a czytanie z front office. Przede wszystkim dotyczyło to kilku ważnych dla nas podsystemów – danych użytkownika oraz systemu wyliczania ostatecznego kosztu towaru na podstawie informacji o dodatkowych rabatach i kuponach dla klientów.

Zębaty. Teraz aż strach to sobie wyobrazić, ale oprócz wyżej wymienionych podsystemów z naszego monolitu usunięto także katalogi produktów, koszyk użytkownika, system wyszukiwania produktów, system filtrowania katalogów produktów i różnego rodzaju systemy rekomendacji. Do działania każdego z nich istnieją osobne klasy wąsko dostosowanych systemów, ale kiedyś wszyscy mieszkali w jednym „domu”.

Od razu planowaliśmy przeniesienie danych o naszych klientach do systemu sharded. Usunięcie funkcjonalności obliczania ostatecznego kosztu towaru wymagało dobrej skalowalności odczytu, ponieważ powodowało największe obciążenie RPS i było najtrudniejsze do wdrożenia dla bazy danych (w proces kalkulacji zaangażowanych jest dużo danych).

W rezultacie opracowaliśmy schemat, który dobrze pasuje do Tarantool.

W tym czasie do działania mikroserwisów wybrano schematy pracy z kilkoma centrami danych na maszynach wirtualnych i sprzętowych. Jak pokazano na rysunkach, opcje replikacji Tarantool zostały zastosowane zarówno w trybie master-master, jak i master-slave.

Jak przestać się martwić i zacząć żyć bez monolitu
Architektura. Opcja 1. Obsługa użytkowników

W chwili obecnej istnieją 24 odłamki, z których każdy ma 2 instancje (po jednej dla każdego DC), wszystkie w trybie master-master.

Na bazie danych znajdują się aplikacje uzyskujące dostęp do replik baz danych. Aplikacje współpracują z Tarantool poprzez naszą niestandardową bibliotekę, która implementuje interfejs sterownika Tarantool Go. Widzi wszystkie repliki i może współpracować z mistrzem przy czytaniu i pisaniu. Zasadniczo implementuje model zestawu replik, który dodaje logikę wyboru replik, wykonywania ponownych prób, wyłącznika automatycznego i limitu szybkości.

W takim przypadku istnieje możliwość skonfigurowania polityki wyboru replik w kontekście fragmentów. Na przykład roundrobin.

Jak przestać się martwić i zacząć żyć bez monolitu
Architektura. Opcja 2. Usługa wyliczenia ostatecznego kosztu towaru

Kilka miesięcy temu większość próśb o wyliczenie ostatecznego kosztu towaru trafiła do nowego serwisu, który w zasadzie działa bez baz danych, jednak jakiś czas temu wszystko zostało w 100% przetworzone przez serwis z Tarantoolem pod maską.

Baza danych usługi składa się z 4 wzorców, do których synchronizator gromadzi dane, a każdy z tych wzorców replikacji dystrybuuje dane do replik tylko do odczytu. Każdy mistrz ma około 15 takich replik.

Zarówno w pierwszym, jak i w drugim schemacie, jeśli jeden DC jest niedostępny, aplikacja może odebrać dane w drugim.

Warto zaznaczyć, że replikacja w Tarantoolu jest dość elastyczna i można ją konfigurować w czasie wykonywania. W innych systemach pojawiły się trudności. Przykładowo zmiana parametrów max_wal_senders i max_replication_slots w PostgreSQL wymaga ponownego uruchomienia kreatora, co w niektórych przypadkach może doprowadzić do zerwania połączeń pomiędzy aplikacją a systemem DBMS.

Szukaj i znajduj!

Dlaczego nie zrobiliśmy tego „jak normalni ludzie”, ale wybraliśmy nietypowy sposób? To zależy od tego, co jest uważane za normalne. Wiele osób zazwyczaj tworzy klaster z Mongo i rozprowadza go po trzech rozproszonych geograficznie DC.

W tym czasie mieliśmy już dwa projekty Redis. Pierwsza była pamięcią podręczną, a druga trwałym magazynem niezbyt krytycznych danych. Było z nim dość ciężko, częściowo z naszej winy. Czasami kluczem były dość duże wolumeny i od czasu do czasu strona źle się prezentowała. Zastosowaliśmy ten system w wersji master-slave. I było wiele przypadków, gdy coś stało się z mistrzem i replikacja się zepsuła.

Oznacza to, że Redis jest dobry do zadań bezstanowych, a nie stanowych. W zasadzie pozwalało to rozwiązać większość problemów, ale tylko wtedy, gdy były to rozwiązania typu klucz-wartość z parą indeksów. Ale Redisowi w tamtym czasie było dość smutno z powodu wytrwałości i replikacji. Ponadto pojawiły się skargi dotyczące wydajności.

Myśleliśmy o MySQL i PostgreSQL. Ale to pierwsze jakoś do nas nie trafiło, a drugie jest samo w sobie dość wyrafinowanym produktem i niestosowne byłoby budowanie na nim prostych usług.
Próbowaliśmy RIAK, Cassandra, a nawet baza danych grafów. To wszystko są rozwiązania dość niszowe, które nie nadawały się do roli ogólnego, uniwersalnego narzędzia do tworzenia usług.

Ostatecznie zdecydowaliśmy się na Tarantool.

Zwróciliśmy się do niego, gdy był w wersji 1.6. Zainteresowała nas symbioza klucz-wartość i funkcjonalność relacyjnej bazy danych. Istnieją indeksy wtórne, transakcje i spacje, są one jak tabele, ale nie są proste, można w nich przechowywać różną liczbę kolumn. Ale zabójczą cechą Tarantoola były indeksy wtórne połączone z wartością klucza i transakcyjnością.

Ważną rolę odegrała także reagująca rosyjskojęzyczna społeczność, gotowa do pomocy na czacie. Aktywnie z tego korzystaliśmy i żyjemy bezpośrednio na czacie. I nie zapomnij o przyzwoitej wytrwałości, bez oczywistych błędów i błędów. Jeśli spojrzysz na naszą historię z Tarantoolem, mieliśmy wiele problemów i niepowodzeń z replikacją, ale nigdy nie straciliśmy danych z jej winy!

Wdrożenie rozpoczęło się ostro

W tamtym czasie naszym głównym stosem programistycznym była platforma .NET, do której nie było złącza dla Tarantool. Od razu zaczęliśmy robić coś w Go. Z Luą też wszystko działało dobrze. Głównym problemem w tamtym czasie było debugowanie: w .NET wszystko jest z tym świetnie, ale potem trudno było zanurzyć się w świat wbudowanego Lua, gdy nie ma debugowania poza logami. Dodatkowo z jakiegoś powodu replikacja okresowo się rozpadała, więc musiałem zagłębić się w konstrukcję silnika Tarantool. Pomógł w tym czat i w mniejszym stopniu dokumentacja, czasem zaglądaliśmy do kodu. Dokumentacja była wówczas taka sobie.

Tak więc w ciągu kilku miesięcy udało mi się zebrać myśli i uzyskać przyzwoite wyniki pracy z Tarantool. Zestawiliśmy rozwiązania referencyjne w git, które pomogły w tworzeniu nowych mikrousług. Przykładowo, gdy pojawiło się zadanie: stworzenia kolejnego mikroserwisu, programista zajrzał do kodu źródłowego rozwiązania referencyjnego w repozytorium i utworzenie nowego zajęło nie więcej niż tydzień.

To były wyjątkowe czasy. Konwencjonalnie możesz wtedy podejść do administratora przy stoliku obok i zapytać: „Daj mi maszynę wirtualną”. Około trzydzieści minut później samochód był już przy tobie. Połączyłeś się, wszystko zainstalowałeś i ruch został do Ciebie wysłany.

Dziś to już nie będzie działać: trzeba dodać do usługi monitoring i logowanie, objąć funkcjonalność testami, zamówić maszynę wirtualną lub dostawę do Kubera itp. Generalnie tak będzie lepiej, chociaż zajmie to więcej czasu i będzie bardziej kłopotliwe.

Dziel i rządź. O co chodzi z Luą?

Pojawił się poważny dylemat: niektóre zespoły nie były w stanie wiarygodnie wprowadzić zmian w usłudze przy użyciu dużej ilości logiki w Lua. Często towarzyszyło temu niedziałanie usługi.

Oznacza to, że programiści przygotowują jakąś zmianę. Tarantool rozpoczyna migrację, ale replika nadal ma stary kod; Jakiś DDL lub coś innego dociera tam poprzez replikację, a kod po prostu się rozpada, ponieważ nie jest brany pod uwagę. W rezultacie procedura aktualizacji dla administratorów została zapisana na kartce A4: zatrzymaj replikację, zaktualizuj to, włącz replikację, wyłącz tutaj, zaktualizuj tam. Koszmar!

W rezultacie teraz najczęściej staramy się nie robić nic w Lua. Po prostu użyj iproto (protokół binarny do interakcji z serwerem) i to wszystko. Być może wynika to z braku wiedzy wśród programistów, ale z tego punktu widzenia system jest złożony.

Nie zawsze ślepo podążamy za tym scenariuszem. Dziś nie mamy czerni i bieli: albo wszystko jest w Lua, albo wszystko jest w Go. Rozumiemy już, jak możemy je połączyć, aby później nie skończyć się problemami z migracją.

Gdzie jest teraz Tarantool?
Tarantool służy w serwisie do wyliczania ostatecznego kosztu towaru z uwzględnieniem kuponów rabatowych, zwanego także „Promotorem”. Jak mówiłem wcześniej, odchodzi obecnie na emeryturę: na jego miejsce wchodzi nowy serwis katalogowy z przeliczonymi cenami, ale pół roku temu wszystkie wyliczenia były robione w Promotizerze. Wcześniej połowa jego logiki była napisana w Lua. Dwa lata temu serwis zamieniono na magazyn, a logikę przepisano w Go, bo zmieniła się trochę mechanika rabatów i serwisowi zabrakło wydajności.

Jedną z najważniejszych usług jest profil użytkownika. Oznacza to, że wszyscy użytkownicy Wildberries są przechowywani w Tarantool, a jest ich około 50 milionów.System podzielony na fragmenty według identyfikatora użytkownika, rozdzielony na kilka kontrolerów domeny podłączonych do usług Go.
Według RPS Promotor był kiedyś liderem, osiągając 6 tys. żądań. W pewnym momencie mieliśmy 50-60 egzemplarzy. Obecnie liderem w RPS są profile użytkowników, których jest około 12 tys. Usługa ta wykorzystuje niestandardowy sharding, podzielony przez zakresy identyfikatorów użytkowników. Usługa obsługuje ponad 20 maszyn, ale to za dużo, planujemy zmniejszyć przydzielone zasoby, bo wystarcza na to pojemność 4-5 maszyn.

Usługa sesji to nasza pierwsza usługa na vshard i Cartridge. Konfiguracja vsharda i aktualizacja Cartridge'a wymagały od nas pewnego wysiłku, ale ostatecznie wszystko się udało.

Usługa wyświetlania różnych banerów na stronie internetowej i w aplikacji mobilnej była jedną z pierwszych, która została udostępniona bezpośrednio w Tarantool. Usługa ta wyróżnia się tym, że ma 6-7 lat, nadal działa i nigdy nie została ponownie uruchomiona. Zastosowano replikację typu master-master. Nigdy nic się nie zepsuło.

Poniżej znajduje się przykład wykorzystania Tarantoola do szybkiego sprawdzania informacji w systemie magazynowym, aby w niektórych przypadkach szybko i dokładnie sprawdzić informacje. Próbowaliśmy wykorzystać do tego Redisa, jednak dane w pamięci zajmowały więcej miejsca niż Tarantool.

Usługi listy oczekujących, subskrypcji klientów, modnych obecnie historii i towarów odroczonych działają również z Tarantool. Ostatnia usługa w pamięci zajmuje około 120 GB. Jest to najbardziej kompleksowa usługa z powyższych.

wniosek

Dzięki indeksom wtórnym w połączeniu z wartością klucza i transakcyjnością Tarantool doskonale nadaje się do architektur opartych na mikrousługach. Jednakże napotkaliśmy trudności podczas wdrażania zmian w usługach z dużą logiką w Lua - usługi często przestały działać. Nie byliśmy w stanie tego przezwyciężyć i z czasem doszliśmy do różnych kombinacji Lua i Go: wiemy, gdzie używać jednego języka, a gdzie innego.

Co jeszcze przeczytać na ten temat

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

Dodaj komentarz