Cześć! Nazywam się Nikolaj Golow. Wcześniej pracowałem w Avito i przez sześć lat kierowałem platformą danych, zajmując się wszystkimi bazami: analitycznymi (Vertica, ClickHouse), strumieniowymi i OLTP (Redis, Tarantool, VoltDB, MongoDB, PostgreSQL). W tym czasie zapoznałem się z dużą liczbą baz danych — bardzo różnych i nietypowych oraz z nietypowymi przypadkami ich użycia.
Obecnie pracuję w ManyChat. W zasadzie to startup — nowy, ambitny i szybko rozwijający się. I kiedy tylko dołączyłem do firmy, pojawiło się klasyczne pytanie: „Co teraz powinien wybrać młody startup z rynku DBMS i baz danych?”.
W tym artykule, opartym na moim wystąpieniu na , odpowiem na to pytanie. Wersja wideo prezentacji jest dostępna na .

Powszechnie znane bazy danych z 2020 roku
Mamy rok 2020, rozejrzałem się i dostrzegłem trzy typy baz danych.
Pierwszy typ — klasyczne bazy OLTP: PostgreSQL, SQL Server, Oracle, MySQL. Zostały napisane dawno temu, ale wciąż są aktualne, ponieważ są dobrze znane środowisku programistów.
Drugi typ — bazy z "zerowych". Starały się odejść od klasycznych wzorców, rezygnując z SQL, tradycyjnych struktur i ACID, dzięki wbudowanemu shardingowi i innym atrakcyjnym funkcjom. Na przykład, to Cassandra, MongoDB, Redis lub Tarantool. Wszystkie te rozwiązania chciały zaoferować rynkowi coś zasadniczo nowego i zajęły swoją niszę, ponieważ w określonych zadaniach okazały się niezwykle wygodne. Te bazy określę szerokim terminem NOSQL.
"Zerowe" się zakończyły, do baz NOSQL przywykliśmy, a świat, z mojego punktu widzenia, uczynił kolejny krok — ku zarządzanym bazom. Ich rdzeń jest taki sam jak w klasycznych bazach OLTP lub nowych NoSQL. Jednak nie wymagają DBA i DevOps i działają na zarządzanym sprzęcie w chmurze. Dla programisty to "po prostu baza", która gdzieś działa, a to, jak została zainstalowana na serwerze, kto skonfigurował serwer i kto go aktualizuje, nikogo nie obchodzi.
Przykłady takich baz:
- AWS RDS — zarządzana nakładka na PostgreSQL/MySQL.
- DynamoDB — odpowiednik bazy opartej na dokumentach AWS, przypomina Redis i MongoDB.
- Amazon Redshift — zarządzana baza analityczna.
Jest to oparta na starych bazach, ale przeniesiona do zarządzanego środowiska, bez potrzeby pracy ze sprzętem.
Uwaga. Przykłady zostały wybrane dla środowiska AWS, ale ich odpowiedniki istnieją również w Microsoft Azure, Google Cloud lub Yandex.Cloud.

Co więc nowego z tego? W 2020 roku nic z tego.
Koncepcja Serverless
Rzeczywiście nowe na rynku w 2020 roku to rozwiązania serverless lub bezserwerowe.
Postaram się wyjaśnić, co to oznacza, na przykładzie zwykłej usługi lub aplikacji backendowej.
Aby uruchomić zwykłą aplikację backendową, kupujemy lub wynajmujemy serwer, kopiujemy na niego kod, publikujemy na zewnątrz endpoint i regularnie płacimy za wynajem, prąd i usługi centrum danych. To standardowy schemat.
Czy można to zrobić inaczej? Z usługami bezserwerowymi można.
Na czym polega ten sposób: nie ma serwera, nawet wynajmowania wirtualnego instance'u w chmurze. Aby uruchomić usługę, kopiujemy kod (funkcje) do repozytorium i publikujemy na zewnątrz endpoint. Następnie płacimy tylko za każde wywołanie tej funkcji, całkowicie ignorując sprzęt, na którym jest wykonywana.
Postaram się zilustrować to podejście obrazkami.

