Compacties op afstand in RocksDB-Cloud

(Hieu Pham) (10 juni) , 2020)

Introductie

RocksDB is een LSM-opslagmotor waarvan de groei de afgelopen jaren enorm is toegenomen . RocksDB-Cloud is open-source en is volledig compatibel met RocksDB, met als bijkomend kenmerk dat alle gegevens duurzaam worden gemaakt door ze automatisch op te slaan in cloudopslag (bijvoorbeeld Amazon S3).

Bij Rockset gebruiken we RocksDB-Cloud als een van de bouwstenen van Rocksets gedistribueerde Converged Index . Rockset is ontworpen met cloud-native principes, en een van de primaire ontwerpprincipes van een cloud-native database is om compute en opslag te scheiden. We zullen bespreken hoe we RocksDB-Cloud hebben uitgebreid om een ​​duidelijke scheiding te hebben tussen de opslagbehoeften en de rekenbehoeften.

Een compactor, bediend door US Navy Seabees, die bodemverdichting uitvoert

RocksDBs LSM-motor

RocksDB-Cloud slaat gegevens op in lokaal aangesloten SSD of draaiende schijven. De SSD of de draaiende schijf biedt de opslag die nodig is om de gegevens op te slaan. Nieuwe schrijfbewerkingen naar RocksDB-Cloud worden naar een in-memory memtable geschreven, en als de memtable vol is, wordt deze naar een nieuw SST-bestand in de opslag gespoeld.

Omdat het een LSM-opslagengine is, een set van achtergrondthreads worden gebruikt voor verdichting, en verdichting is een proces van het combineren van een set SST-bestanden en het genereren van nieuwe SST-bestanden met overschreven sleutels en verwijderde sleutels die uit de uitvoerbestanden worden verwijderd. Verdichting heeft veel rekenbronnen nodig. Hoe hoger de schrijfsnelheid in de database, des te meer rekenbronnen zijn er nodig voor het comprimeren, omdat het systeem alleen stabiel is als het comprimeren in staat is om nieuwe schrijfbewerkingen naar uw database bij te houden.

Het probleem wanneer rekenkracht en opslag niet zijn uitgesplitst

In een typische RocksDB-gebaseerd systeem, compactie vindt plaats op CPUs die lokaal zijn op de server die ook de opslag host. In dit geval worden rekenkracht en opslag niet uitgesplitst. En dit betekent dat als uw schrijfsnelheid toeneemt maar de totale grootte van uw database hetzelfde blijft, u dynamisch meer servers zou moeten voorzien, uw gegevens over al die servers zou moeten verspreiden en vervolgens de extra rekenkracht op deze servers zou moeten gebruiken om de verdichtingsbelasting.

Dit heeft twee problemen:

  • Het verspreiden van uw gegevens naar meer servers is niet onmiddellijk omdat u daarvoor veel gegevens moet kopiëren. Dit betekent dat u niet snel kunt reageren op een snel veranderende werklast.
  • Het gebruik van de opslagcapaciteit op elk van uw servers wordt erg laag omdat u uw gegevens over meer servers verspreidt. U verliest de prijs-prestatieverhouding door alle ongebruikte opslag op uw servers.

Onze oplossing

De belangrijkste reden waarom RocksDB-Cloud geschikt is voor het scheiden van compute compute en opslag is omdat het een LSM opslag engine is. In tegenstelling tot een B-Tree-database, werkt RocksDB-Cloud nooit een SST-bestand bij nadat het is gemaakt. Dit betekent dat alle SST-bestanden in het hele systeem alleen-lezen zijn, behalve het minuscule deel van de gegevens in uw actieve memtable. RocksDB-Cloud bewaart alle SST-bestanden in een cloudopslagobjectopslag zoals S3, en deze cloudobjecten zijn veilig toegankelijk vanaf al uw servers omdat ze alleen-lezen zijn.

Dus ons idee is dat als een RocksDB -Cloud-server A kan een comprimeringstaak met zijn set cloud-objecten inkapselen en vervolgens het verzoek naar een externe stateless server B sturen-en die server B kan de relevante objecten uit de cloudopslag halen, het comprimeren doen, een set output produceren SST-bestanden die worden teruggeschreven naar de cloud-objectopslag en die informatie vervolgens terugzenden naar server A – we hebben in wezen de opslag (die zich op server A bevindt) gescheiden van de comprimeringsberekening (die zich op server B bevindt). Server A heeft de opslag en terwijl server B geen permanente opslag heeft, maar alleen de rekenkracht die nodig is voor verdichting. Voila!

RocksDB pluggable compaction API

We hebben de basis RocksDB API uitgebreid met twee nieuwe methoden die de verdichtingsmotor in RocksDB extern pluggable maken. In db.h introduceren we een nieuwe API om een ​​verdichtingsservice te registreren.

Status RegisterPluggableCompactionService(std::unique_ptr);

Deze API registreert de plug-in die wordt gebruikt om de verdichtingsopdracht door RocksDB uit te voeren. Op afstand comprimeren gebeurt in twee stappen: Run en InstallFiles. Daarom zou de plug-in, PluggableCompactionService , 2 APIs hebben:

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 is waar het comprimeren plaatsvindt.In onze architectuur voor compacteren op afstand zou Run een RPC naar een laag comprimeren op afstand sturen en een compactieresultaat ontvangen dat onder andere de lijst met nieuw gecomprimeerde SST-bestanden bevat.

