MongoDB do Postgresa
UWAGA: Ten wpis na blogu jest połączeniem moich MongoDB do Postgresa (2024-03-06) oraz Sequelize vs. Prisma (2023-05-25). Oryginalne wpisy zostały usunięte, a ten wpis zajął ich miejsce, ponieważ oba zawierały zasadniczo tę samą treść/informacje. Migracja rozpoczęła się na początku marca 2023, przełączenie nastąpiło w połowie listopada 2023, a wszystkie instancje starego systemu MongoDB zostały całkowicie wyłączone na początku stycznia 2024.
Wprowadzenie
Podczas pracy w eBay stanąłem przed problemem, który stał się najbardziej technicznie wymagającym wyzwaniem w mojej karierze: migracją Storage Management System (STMS) z MongoDB do Postgresa. Nie była to po prostu zwykła zamiana bazy danych; była to całkowita transformacja architektoniczna krytycznego systemu, który przetwarza ponad 1,5 miliona metryk na minutę w centrach danych eBay, przy wymaganiu zerowego przestoju i zachowaniu niemal całej istniejącej funkcjonalności.
Czym jest STMS?
Storage Management System (STMS) służy jako kluczowe wewnętrzne narzędzie dla zespołu Service & Storage Infrastructure (SSI) w eBay. Monitoruje i zarządza urządzeniami w centrach danych eBay, umożliwiając inżynierom:
- Monitorowanie metryk z dziesiątek macierzy, przełączników, hostów, grup dysków i klastrów
- Obsługę alertów dla przełączników i macierzy
- Wykonywanie zaawansowanych zadań, takich jak alokacje hostów
- Dostęp do danych w czasie rzeczywistym dla innych wewnętrznych usług eBay
STMS obejmuje ponad 70 macierzy, 60 przełączników, 1100 hostów, 900 grup dysków i 200 klastrów w 3 centrach danych eBay. Biorąc pod uwagę jego kluczową rolę w infrastrukturze eBay, jakikolwiek przestój lub utrata funkcjonalności bezpośrednio wpłynęłyby na podstawowe usługi i operacje biznesowe firmy.
Wyzwanie
Dlaczego migracja była konieczna
Decyzja o migracji z MongoDB do Postgresa nie została podjęta lekkomyślnie. Choć MongoDB początkowo dobrze służyło STMS, rosnąca złożoność naszych relacji danych oraz potrzeba bardziej zaawansowanych możliwości zapytań sprawiły, że Postgres był lepszym długoterminowym rozwiązaniem dla naszego zastosowania.
Co sprawiało, że ten problem był trudny
Złożoność tej migracji wynikała z kilku podstawowych wyzwań:
1. Fundamentalne różnice między bazami danych MongoDB i Postgres to zasadniczo różne bazy danych. MongoDB jest bazą dokumentową (NoSQL), co oznacza, że dane są przechowywane jako JSON w kolekcjach, podobnie jak dokumenty w szafce na akta. Postgres jest relacyjną bazą danych (SQL), co oznacza, że dane są przechowywane jako wiersze w tabelach, podobnie jak w arkuszu kalkulacyjnym.
2. Architektura bazy kodu Cały backend STMS został zbudowany tak, aby przetwarzać i zarządzać danymi jako JSON-ami, używając pakietów wyłącznie zgodnych z MongoDB do operacji bazodanowych. Oznaczało to nie tylko zmianę bazy danych, ale przebudowę sposobu, w jaki cała nasza aplikacja obsługiwała dane.
3. Wymóg zerowego przestoju Ze względu na to, jak istotne jest STMS jako narzędzie wewnętrzne, podczas migracji nie mogło być żadnego przestoju. System musiał nadal obsługiwać ponad 1,5 miliona metryk na minutę przez cały proces.
4. Napięty harmonogram i ograniczone doświadczenie Migracja musiała zostać ukończona w ciągu kilku miesięcy, początkowo bez jasnego planu realizacji. Ani ja, ani moi współpracownicy nie mieliśmy doświadczenia w migracji dużej, starszej bazy kodu z baz NoSQL do SQL, a ja miałem ograniczone wcześniejsze doświadczenie z Postgres.
5. Skala i złożoność Migracja obejmowała konwersję 36 kolekcji MongoDB do 74 tabel Postgresa, wymagając starannego uwzględnienia relacji, indeksowania i optymalizacji zapytań.
Wybór odpowiedniego ORM: Sequelize vs Prisma
Jedną z pierwszych ważnych decyzji był wybór narzędzia ORM (Object-Relational Mapping). Ponieważ nasza baza kodu była już zaprojektowana do korzystania z Mongoose dla MongoDB, użycie ORM zapewniłoby najpłynniejszą ścieżkę przejścia.
Analiza wymagań
Po dokładnej analizie potrzeb projektu ustaliłem kluczowe kryteria dla każdego rozwiązania ORM:
- Musi być pakietem JavaScript (większość naszego kodu była napisana w JavaScript)
- Musi obsługiwać Postgresa i większość jego funkcji
- Wydajność musi być co najmniej na równi lub lepsza niż w Mongoose
- Musi być open source i utrzymywany
Kandydaci
Po szeroko zakrojonych badaniach zawęziłem wybór do dwóch głównych kandydatów: Sequelize i Prisma. Stworzyłem kompleksowe środowiska testowe używając Docker dla Postgresa i przekonwertowałem nasz największy, najbardziej złożony zbiór danych ze struktury dokumentowej na strukturę tabel.
Metodyka testów
Dla każdego ORM mierzyłem wydajność w kluczowych operacjach:
- Czas utworzenia wpisu
- Czas aktualizacji wpisu
- Czas aktualizacji zagnieżdżonych wpisów (relacje i pary klucz-wartość JSON)
- Czas usunięcia wpisu
- Czas zapytania/pobrania wpisu
Decyzja: Sequelize
Około 15 maja 2023 zdecydowałem, że Sequelize jest lepszym ORM dla naszego przypadku użycia. Oto dlaczego:
Zalety Sequelize:
- Naprawdę open source i nieutrzymywany przez finansowany startup
- Obsługiwał większość funkcji Postgresa
- Lepsza wydajność, szczególnie w porównaniu z Prisma
- Dojrzały ekosystem z ponad 10 latami rozwoju
- Elastyczna reprezentacja modelu/schematu z użyciem klas JavaScript
- Obsługa złożonych joinów i opcji filtrowania, w tym Regex
Wyniki wydajności:
W moich testach Sequelize znacząco wyprzedzał Prismę. Dla dużych wpisów z naszego zbioru danych:
- Sequelize: ~2,26 sekundy na wpis
- Prisma: ~11,21 sekundy na wpis
Prisma była około 5x wolniejsza niż Sequelize w naszym przypadku użycia. Dodatkowo usunięcie jednego wpisu z naszego największego zbioru danych zajmowało Prisma prawie 4 minuty, co było nie do przyjęcia dla naszych wymagań.
Wyzwania związane z Sequelize:
- Bardziej złożone i rozbudowane reprezentacje modeli (564 linie vs 262 linie w Mongoose)
- Myląca składnia w niektórych przypadkach
- Złożoność migracji bazy danych
- Mniej rozbudowana dokumentacja w porównaniu z Prisma
Porównanie zalet i wad Sequelize oraz Prisma
Aby dać pełniejszy obraz tego, dlaczego wybrałem Sequelize, chcę podzielić się szczegółowymi zaletami i wadami, które zebrałem dla obu ORM-ów podczas oceny. Przyjrzałem się również temu, jak wypadały pod względem reprezentacji schematu i wsparcia społeczności na dzień 15 maja 2023. To głębsze spojrzenie pomogło mi umocnić mój wybór i mam nadzieję, że może być przydatne dla kogoś innego stojącego przed podobną decyzją.
Zalety Sequelize:
- Ma funkcję sync(), która automatycznie tworzy i obsługuje tabele, oszczędzając dużo ręcznej pracy.
- Potrafi obsługiwać złożone joiny dla zagnieżdżonych danych, co było kluczowe dla struktury STMS.
- Obsługuje szeroki zakres opcji filtrowania, w tym Regex, zapewniając elastyczność w zapytaniach.
- Reprezentacja modelu/schematu odbywa się w czystym JavaScript z użyciem klas, które można w wysokim stopniu dostosować do konkretnych potrzeb.
- Bezproblemowo obsługuje połączenia z bazą danych, w tym wsparcie dla wielu połączeń do odczytu.
- Obsługuje surowe zapytania SQL, gdy trzeba zajrzeć pod maskę.
- Statystyki społeczności na dzień 15 maja 2023: Na NPM ostatnia aktualizacja 14 dni temu, 1,505,835 tygodniowych pobrań; na GitHubie ostatnia aktualizacja wczoraj, 4,2 tys. Forków i 27,9 tys. Gwiazdek. Jest open source na licencji MIT od ponad 10 lat, więc mam pewność, że tak pozostanie.
Wady Sequelize:
- Reprezentacja modelu/schematu może stać się bardzo złożona i rozbudowana. Na przykład, podczas gdy reprezentacja Mongoose naszego dużego zbioru danych miała około 262 linie (wraz ze spacjami), ten sam zbiór danych w Sequelize rozrósł się do 564 linii.
- Składnia może być myląca i skomplikowana w niektórych scenariuszach, co czasem mnie spowalniało.
- Migracja lub edycja bazy danych jest uciążliwa. Nawet przy sequelize-cli generującym skrypty migracji, nadal jest to kłopotliwe, choć zauważyłem, że jest to częsty problem większości ORM-ów.
- Dokumentacja nie jest świetna, choć się poprawia. Na szczęście narzędzia takie jak ChatGPT dobrze znają Sequelize dzięki jego długiej historii, co pomogło wypełnić luki.
- Nie jest tak czuły na typy jak Prisma, co w niektórych projektach może prowadzić do problemów.
- Ograniczone wsparcie TypeScript, choć nie było to problemem dla STMS, dla innych może być to czynnik decydujący.
Zalety Prisma:
- Używa własnego języka schematu, dzięki czemu tworzenie modeli jest czystsze i bardziej zwięzłe. Dla porównania, podczas gdy Mongoose zajmowało 262 linie dla naszego dużego zbioru danych, Prisma zmieściła to w zaledwie 221 liniach.
- Dostarczana z narzędziem CLI, które upraszcza tworzenie i migrację bazy danych, co jest najlepszym rozwiązaniem, jakie dotąd widziałem w ORM, nawet jeśli nie jest idealne.
- Obsługuje surowe zapytania SQL, oferując elastyczność, gdy jest potrzebna.
- Składnia kodu jest czysta i prostsza do zrozumienia w porównaniu z Sequelize, co ułatwia naukę.
- Automatycznie generuje konstruktory zapytań dla Node.js i TypeScript za pośrednictwem swojego klienta, co jest miłym dodatkiem.
- Ma doskonałą, przejrzystą dokumentację. ChatGPT nie jest tak aktualny w kwestii Prisma, ale oficjalna dokumentacja często to rekompensowała.
- Statystyki społeczności na dzień 15 maja 2023: Na NPM ostatnia aktualizacja 6 dni temu, 1,344,705 tygodniowych pobrań; na GitHubie ostatnia aktualizacja 3 godziny temu, 1,1 tys. Forków i 31,3 tys. Gwiazdek.
Wady Prisma:
- Nie obsługuje filtrowania Regex dla Postgresa, choć oferuje alternatywy takie jak “contains”, “includes” i “startsWith.”
- Wydajność była głównym problemem w moich testach. Tworzenie wpisów dla naszego dużego zbioru danych zajmowało Prisma około 11,21 sekundy na wpis, w porównaniu z 2,26 sekundy w Sequelize, czyli około 5x wolniej.
- Usunięcie pojedynczego wpisu z dużego zbioru danych zajmowało prawie 4 minuty, co przekreślało to rozwiązanie dla naszych potrzeb.
- Nawet przy uczciwym porównaniu na złożonym zbiorze danych z relacjami na trzy poziomy głębokości, Sequelize był znacząco szybszy przy usuwaniu.
- Prisma jest wspierana przez startup z finansowaniem w wysokości 56,5 miliona dolarów. Chociaż jej główny kod ORM jest open source na licencji Apache-2.0, obawiam się potencjalnych zmian licencyjnych w przyszłości, podobnych do tego, co wydarzyło się z MongoDB.
Te szczegółowe porównania jasno pokazały, że Sequelize lepiej odpowiadał potrzebom STMS, szczególnie pod względem wydajności i długoterminowej niezawodności. Uznałem jednak, że rozłożenie tego na czynniki pierwsze może pomóc innym mierzącym się z podobnym wyborem w swoich projektach.
Proces migracji
Transformacja struktury danych
Przejście ze struktury dokumentowej MongoDB do relacyjnej struktury Postgresa wymagało starannego planowania. Musiałem:
- Analizować relacje: Zidentyfikować, w jaki sposób dokumenty MongoDB są ze sobą powiązane, i zaprojektować odpowiednie relacje kluczy obcych
- Normalizować dane: Rozbić zagnieżdżone dokumenty na osobne tabele tam, gdzie było to właściwe
- Zachować funkcje JSON: Używać kolumn JSONB dla naprawdę niestrukturyzowanych danych, które musiały pozostać elastyczne
- Projektować indeksy: Utworzyć odpowiednie indeksy dla wydajności zapytań
Niestandardowe rozwiązania
Migracja wymagała opracowania kilku niestandardowych rozwiązań:
1. Skrypty migracji danych Stworzyłem kompleksowe skrypty, aby:
- Wyodrębniać dane z kolekcji MongoDB
- Przekształcać struktury dokumentów do formatu relacyjnego
- Importować dane do tabel Postgres z prawidłowymi relacjami
2. Warstwa kompatybilności API Aby utrzymać brak przestojów, zbudowałem warstwę kompatybilności, która mogła:
- Kierować żądania do MongoDB lub Postgresa w zależności od stanu migracji
- Zapewniać spójność danych podczas okresu przejściowego
- Udostępniać mechanizmy awaryjnego przełączenia
3. Niestandardowe oprogramowanie pośredniczące Opracowano oprogramowanie pośredniczące do obsługi różnic w sposobie, w jaki MongoDB i Postgres obsługują niektóre operacje, zapewniając, że istniejące punkty końcowe API nadal działały bez modyfikacji.
Pokonywanie wyzwań technicznych
Obsługa złożonych relacji
Jednym z największych wyzwań było przekształcenie osadzonych dokumentów MongoDB w relacje Postgresa. Na przykład pojedynczy dokument MongoDB mógł zawierać:
- Podstawowe właściwości
- Zagnieżdżone obiekty reprezentujące powiązane encje
- Tablice osadzonych dokumentów
Trzeba to było starannie rozłożyć na:
- Tabele główne dla podstawowych encji
- Tabele łącznikowe dla relacji wiele-do-wielu
- Relacje kluczy obcych dla powiązań jeden-do-wielu
Optymalizacja zapytań
Wzorce zapytań MongoDB nie przekładają się bezpośrednio na SQL. Musiałem:
- Przepisać złożone potoki agregacji jako złączenia SQL
- Zoptymalizować indeksy pod nowe wzorce zapytań
- Zapewnić, że wydajność zapytań osiągała lub przewyższała wydajność MongoDB
Integralność danych
Zapewnienie integralności danych podczas migracji wymagało:
- Kompleksowych skryptów walidacyjnych
- Procedur wycofywania zmian
- Synchronizacji danych w czasie rzeczywistym podczas okresów przejściowych
Wyniki i wpływ
Migracja STMS z MongoDB do Postgresa została pomyślnie ukończona bez przestojów, przy zachowaniu niemal wszystkich funkcji i możliwości. Wyniki przerosły oczekiwania:
Poprawa wydajności:
- Wydajność zapytań poprawiła się w przypadku złożonych zapytań relacyjnych
- Lepsza spójność i integralność danych
- Bardziej efektywne wykorzystanie przestrzeni dyskowej
Korzyści operacyjne:
- Ulepszone możliwości monitorowania i debugowania
- Lepsza integracja z istniejącymi narzędziami SQL firmy eBay
- Ulepszone procedury tworzenia kopii zapasowych i odzyskiwania danych
Wpływ na zespół:
- Rozszerzenie wiedzy zespołu na temat relacyjnych baz danych
- Ustanowienie wzorców dla przyszłych migracji baz danych
- Stworzenie narzędzi i procesów wielokrotnego użytku
Nabyte umiejętności techniczne
Ten projekt znacząco rozszerzył moje kompetencje techniczne:
Technologie baz danych:
- Dogłębne zrozumienie funkcji Postgresa i optymalizacji
- Optymalizacja zapytań SQL i dostrajanie wydajności
- Wzorce projektowania baz danych i normalizacja
- Konfiguracje baz danych główna-zapasowa
Narzędzia deweloperskie:
- ORM Sequelize i budowanie zapytań
- Strategie migracji baz danych
- Metodyki testowania wydajności
- Walidacja danych i sprawdzanie integralności
Wzorce architektoniczne:
- Strategie migracji bez przestojów
- Warstwy kompatybilności API
- Wzorce abstrakcji baz danych
- Systemy monitorowania i alertowania
Rozwój osobisty i zawodowy
Ten projekt migracyjny był przełomowy dla mojego rozwoju zawodowego. Wypchnął mnie na nieznane terytorium, wymagając:
Umiejętności przywódcze:
- Prowadzenia złożonego projektu technicznego bez wcześniejszego doświadczenia
- Podejmowania krytycznych decyzji architektonicznych pod presją
- Koordynacji z wieloma zespołami i interesariuszami
Umiejętności rozwiązywania problemów:
- Rozbijania złożonych problemów na możliwe do opanowania komponenty
- Opracowywania kreatywnych rozwiązań dla bezprecedensowych wyzwań
- Równoważenia wielu konkurujących wymagań i ograniczeń
Komunikacja i praca zespołowa:
- Wyjaśniania pojęć technicznych interesariuszom nietechnicznym
- Dokumentowania procesów i decyzji do przyszłego wykorzystania
- Mentorowania członków zespołu w zakresie nowych technologii i wzorców
Wnioski
Wnioski techniczne
- Wybór bazy danych ma znaczenie: Wybór między NoSQL a SQL powinien opierać się na konkretnych przypadkach użycia i długoterminowych wymaganiach
- Testowanie wydajności jest krytyczne: Teoretyczne zalety nie zawsze przekładają się na realne korzyści wydajnościowe
- Planowanie migracji: Kompleksowe planowanie i testowanie są niezbędne przy złożonych migracjach
- Inwestycja w narzędzia: Zbudowanie odpowiednich narzędzi z wyprzedzeniem oszczędza znaczną ilość czasu i redukuje liczbę błędów
Wnioski z zarządzania projektem
- Komunikacja z interesariuszami: Regularne aktualizacje i jasna komunikacja zapobiegają nieporozumieniom
- Zarządzanie ryzykiem: Posiadanie planów awaryjnych i procedur wycofywania zmian jest niezbędne
- Zarządzanie harmonogramem: Warto przewidzieć zapas czasu na nieoczekiwane wyzwania i krzywe uczenia się
- Dokumentacja: Dokładna dokumentacja umożliwia przekazywanie wiedzy i przyszłe utrzymanie
Wnioski końcowe
Migracja STMS z MongoDB do Postgresa stanowi najbardziej wymagający i najbardziej satysfakcjonujący problem techniczny, jaki rozwiązałem w swojej karierze. Wymagała nie tylko wiedzy technicznej, ale także przywództwa, planowania i zdolności adaptacyjnych. Sukces projektu pokazał, że przy odpowiednim planowaniu, dokładnym testowaniu i zaangażowaniu w doskonałość nawet najbardziej złożone wyzwania techniczne można pokonać.
To doświadczenie fundamentalnie zmieniło moje podejście do inżynierii oprogramowania, podkreślając znaczenie:
- Zrozumienia pełnego kontekstu i wymagań przed podejmowaniem decyzji technicznych
- Inwestowania czasu w odpowiednie narzędzia i testowanie
- Utrzymywania jasnej komunikacji przez cały czas trwania złożonych projektów
- Gotowości do nauki nowych technologii i podejść, gdy jest to konieczne
Sukces migracji nie tylko poprawił możliwości STMS, ale także ustanowił wzorce i procesy, które nadal przynoszą korzyści projektom infrastrukturalnym eBay. Ugruntował moje przekonanie, że przyjmowanie nieznanych wyzwań i odnoszenie w nich sukcesów jest kluczem zarówno do rozwoju osobistego, jak i zawodowego.
Patrząc wstecz, ten projekt stanowi punkt zwrotny w mojej karierze, przekształcając mnie z dewelopera implementującego rozwiązania w inżyniera, który potrafi architektonicznie projektować i prowadzić złożone inicjatywy techniczne. Pewność siebie i umiejętności zdobyte dzięki temu doświadczeniu nadal kierują moim podejściem do nowych wyzwań i możliwości w inżynierii oprogramowania.