User Action Service: od Monolith do Cloud

(Souhaib Guitouni) (23 czerwca 2020 r.)

Wprowadzenie

W przeszłości zaplecze BlaBlaCar było wielkim monolitem PHP. Pozwoliło nam to na szybkie iterowanie i tworzenie funkcji, ale na dłuższą metę nie było łatwo to zrozumieć, utrzymać i ewoluować. W ciągu ostatnich kilku lat przełamywaliśmy ten stary monolit i przechodziliśmy w kierunku architektury zorientowanej na usługi.

Ten artykuł jest jedną z historii o tym, jak zarządzamy tym przejściem, z pewnymi szczegółami na temat narzędzia, które pomogły nam w drodze. Omówi techniczne wybory stosu, ogólną architekturę i opinie na temat używanych przez nas narzędzi.

I – Dlaczego

Wraz z rozwojem działalności BlaBlaCar, posiadanie architektury monolitycznej staje się coraz bardziej ograniczające, głównie dlatego, że:

  • W miarę życia monolity łączą się ze sobą;
  • Trudno jest zorganizować zespoły pracujące nad oddzielnymi zaległościami w oparciu o ten sam kod;
  • Monolity są trudne do zrozumienia dla nowicjuszy;
  • Z powyższego każda nowa funkcjonalność staje się niezwykle kosztowna.

Dlatego w ciągu ostatnich kilku lat przeprojektowywaliśmy naszą platformę na architekturę SOA, poszukuję:

  • Serwery o zakresie funkcjonalnym: usługa zarządza pojedynczą funkcjonalnością i jest w pełni odpowiedzialna za sposób jej implementacji.
  • Luźno powiązane usługi, które mogą ewoluować niezależnie. Zespoły mogą pracować i wdrażać we własnym tempie.
  • Więcej własności kodu, dzięki czemu usługi mają zdefiniowany i bardziej ograniczony zakres, co umożliwia zespołom ich konserwację i obsługę.

II – Zakres i historia działań użytkowników

Ostatnim celem, który miał zostać przekształcony w niezależną usługę, były działania użytkowników. Pomagają naszemu zespołowi ds. Relacji ze społecznością diagnozować i rozwiązywać problemy użytkowników, takie jak zwracanie środków i wykrywanie anomalii lub śledzenie nieuczciwych zachowań.

Jak można się spodziewać, liczba działań użytkowników jest kolosalna. Historycznie, jako jedna tabela SQL, ta część kodu miała problemy z wydajnością. Za każdym razem znajdowaliśmy rozwiązania, ale wraz z naszą ekspansją problemy stawały się coraz większe:

  • Pierwszym rozwiązaniem było utworzenie indeksów w celu przyspieszenia zapytań;
  • Kolejnym był fragment bazę danych w wielu tabelach.

Jednak rozwiązania te osiągnęły swój limit iz czasem zaczęły pojawiać się problemy z wydajnością.

III – Przechowywanie danych

1 – Droga do NoSQL

Wybór magazynu danych był głównie wymagania:

  • Istnieje ogromna ilość danych
  • Duża ilość wstawień
  • Wiele odczytów na sekundę, przy zapotrzebowaniu na świeże dane i wydajność
  • Możliwość filtrowania w rozsądnym czasie

Oczywiście szukaliśmy bazy danych NoSQL, ponieważ dystrybucja pozwoliłaby nam przechowywać i manipulować dużymi ilościami danych oraz skalować, gdy potrzebne.

2 – Usługa zarządzana

Chcieliśmy też z zarządzaną usługą, aby obniżyć koszty konserwacji. Rozproszone bazy danych, takie jak Hbase i Cassandra, są znane z trudności, jakie napotykają zespoły zarządzające bazami danych. Co ważniejsze, dla zespołu tworzącego aplikacje chcieliśmy skupić się na logice obsługi działań użytkowników, zamiast spędzać czas na naprawianiu problemów z infrastrukturą bazy danych. Była to również okazja do przetestowania nowego produktu, gdyż zakres zastosowania nie jest zbyt szeroki. Chcieliśmy spróbować czegoś nowego!

3 – Ostateczny wybór

Wybór padł na Bigtable z następujących powodów:

  • Wolumen: Został zaprojektowany do obsługi dużych ilości danych, w przeciwieństwie do większości baz danych SQL, instancja może obsłużyć 10 000 wstawień na sekundę, więc wybraliśmy minimalna konfiguracja z tylko trzema węzłami.
  • Skalowalność: jest skalowalna i łatwa w replikacji, można również zarządzać wersjami danych.
  • Koszt zarządzania: jest to usługa zarządzana.
  • Wydajność: jest to usługa GCP, która zapewni nam doskonałą wydajność, ponieważ będzie działać w tej samej infrastrukturze, co usługa wdrożona w GKE.

III – Skakanie z jednego jadącego pociągu do drugiego

Trudna sprawa przejście z monolitu do usługi oznacza zapewnienie ciągłości usługi z zewnętrznego punktu widzenia i brak utraty danych.

Aby to zapewnić, zdecydowaliśmy się uruchomić nową usługę, utrzymać działający stary system i napisać nowe akcje przez REST w obu z nich. Następnym krokiem będzie przeniesienie danych historycznych z monolitu do nowej usługi. Ta operacja może spowodować podwojenie, więc wstępne ładowanie danych powinno obsługiwać deduplikację. Trzecim krokiem będzie odczyt z nowej usługi zamiast ze starego systemu. Ostatnim krokiem byłoby zamknięcie części monolitycznej i starszej bazy danych SQL, gdy wszystko już działa w usłudze.

IV – Przenoszenie danych

1 – Od MySQL do Bigtable

Teraz, gdy zdecydowaliśmy, jaki będzie nasz docelowy magazyn danych i jak zostanie wdrożony, zaczęliśmy myśleć o sposoby przenoszenia danych z monolitu do nowej bazy danych. Taka operacja jest krytyczna, a zadanie migracji powinno być:

  • Proste i łatwe do opracowania: złożoność związana z łącznikami baz danych
  • Wysoka wydajność: ponieważ będzie czytać ogromne ilości danych, chcemy, aby wynik był jak najszybszy
  • Niezawodny: nie chcieliśmy utraty danych
  • Łatwy do ponownego uruchomienia: gdyby coś poszło nie tak, chcieliśmy czegoś, co moglibyśmy po prostu uruchom ponownie bez wielu ręcznych działań, ze skryptami powłoki wszędzie i złożoną procedurą
  • Umożliwienie transformacji: musieliśmy połączyć dane z wielu baz danych i tabel MySQL, aby uzyskać ostateczne wersje Bigtable, może to być trudne, jeśli skrypty ręcznie.

2 – Apache Beam i Dataflow

Zdecydowaliśmy się skorzystać z Dataflow, rozproszonej usługi zarządzanej dostarczanej przez Google Cloud, która umożliwia przenoszenie danych w trybie wsadowym i strumieniowym.

Z drugiej strony Apache Beam to platforma używana do kodowania rozproszonych skryptów . Następnie możesz go uruchomić na wielu rozproszonych silnikach, takich jak Dataflow, Spark, Flink… Innymi słowy, jest to warstwa abstrakcji do definiowania transformacji, które mogą być zrozumiane przez wiele silników.

Kolejną fajną rzeczą dotyczącą Apache Beam jest że ma gotowe złącza do wielu źródeł danych, w tym MySQL i Bigtable. Dlatego stworzyliśmy transformacje danych, czytając ze starszych tabel MySQL, łącząc je i umieszczając wynik w Bigtable.

2 – Jak poszło?

Podczas migracji poczyniliśmy kilka obserwacji:

  • Było to wyczerpujące zadanie dla MySQL: aby uniknąć problemów z wydajnością, w jakikolwiek sposób należy unikać uruchamiania go w krytycznej bazie danych. Aby uniknąć tego problemu, uruchomiliśmy go na bazie danych repliki stworzonej do takich zadań. Śledziliśmy wykonanie naszej usługi monitorowania (Prometheus / Grafana), która pokazała, że ​​równoległe maszyny Dataflow wyczerpują MySQL.
  • Również dla Bigtable nie było to łatwe: mieliśmy małą instancję 3 maszyn, które były w stanie dać 30 000 wstawek na sekundę. Jeśli wykonujesz wiele zadań Dataflow, wykraczasz daleko poza to. Zastanów się więc mądrze, ile maszyn chcesz mieć równolegle, ponieważ maksymalna liczba spowoduje utratę pieniędzy.
  • Złącze MySQL Beam nie przesyła strumieniowo danych: Złącze MySQL wykonuje instrukcję SQL i czeka aby załadować całą odpowiedź i kontynuować. To spowoduje problemy z pamięcią RAM, jeśli załadujesz dużo danych. Musisz więc przetestować i zdefiniować zakresy użytkowników, aby uniknąć wyjątku pamięci.

V – Usługa zaplecza

Możliwe było wiele wzorców architektury, my chciałem wybrać architekturę, która może ewoluować w przyszłości i którą możemy budować krok po kroku, z ruchem na żywo od pierwszego kroku.

Zdecydowaliśmy się stworzyć usługę za pomocą Spring WebFlux, reaktywnej struktury , aby mieć nieblokujące żądania, a następnie lepszą wydajność z funkcjonalnymi punktami końcowymi. Użyliśmy Reactor, aby uzyskać najlepszą integrację ze Spring.

1 – Testowanie integracji z Bigtable

Testy integracyjne wywołują API z wieloma ładunkami / nagłówkami i sprawdzają, czy odpowiedź jest zgodna z oczekiwaniami. Aby to zrobić, potrzebowaliśmy instancji Bigtable za naszą usługą, ponieważ chcieliśmy przeprowadzić testy w prawdziwym życiu.

Ta instancja musi być czyszczona przy każdym uruchomieniu, aby za każdym razem uruchamiać się z tego samego stanu.

Rozwiązaniem było użycie emulatora Bigtable obecnego w zestawie SDK klienta Bigtable. Pakiet SDK jest bardzo bogaty i zawiera więcej funkcji, takich jak zarządzanie i monitorowanie przez administratora.

2 – Wdrażanie i infrastruktura

Nasza infrastruktura GCP jest ponad Google Kubernetes i Istio. Całość zarządzamy z Helm and Flux. Na naszym blogu pojawią się inne artykuły, aby dowiedzieć się więcej o naszej infrastrukturze!

Oczywiście nasza usługa miała klasyczne zakończenia monitorowania, logowania i alertów, bez nich nie bylibyśmy w stanie jej uruchomić. , w oparciu o Prometheus / Grafana i ELK.

Ostatnie przemyślenia

Aby zarządzać dużymi ilościami danych, przeszliśmy do Bigtable dzięki możliwości skalowania.Mieliśmy wiele wyzwań, takich jak zdefiniowanie schematu danych za pomocą wzorca kluczowania Bigtable, przenoszenie dużych ilości danych z lokalnej bazy danych SQL do zarządzanej bazy danych NoSQL, testowanie i monitorowanie całości.

Na początku wdrożyliśmy usługę w naszym lokalnym centrum danych i przechodząc do GCP podzieliliśmy opóźnienie na trzy. Nasze zespoły ds. Relacji ze społecznością mają teraz krótsze czasy odpowiedzi i są zachwycone.