InstallFiles is waar RocksDB de nieuw gecomprimeerde SST-bestanden uit de cloud (remote_paths) installeert naar zijn lokale database (local_paths).

Rocksets verdichtingslaag

Nu zullen we laten zien hoe we de pluggable verdichtingsservice hebben gebruikt die hierboven is beschreven in de Rockset-verdichtingsservice. Zoals hierboven vermeld, verzendt de eerste stap, Run, een RPC naar een verdichtingslaag op afstand met verdichtingsinformatie zoals ingevoerde SST-bestandsnamen en compressie-informatie. We noemen de host die deze verdichtingsopdracht uitvoert een compactor.

De verdichter zou bij ontvangst van het verdichtingsverzoek een RocksDB-Cloud-instantie openen in geest -modus. Dit betekent dat RocksDB-Cloud de lokale database opent met alleen de noodzakelijke metadata zonder alle SST-bestanden uit de cloudopslag te halen. Zodra het de RocksDB-instantie in ghost -modus opent, voert het de comprimeringstaak uit, inclusief het ophalen van de vereiste SST-bestanden, comprimeert ze en uploadt de nieuw gecomprimeerde SST-bestanden naar een tijdelijke opslag in de cloud.

Hier zijn de opties om RocksDB-Cloud te openen in de compactor :

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;

Er zijn meerdere uitdagingen waarmee we te maken kregen tijdens de ontwikkeling van de verdichtingslaag en onze oplossingen:

Verbeter de snelheid van het openen van RocksDB-Cloud in geest mode

Tijdens het openen van een RocksDB-instantie, naast het ophalen van alle SST-bestanden uit de cloud (die we hebben uitgeschakeld met ghost -modus), zijn er meerdere andere bewerkingen die het openingsproces kunnen vertragen, met name het ophalen van de lijst met SST-bestanden en het verkrijgen van de grootte van elk SST-bestand. Als alle SST-bestanden zich in de lokale opslag bevinden, zou de latentie van deze bewerkingen met get-file-size normaal gesproken klein zijn. Wanneer de compactor RocksDB-Cloud echter opent, zou elk van deze bewerkingen resulteren in een extern verzoek aan de cloudopslag en wordt de totale gecombineerde latentie onbetaalbaar. In onze ervaring zou het openen van een RocksDB-Cloud-instantie met duizenden SST-bestanden tot een minuut duren vanwege duizenden verzoeken om bestandsgrootte aan S3. Om deze beperking te omzeilen, hebben we verschillende opties in de RocksDB-Cloud-opties geïntroduceerd om deze RPCs tijdens het openen uit te schakelen. Als gevolg hiervan gaat de gemiddelde openingstijd van 7 seconden tot 700 milliseconden.

Schakel L0 uit -> L0-verdichting

Verdichting op afstand is een afweging tussen de snelheid van een enkele verdichting en de mogelijkheid om meer verdichtingsopdrachten parallel uit te voeren. Dit komt doordat elke verdichtingstaak op afstand natuurlijk langzamer zou zijn dan dezelfde verdichting die lokaal wordt uitgevoerd vanwege de kosten van gegevensoverdracht in de cloud. Daarom willen we de bottleneck van het verdichtingsproces, waar RocksDB-Cloud niet kan parallelliseren, zoveel mogelijk minimaliseren.

In de LSM-architectuur is L0-> L1-verdichting meestal niet parallelliseerbaar omdat L0-bestanden hebben overlappende bereiken. Dus wanneer een L0-> L1-verdichting plaatsvindt, heeft RocksDB-Cloud de mogelijkheid om ook L0-> L0-verdichting uit te voeren, met als doel het aantal L0-bestanden te verminderen en schrijfblokkades te voorkomen doordat RocksDB-Cloud het L0-bestand raakt begrenzing. De wisselwerking is echter dat elk L0-bestand groter wordt na elke L0-> L0-verdichting.

In onze ervaring veroorzaakt deze optie meer problemen dan de voordelen die het met zich meebrengt, omdat het hebben van grotere L0-bestanden resulteert in een veel langere L0-> L1 verdichting, waardoor het knelpunt van RocksDB-Cloud verergert. Daarom schakelen we L0-> L0-verdichting uit en leven we met het zeldzame probleem van schrijfblokkering. Uit ons experiment haalt RocksDB-Cloud-verdichting de inkomende schrijfbewerkingen veel beter in.

Je kunt het nu gebruiken

RocksDB-Cloud is een open-sourceproject, dus ons werk kan worden benut door elke andere RocksDB-ontwikkelaar die voordelen wil behalen door hun compacteringsberekening te scheiden van hun opslagbehoeften. We voeren nu de service voor verdichting op afstand in productie. Het is beschikbaar met de 6.7.3-release van RocksDB-Cloud. We bespreken alle dingen over RocksDB-Cloud in het openbare Slack-kanaal op http://bit.ly/rockset-community-channel .

Auteurs:

Hieu Pham – Software Engineer, Rockset
Dhruba Borthakur – CTO, Rockset

Oorspronkelijk gepubliceerd op https: // rockset.com op 4 juni 2020.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *