Zdalne zagęszczanie w RocksDB-Cloud

(Hieu Pham) (10 czerwca , 2020)

Wprowadzenie

RocksDB to silnik pamięci masowej LSM, którego wzrost ogromnie się rozprzestrzenił w ciągu ostatnich kilku lat . RocksDB-Cloud jest open-source i jest w pełni kompatybilny z RocksDB, z dodatkową funkcją polegającą na tym, że wszystkie dane są trwałe dzięki automatycznemu przechowywaniu ich w chmurze (np. Amazon S3).

My w Rockset używamy RocksDB-Cloud jako jeden z elementów składowych rozproszonego indeksu konwergentnego firmy Rockset . Rockset został zaprojektowany zgodnie z zasadami natywnymi dla chmury, a jedną z głównych zasad projektowania bazy danych natywnej dla chmury jest oddzielenie mocy obliczeniowej od pamięci masowej. Omówimy, w jaki sposób rozszerzyliśmy usługę RocksDB-Cloud, aby dokładnie oddzielić jej potrzeby w zakresie pamięci masowej od potrzeb obliczeniowych.

Kompaktor, obsługiwany przez US Navy Seabees, zagęszczający glebę

Silnik LSM firmy RocksDB

RocksDB-Cloud przechowuje dane na lokalnie podłączonych dyskach SSD lub dyskach obrotowych. Dysk SSD lub obracający się dysk zapewnia miejsce do przechowywania danych, które obsługuje. Nowe zapisy do RocksDB-Cloud są zapisywane do pamięci w pamięci, a następnie, gdy jest on zapełniony, jest przesyłany do nowego pliku SST w magazynie.

Będąc silnikiem pamięci LSM, zestaw wątków w tle jest używanych do kompaktowania, a kompaktowanie to proces łączenia zestawu plików SST i generowania nowych plików SST z nadpisanymi kluczami i usuniętymi kluczami wyczyszczonymi z plików wyjściowych. Kompresja wymaga dużej ilości zasobów obliczeniowych. Im wyższa szybkość zapisu do bazy danych, tym więcej zasobów obliczeniowych jest potrzebnych do kompaktowania, ponieważ system jest stabilny tylko wtedy, gdy kompresja jest w stanie nadążyć za nowymi zapisami w bazie danych.

Problem, gdy moc obliczeniowa i pamięć nie są rozdzielone

W typowym W systemie opartym na RocksDB zagęszczanie odbywa się na procesorach lokalnych na serwerze, na którym znajduje się również pamięć masowa. W takim przypadku obliczenia i magazyn nie są zdezagregowane. A to oznacza, że ​​jeśli szybkość zapisu wzrośnie, ale całkowity rozmiar bazy danych pozostanie taki sam, będziesz musiał dynamicznie udostępniać więcej serwerów, rozłożyć dane na wszystkie te serwery, a następnie wykorzystać dodatkowe moce obliczeniowe na tych serwerach, aby nadążyć za obciążenie kompresji.

To ma dwa problemy:

  • Rozpowszechnianie danych na większej liczbie serwerów nie jest natychmiastowe, ponieważ musisz skopiować dużo danych, aby to zrobić. Oznacza to, że nie możesz szybko reagować na szybko zmieniające się obciążenie.
  • Wykorzystanie pojemności pamięci masowej na każdym z serwerów staje się bardzo niskie, ponieważ dane są rozmieszczane na większej liczbie serwerów. Tracisz stosunek ceny do wydajności z powodu całej nieużywanej pamięci masowej na Twoich serwerach.

Nasze rozwiązanie

Główny powód, dla którego RocksDB-Cloud jest odpowiedni oddzielenie mocy obliczeniowej i magazynu do zagęszczania wynika z tego, że jest to silnik magazynujący LSM. W przeciwieństwie do bazy danych B-Tree, RocksDB-Cloud nigdy nie aktualizuje pliku SST po jego utworzeniu. Oznacza to, że wszystkie pliki SST w całym systemie są przeznaczone tylko do odczytu, z wyjątkiem znikomej części danych w aktywnym pliku pamięci. RocksDB-Cloud zachowuje wszystkie pliki SST w magazynie obiektów w chmurze, takim jak S3, a te obiekty w chmurze są bezpiecznie dostępne ze wszystkich serwerów, ponieważ są tylko do odczytu.

Nasz pomysł jest taki, że jeśli RocksDB -Serwer w chmurze A może hermetyzować zadanie kompaktowania za pomocą zestawu obiektów w chmurze, a następnie wysłać żądanie do zdalnego serwera bezstanowego B- i ten serwer B może pobrać odpowiednie obiekty z magazynu w chmurze, wykonać kompaktowanie, wygenerować zestaw danych wyjściowych Pliki SST, które są zapisywane z powrotem w magazynie obiektów w chmurze, a następnie przekazują te informacje z powrotem do serwera A – zasadniczo oddzieliliśmy pamięć (która znajduje się na serwerze A) od obliczeń kompaktowania (znajdującego się na serwerze B). Serwer A ma magazyn, a serwer B nie ma stałego magazynu, a jedynie moc obliczeniową potrzebną do kompaktowania. Voila!

Podłączany interfejs API do zagęszczania RocksDB

Rozszerzyliśmy podstawowe API RocksDB o dwie nowe metody, dzięki którym silnik zagęszczania w RocksDB jest podłączany zewnętrznie. W db.h wprowadzamy nowe API do rejestracji usługi kompaktowania.

Status RegisterPluggableCompactionService(std::unique_ptr);

To API rejestruje wtyczkę, która jest używana do wykonywania zadania kompaktowania przez RocksDB. Zdalne kompaktowanie przebiega w dwóch etapach: Run i InstallFiles. Dlatego wtyczka PluggableCompactionService miałaby 2 interfejsy API:

Status Run(const PluggableCompactionParam& job, PluggableCompactionResult* result) std::vector InstallFiles(
const std::vector& remote_paths,
const std::vector& local_paths,
const EnvOptions& env_options, Env* local_env)

Run to miejsce, w którym odbywa się kompaktowanie.W naszej architekturze zdalnego kompaktowania Run wyśle ​​RPC do zdalnego poziomu kompaktowania i otrzyma wynik kompaktowania, który zawiera między innymi listę nowo skompaktowanych plików SST.

InstallFiles to miejsce, w którym RocksDB instaluje nowo skompaktowane pliki SST z chmury (remote_paths) do swojej lokalnej bazy danych (local_paths).

Poziom zagęszczania Rockset

Teraz pokażemy, jak korzystaliśmy z podłączanej usługi zagęszczania opisanej powyżej w usłudze kompaktowania Rockset. Jak wspomniano powyżej, pierwszy krok, Run, wysyła RPC do warstwy zdalnego kompaktowania z informacjami o kompaktowaniu, takimi jak nazwy wejściowych plików SST i informacje o kompresji. Nazywamy hosta, który wykonuje to zadanie kompaktowania, kompaktorem.

kompaktor , po otrzymaniu żądania kompaktowania, otworzyłby instancję RocksDB-Cloud w tryb ducha . Oznacza to, że RocksDB-Cloud otwiera lokalną bazę danych tylko z niezbędnymi metadanymi bez pobierania wszystkich plików SST z chmury. Po otwarciu instancji RocksDB w trybie ducha , wykonywałoby wówczas zadanie kompaktowania, w tym pobieranie wymaganych plików SST, kompaktowanie ich i przesyłanie nowo skompaktowanych plików SST do tymczasowego magazynu w chmurze.

Oto opcje otwierania RocksDB-Cloud w kompaktorze :

rocksdb::CloudOptions cloud_options; cloud_options.ephemeral_resync_on_open = false; cloud_options.constant_sst_file_size_in_sst_file_manager = 1024; cloud_options.skip_cloud_files_in_getchildren = true;rocksdb::Options rocksdb_options;
rocksdb_options.max_open_files = 0; rocksdb_options.disable_auto_compactions = true; rocksdb_options.skip_stats_update_on_db_open = true; rocksdb_options.paranoid_checks = false; rocksdb_options.compaction_readahead_size = 10 * 1024 * 1024;