Klasyczny deployment. Mamy usługę z określonym obciążeniem. Podnosimy dwa instancje: fizyczne serwery lub instancje w AWS. Do tych instancji kierowane są zewnętrzne zapytania, które są tam przetwarzane.
Jak widać na obrazku, serwery są wykorzystywane w różnym stopniu. Jeden jest wykorzystywany w 100%, obsługując dwa zapytania, a drugi tylko w 50% — częściowo stoi bezczynnie. Jeśli przyjdzie nie trzy zapytania, a 30, to cały system nie poradzi sobie z obciążeniem i zacznie zwalniać.

Bezserwerowy deployment. W środowisku bezserwerowym taka usługa nie ma instancji ani serwerów. Jest pewien zbiór rozgrzanych zasobów — małych przygotowanych kontenerów Docker z wdrożonym kodem funkcji. System otrzymuje zewnętrzne zapytania i na każde z nich bezserwerowy framework uruchamia mały kontener z kodem: przetwarza właśnie to zapytanie i zamyka kontener.
Jedno zapytanie — jeden uruchomiony kontener, 1000 zapytań — 1000 kontenerów. A wdrażanie na serwerach fizycznych to już zadanie dostawcy chmury. Jest to całkowicie ukryte przez bezserwerowy framework. W tej koncepcji płacimy za każde wywołanie. Na przykład, jeśli przychodzi jedno wywołanie dziennie — płacimy za jedno wywołanie, przyjdzie milion na minutę — płacimy za milion. Lub na sekundę, to też się zdarza.
Koncepcja publikacji funkcji bezserwerowej nadaje się do serwisu stateless. A jeśli potrzebujesz serwisu statefull, należy dodać bazę danych. W takim przypadku, gdy dochodzi do pracy ze stanem, każda funkcja statefull po prostu zapisuje i odczytuje z bazy danych. Co więcej, z bazy danych dowolnego z trzech typów opisanych na początku artykułu.
Jakie ograniczenie ogólne mają wszystkie te bazy? To koszty związane z ciągle używanym serwerem w chmurze lub fizycznym (lub kilkoma serwerami). Niezależnie od tego, czy korzystamy z klasycznej bazy, czy zarządzanej, czy mamy Devops i administratora, wciąż płacimy 24 na 7 za sprzęt, elektryczność i wynajem centrum danych. Jeśli mamy klasyczną bazę, płacimy za master i slave. Jeśli mamy wysokoobciążoną, sharded bazę – płacimy za 10, 20 lub 30 serwerów, i płacimy non stop.
Obecność w strukturze wydatków stale zarezerwowanych serwerów dawniej była postrzegana jako nieuniknione zło. Zwykłe bazy mają również inne trudności, takie jak limity na liczbę połączeń, ograniczenia skalowalności, geograficzny konsensus – można je jakoś rozwiązać w określonych bazach, ale nie wszystkie na raz i nie idealnie.
Bezserwerowa baza danych – teoria
Pytanie z 2020 roku: czy bazę danych można również uczynić bezserwerową? Wszyscy słyszeli o bezserwerowym backendzie… a dlaczego by nie spróbować także bazy danych uczynić bezserwerową?
To brzmi dziwnie, ponieważ baza danych to statefull serwis, niezbyt odpowiedni dla infrastruktury bezserwerowej. Przy tym również stan bazy danych jest bardzo duży: gigabajty, terabajty, a w bazach analitycznych nawet petabajty. Nie można go tak po prostu umieścić w lekkich kontenerach Docker.
Z drugiej strony, prawie wszystkie nowoczesne bazy to ogromna ilość logiki i komponentów: transakcje, zapewnienie integralności, procedury, relacyjne zależności i wiele logiki. Znaczna część logiki bazy danych potrzebuje stosunkowo niewielkiego stanu. Gigabajty i terabajty są bezpośrednio wykorzystywane tylko przez małą część logiki bazy danych związanej z bezpośrednim wykonywaniem zapytań.
W związku z tym pomysł: jeśli część logiki dopuszcza stateless wykonanie, dlaczego by nie podzielić bazy na części Stateful i Stateless.
Bezserwerowe rozwiązania dla OLAP
Przyjrzyjmy się, jak może wyglądać podział bazy danych na części Stateful i Stateless na praktycznych przykładach.

Na przykład, mamy analityczną bazę danych: dane zewnętrzne (czerwony cylinder po lewej), proces ETL, który ładował dane do bazy, oraz analityk, który wysyła zapytania SQL do bazy. To klasyczny schemat działania hurtowni danych.
W tym schemacie, warunkowo, proces ETL wykonuje się raz. Później trzeba stale płacić za serwery, na których działa baza z danymi załadowanymi przez ETL, aby można było wysyłać zapytania.
Rozważmy alternatywne podejście, które zostało wdrożone w bazie AWS Athena Serverless. Tutaj nie ma serwera, który byłby stale dedykowany do przechowywania załadowanych danych. Zamiast tego:
- Użytkownik wysyła zapytanie SQL do Athena. Optymalizator Athena analizuje zapytanie SQL i szuka w magazynie metadanych konkretnych danych potrzebnych do wykonania zapytania.
- Optymalizator, na podstawie zgromadzonych danych, wyciąga potrzebne dane z zewnętrznych źródeł do tymczasowego magazynu (tymczasowej bazy danych).
- W tymczasowym magazynie wykonuje się zapytanie SQL od użytkownika, a wynik jest zwracany użytkownikowi.
- Tymczasowy magazyn jest czyszczony, zasoby są zwalniane.
W tej architekturze płacimy tylko za proces wykonania zapytania. Brak zapytań — brak wydatków.

To skuteczne podejście i jest realizowane nie tylko w Athena Serverless, ale także w Redshift Spectrum (w AWS).
Na przykładzie Athena widać, że serwerowa baza danych działa na rzeczywistych zapytaniach z dziesiątkami i setkami terabajtów danych. Dla setek terabajtów potrzebne będą setki serwerów, ale nie musimy za nie płacić — płacimy za zapytania. Prędkość każdego zapytania jest (bardzo) niska w porównaniu z wyspecjalizowanymi bazami analitycznymi, takimi jak Vertica, ale nie płacimy za okresy bezczynności.
Taka baza danych nadaje się do rzadkich analitycznych zapytań ad-hoc. Na przykład, gdy spontanicznie zdecydujemy się sprawdzić hipotezę na olbrzymiej ilości danych. W takich przypadkach Athena sprawdza się idealnie. Dla regularnych zapytań taki system staje się drogi. W takim przypadku należy buforować dane w jakimś wyspecjalizowanym rozwiązaniu.
Serverless dla rozwiązań OLTP
W poprzednim przykładzie rozważano zadania OLAP (analityczne). Teraz omówimy zadania OLTP.
Przedstawmy skalowalny PostgreSQL lub MySQL. Podnieśmy standardową zarządzaną instancję PostgreSQL lub MySQL na minimalnych zasobach. Kiedy na instancję napływa większe obciążenie, dołączamy dodatkowe repliki, na które rozdzielamy część obciążenia odczytowego. Jeśli nie ma zapytań i obciążenia — wyłączamy repliki. Pierwsza instancja to master, a pozostałe to repliki.
Ta idea została zrealizowana w bazie o nazwie Aurora Serverless AWS. Zasada jest prosta: zapytania z zewnętrznych aplikacji przyjmuje zespół proxy. Widząc wzrost obciążenia, przydziela zasoby obliczeniowe z wstępnie uruchomionych minimalnych instancji — połączenie następuje maksymalnie szybko. Wyłączanie instancji odbywa się w ten sam sposób.
W ramach Aurory istnieje pojęcie Aurora Capacity Unit, ACU. To (umownie) instancja (serwer). Każde konkretne ACU może być master lub slave. Każda jednostka pojemności ma własną pamięć RAM, procesor i minimalny dysk. W związku z tym jedna instancja jest master, a pozostałe to repliki tylko do odczytu.
Liczba tych działających jednostek pojemności Aurora jest parametrem konfigurowalnym. Minimalna liczba może wynosić jeden lub zero (w takim przypadku baza nie działa, jeśli nie ma zapytań).

Gdy baza otrzymuje zapytania, zespół proxy podnosi jednostki pojemności Aurora, zwiększając zasoby wydajności systemu. Możliwość zwiększania i zmniejszania zasobów pozwala systemowi „żonglować” zasobami: automatycznie wyłączać poszczególne ACU (zastępując je nowymi) i wdrażać na wyłączone zasoby wszystkie aktualne aktualizacje.
Baza Aurora Serverless może skalować obciążenie odczytowe. Ale w dokumentacji nie jest to powiedziane wprost. Może powstać wrażenie, że mogą uruchamiać multi-master. Żadnego magicznego aspektu tu nie ma.
Ta baza dobrze nadaje się do unikania wydawania ogromnych pieniędzy na systemy z nieprzewidywalnym dostępem. Na przykład, przy tworzeniu MVP lub marketingowych stron wizytówkowych, zwykle nie spodziewamy się stabilnego obciążenia. W związku z tym, przy braku dostępu, nie płacimy za instancje. Gdy nagle pojawia się obciążenie, na przykład po konferencji lub kampanii reklamowej, tłumy ludzi odwiedzają stronę, a obciążenie gwałtownie rośnie, Aurora Serverless automatycznie przyjmuje to obciążenie i szybko uruchamia brakujące zasoby (ACU). Po zakończeniu konferencji wszyscy zapominają o prototypie, serwery (ACU) gasną, a wydatki spadają do zera — to wygodne.
To rozwiązanie nie nadaje się do stabilnego wysokiego obciążenia, ponieważ nie potrafi skalować obciążenia zapisu. Wszystkie te połączenia i odłączenia zasobów odbywają się w momencie tzw. „punktu skalowania” — momentu, w którym baza nie jest trzymana przez transakcję ani przez tymczasowe tabele. Na przykład, w ciągu tygodnia punkt skalowania może się nie zdarzyć, a baza działa na tych samych zasobach i po prostu nie może ani się rozbudować, ani skurczyć.
Nie ma magii — to zwykły PostgreSQL. Ale proces dodawania maszyn i odłączania jest częściowo zautomatyzowany.
Serverless by design
Aurora Serverless to stara baza, przepisana pod chmury, aby wykorzystać oddzielne zalety Serverless. A teraz opowiem o bazie, która została pierwotnie napisana pod chmury, w podejściu serverless — Serverless-by-design. Została od razu zaprojektowana bez założenia, że działa na fizycznych serwerach.
Ta baza nazywa się Snowflake. Ma trzy kluczowe bloki.

Pierwszy – to blok metadanych. To szybki serwis in-memory, który rozwiązuje kwestie związane z bezpieczeństwem, metadanymi, transakcjami, optymalizacją zapytań (na ilustracji po lewej).
Drugi blok – to wiele wirtualnych klastrów obliczeniowych do obliczeń (na ilustracji – zestaw niebieskich kółek).
Trzeci blok – to system przechowywania danych oparty na S3. S3 to bezwymiarowe obiektowe przechowywanie w AWS, coś w rodzaju bezwymiarowego Dropboxa dla biznesu.
Przyjrzyjmy się, jak działa Snowflake, zakładając zimny start. To znaczy, że baza istnieje, dane zostały załadowane, a zapytań nie ma. W związku z tym, jeśli nie ma zapytań do bazy, uruchomiony mamy szybki serwis Metadata w pamięci (pierwszy blok). A w naszym przypadku mamy również magazyn S3, w którym znajdują się dane tabel, podzielone na tzw. mikropartycje. Upraszczając: jeśli w tabeli znajdują się transakcje, to mikropartycje to dni transakcji. Każdy dzień to oddzielna mikropartycja, oddzielny plik. Gdy baza działa w takim trybie, płacisz tylko za miejsce zajmowane przez dane. Co więcej, stawka za miejsce jest bardzo niska (szczególnie biorąc pod uwagę znaczne kompresje). Serwis metadanych również działa cały czas, ale aby zoptymalizować zapytania, nie potrzebuje wielu zasobów, więc można uznać go za warunkowo bezpłatny.
Teraz wyobraźmy sobie, że użytkownik przyszedł do naszej bazy i złożył zapytanie SQL. Zapytanie SQL jest natychmiast kierowane do przetworzenia do serwisu Metadata. Odpowiednio, po otrzymaniu zapytania, ten serwis analizuje zapytanie, dostępne dane, uprawnienia użytkownika i, jeśli wszystko jest w porządku, tworzy plan przetwarzania zapytania.
Następnie serwis inicjuje uruchomienie klastra obliczeniowego. Klastr obliczeniowy to klaster serwerów, które przeprowadzają obliczenia. To znaczy, że klaster może zawierać 1 serwer, 2 serwery, 4, 8, 16, 32 — ile chcesz. Składasz zapytanie, a w jego odpowiedzi natychmiast rozpoczyna się uruchamianie tego klastra. To naprawdę zajmuje sekundy.

Następnie, po uruchomieniu klastra, mikropartycje potrzebne do przetworzenia Twojego zapytania są kopiowane z S3 do klastra. Oznacza to, że jeśli do wykonania zapytania SQL potrzebne są dwie partycje z jednej tabeli i jedna z drugiej, do klastra zostaną skopiowane tylko te trzy potrzebne partycje, a nie wszystkie tabele w całości. Dlatego, ponieważ wszystko znajduje się w ramach jednego centrum danych i jest połączone bardzo szybkimi kanałami, cały proces przesyłania danych odbywa się bardzo szybko: w ciągu sekund, rzadko w ciągu minut, chyba że mamy do czynienia z jakimiś niezwykle złożonymi zapytaniami. W związku z tym mikropartycje są kopiowane do klastra obliczeniowego, a po zakończeniu tego procesu zapytanie SQL jest wykonywane na tym klastrze. Wynikiem tego zapytania może być jeden wiersz, kilka wierszy lub tabela — są one następnie wysyłane do użytkownika, aby mógł je pobrać, wyświetlić w swoim narzędziu BI lub w inny sposób wykorzystać.
Każde zapytanie SQL może nie tylko obliczać agregaty z wcześniej załadowanych danych, ale także ładować/formować nowe dane w bazie. Oznacza to, że może to być zapytanie, które na przykład wstawia nowe rekordy do innej tabeli, co prowadzi do powstania nowej partycji w klastrze obliczeniowym, która z kolei automatycznie zostaje zapisana w jednolitym magazynie S3.
Opisany powyżej scenariusz, od momentu przybycia użytkownika do uruchomienia klastra, załadunku danych, wykonania zapytań i otrzymania wyników, jest naliczany według stawki za minuty korzystania z uruchomionego wirtualnego klastra obliczeniowego, wirtualnego magazynu. Stawka różni się w zależności od strefy AWS i rozmiaru klastra, ale średnio wynosi kilka dolarów za godzinę. Klaster składający się z czterech maszyn kosztuje dwa razy więcej niż klaster z dwóch maszyn, a klaster z ośmiu maszyn jeszcze dwa razy więcej. Dostępne są opcje z 16 lub 32 maszynami, w zależności od złożoności zapytań. Płacisz jednak tylko za te minuty, kiedy klaster rzeczywiście działa, ponieważ gdy zapytań nie ma, możesz jakby odczekać, a po 5-10 minutach oczekiwania (można to dostosować) klaster sam się wyłączy, zwalniając zasoby i stając się bezpłatnym.
Scenariusz, w którym składając zapytanie, klaster uruchamia się, mówiąc w skrócie, w ciągu minuty, przez kolejną minutę wykonuje obliczenia, a następnie przez pięć minut się wyłącza, a w rezultacie płacisz za siedem minut pracy tego klastra, a nie za miesiące czy lata.
Pierwszy scenariusz opisał użycie Snowflake w wariancie jednego użytkownika. Teraz wyobraźmy sobie, że użytkowników jest wielu, co już bardziej zbliża się do rzeczywistego scenariusza.
Przypuśćmy, że mamy wielu analityków i raporty Tableau, które nieustannie bombardują naszą bazę dużą ilością prostych analitycznych zapytań SQL.
Ponadto załóżmy, że mamy pomysłowych Data Scientistów, którzy próbują robić z danymi rzeczy niezwykłe, operując dziesiątkami terabajtów, analizując miliardy i tryliony wierszy danych.
Dla opisanych powyżej dwóch typów obciążenia Snowflake umożliwia uruchamianie kilku niezależnych klastrów obliczeniowych o różnej mocy. Te klastry obliczeniowe działają niezależnie, ale na wspólnych, zgody danych.
Dla dużej liczby lekkich zapytań można uruchomić 2-3 małe klastry, na przykład po 2 maszyny każdy. To zachowanie można wdrożyć również za pomocą automatycznych ustawień. Mówiąc: „Snowflake, uruchom mały klaster. Jeśli obciążenie wzrośnie ponad określony parametr, uruchom analogiczny drugi, trzeci. Kiedy obciążenie zacznie maleć — zgaś zbędne”. Dzięki temu niezależnie od tego, ile analityków przychodzi i zaczyna przeglądać raporty, wszystkim wystarczy zasobów.
Jednocześnie, jeśli analitycy śpią, a nikt nie przegląda raportów — klastry mogą całkowicie się wyłączyć, a Ty przestajesz za nie płacić.
Jednak w przypadku cięższych zapytań (od Data Scientistów) możesz uruchomić jeden bardzo duży klaster na przykład 32 maszyn. Ten klaster również będzie opłacany tylko za te minuty i godziny, kiedy działa Twoje ogromne zapytanie.
Opisana powyżej możliwość pozwala dzielić obciążenia na klastry nie tylko dla 2, ale i dla więcej rodzajów obciążenia (ETL, monitorowanie, materializacja raportów,…).
Podsumujmy Snowflake. Baza łączy piękną ideę z funkcjonalną realizacją. W ManyChat używamy Snowflake do analizy wszystkich dostępnych danych. Mamy nie trzy klastry, jak w przykładzie, a od 5 do 9, w różnych rozmiarach. Posiadamy klastrowe maszyny 16-rdzeniowe, 2-rdzeniowe, a także super małe 1-rdzeniowe do niektórych zadań. One efektywnie rozdzielają obciążenie i pozwalają nam zaoszczędzić.
Baza skutecznie skalowalna jest na obciążeniach odczytu i zapisu. To ogromna różnica i znaczący przełom w porównaniu do 'Aurory', która obsługiwała tylko obciążenie odczytu. Snowflake umożliwia skalowanie tych obciążeń obliczeniowymi klastrami, w tym zapisu. Jak wspomniałem, w ManyChat używamy kilku klastrów, a małe i super małe klastry najczęściej wykorzystywane są do ETL, do ładowania danych. Analitycy pracują z kolei na średnich klastrach, które są całkowicie niezagrożone obciążeniem ETL, dlatego działają bardzo szybko.
Odpowiednio, baza dobrze nadaje się do zadań OLAP. Niestety, nie nadaje się jeszcze do obciążeń OLTP. Po pierwsze, ta baza jest kolumnowa, co pociąga za sobą odpowiednie konsekwencje. Po drugie, sama koncepcja, w której na każde zapytanie odpowiednio uruchamiasz obliczeniowy klaster i obciążasz go danymi, niestety, dla obciążeń OLTP jest jeszcze niewystarczająco szybka. Sekundy oczekiwania w przypadku zadań OLAP są akceptowalne, ale w przypadku obciążeń OLTP są niedopuszczalne; lepiej byłoby w 100 ms, a jeszcze lepiej — w 10 ms.
Podsumowanie
Baza danych bezserwerowa możliwa jest dzięki podziałowi bazy danych na części Stateless i Stateful. Z pewnością zauważyłeś, że we wszystkich podanych przykładach część Stateful — to, powiedzmy, przechowywanie mikropartycji w S3, a Stateless — to optymalizator, praca z metadanymi, przetwarzanie kwestii bezpieczeństwa, które mogą być uruchomione jako niezależne, lekkie usługi Stateless.
Wykonywanie zapytań SQL można również postrzegać jako usługi z lekkim stanem, które mogą działać w trybie bezserwerowym, jak obliczeniowe klastry Snowflake, pobierać tylko potrzebne dane, wykonywać zapytanie i 'wygaszać'.
Bazy danych bezserwerowych poziomu produkcyjnego są już dostępne i działają. Te bazy bezserwerowe są gotowe do radzenia sobie z zadaniami OLAP. Niestety, w przypadku zadań OLTP stosowane są... z pewnymi zastrzeżeniami, ponieważ istnieją ograniczenia. Z jednej strony jest to wada. Z drugiej strony to szansa. Może ktoś z czytelników znajdzie sposób, aby baza OLTP stała się całkowicie bezserwerowa, bez ograniczeń Aurora.
Mam nadzieję, że to było interesujące. Za bezserwerową przyszłość 🙂
Źródło: habr.com