Istnieje wiele wyzwań napotkaliśmy podczas opracowywania warstwy zagęszczania i naszych rozwiązań:

Popraw prędkość otwierania RocksDB-Cloud w duchu tryb

Podczas otwierania instancji RocksDB, oprócz pobrania wszystkich plików SST z chmury (które wyłączyliśmy za pomocą ghost mode), istnieje wiele innych operacji, które mogą spowolnić proces otwierania, w szczególności pobieranie listy plików SST i uzyskiwanie rozmiaru każdego pliku SST. Zwykle, jeśli wszystkie pliki SST znajdują się w pamięci lokalnej, opóźnienie tych operacji pobierania rozmiaru pliku byłoby niewielkie. Jednak gdy kompaktor otwiera RocksDB-Cloud, każda z tych operacji skutkowałaby zdalnym żądaniem do pamięci masowej w chmurze, a łączne opóźnienie stało się zbyt drogie. Z naszego doświadczenia wynika, że ​​w przypadku instancji RocksDB-Cloud z tysiącami plików SST otwarcie jej zajęłoby nawet minutę ze względu na tysiące żądań pobrania rozmiaru pliku do S3. Aby obejść to ograniczenie, wprowadziliśmy różne opcje w opcjach RocksDB-Cloud, aby wyłączyć te RPC podczas otwierania. W rezultacie średni czas otwierania wynosi od 7 sekund do 700 milisekund.

Wyłącz kompaktowanie L0 -> L0

Zdalne zagęszczanie to kompromis między szybkością pojedynczego zagęszczania a możliwością równoległego wykonywania większej liczby zadań zagęszczania. Dzieje się tak dlatego, że każde zdalne zadanie zagęszczania byłoby wolniejsze niż to samo zagęszczanie wykonywane lokalnie ze względu na koszt przesyłania danych w chmurze. Dlatego chcielibyśmy zminimalizować wąskie gardło procesu zagęszczania, w którym RocksDB-Cloud nie może zrównoleglać, tak bardzo, jak to możliwe.

W architekturze LSM zagęszczanie L0-> L1 zwykle nie jest równoległe, ponieważ Pliki L0 mają nakładające się zakresy. W związku z tym, gdy występuje zagęszczanie L0-> L1, RocksDB-Cloud ma również możliwość wykonywania kompresji L0-> L0, w celu zmniejszenia liczby plików L0 i zapobiegania blokadom zapisu spowodowanym uderzeniem RocksDB-Cloud w plik L0. limit. Jednak kompromis jest taki, że każdy plik L0 powiększałby się po każdym kompresji L0-> L0.

Z naszego doświadczenia wynika, że ​​ta opcja powoduje więcej problemów niż przynosi korzyści, ponieważ posiadanie większych plików L0 powoduje znacznie dłuższe zagęszczenie L0-> L1, pogarszając wąskie gardło RocksDB-Cloud. Dlatego wyłączamy kompresję L0-> L0 i zamiast tego żyjemy z rzadkim problemem związanym z przeciąganiem zapisu. Z naszego eksperymentu wynika, że ​​kompresja RocksDB-Cloud znacznie lepiej dogania przychodzące zapisy.

Możesz go teraz używać

RocksDB-Cloud jest projektem open source, więc nasza praca może być wykorzystywane przez każdego innego programistę RocksDB, który chce czerpać korzyści z oddzielenia ich obliczeń kompaktowania od potrzeb związanych z pamięcią masową. Obecnie prowadzimy usługę zdalnego zagęszczania w produkcji. Jest dostępny w wersji 6.7.3 RocksDB-Cloud. Omawiamy wszystko o RocksDB-Cloud na publicznym kanale Slack pod adresem http://bit.ly/rockset-community-channel .

Autorzy:

Hieu Pham – inżynier oprogramowania, Rockset
Dhruba Borthakur – CTO, Rockset

Pierwotnie opublikowane pod adresem https: // rockset.com 4 czerwca 2020 r.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *