{"id":91090,"date":"2020-08-08T13:42:11","date_gmt":"2020-08-08T11:42:11","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage"},"modified":"2020-08-08T13:42:11","modified_gmt":"2020-08-08T11:42:11","slug":"arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage","status":"publish","type":"post","link":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage","title":{"rendered":"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/a53775776b3fc969cc15c9d13a64039d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em><noindex><a rel=\"nofollow\" href=\"https:\/\/www.deviantart.com\/st-pete\/art\/Storage-Corridor-408874509\">Lagerkorridor<\/a><\/noindex> ved St-Petersburg<\/em><\/p>\n<p><\/p>\n<p>Hej alle sammen! Jeg er Mons Anderson, platformarkitekt <noindex><a rel=\"nofollow\" href=\"https:\/\/mcs.mail.ru\/\">Mail.ru Cloud Solutions<\/a><\/noindex>, og jeg vil fort\u00e6lle, hvordan vi byggede vores S3-lager, hvordan det fungerer, hvilke l\u00f8sninger der var vellykkede, og hvilke vi ville \u00e6ndre, hvis vi skulle starte et s\u00e5dant projekt fra bunden nu.<\/p>\n<p><\/p>\n<p>Artiklen er baseret p\u00e5 et foredrag ved <noindex><a rel=\"nofollow\" href=\"https:\/\/corp.mail.ru\/ru\/press\/events\/databases-2\/\">@Databases Meetup<\/a><\/noindex> af Mail.ru Cloud Solutions &amp; Tarantool. I artiklen vil vi tale om:<\/p>\n<p><\/p>\n<ul>\n<li>hvordan Mail.ru-lageret var opbygget, som vi byggede vores S3-lager oven p\u00e5;<\/li>\n<li>hvad vi tilf\u00f8jede for at skabe Mail.ru Cloud Storage;<\/li>\n<li>hvordan objektlagermodellen fungerer, og hvilke skridt der er taget for at komme i produktion;<\/li>\n<li>om forbedringer af det aktive system: failover og skalering;<\/li>\n<li>hvordan vi implementerede sharding og re-sharding;<\/li>\n<li>samt om arbejdet med SSL-certifikater.<\/li>\n<\/ul>\n<p><\/p>\n<p>Hvis du ikke \u00f8nsker at l\u00e6se, kan du <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/NEgm1nsv-qg\">se<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"kak-bylo-ustroeno-hranilische-mailru-poverh-kotorogo-my-stroili-s3-hranilische\">Hvordan Mail.ru-lageret var opbygget, som vi byggede vores S3-lager oven p\u00e5<\/h2>\n<p><\/p>\n<p>Udviklingen af vores S3 begyndte oven p\u00e5 Mail.ru Cloud-lageret, s\u00e5 det er vigtigt f\u00f8rst at fort\u00e6lle, hvordan det er opbygget, og hvad det kan.<\/p>\n<p><\/p>\n<p>Mail.ru Cloud-lageret best\u00e5r af servere med diske. I gennemsnit er en moderne storage-server 36 diske \u00e1 12\u201314 terabyte. Tidligere var diskene mindre, men over de sidste tre \u00e5r er diskst\u00f8rrelserne vokset, og i dag er det n\u00e6sten en halv petabyte r\u00e5 data. <\/p>\n<p><\/p>\n<p>Diskene fra forskellige lager-servere samles i s\u00e5kaldte \u2018par\u2019. Et par er en enkelt enhed til opbevaring af filer. Det er i bund og grund en disk, der er monteret i et bestemt partition p\u00e5 en bestemt sti, hvor filer, der er identifikation via hashes, kan opbevares. <\/p>\n<p><\/p>\n<p>Par er et historisk navn, som er bevaret til i dag, selvom der i et par ikke n\u00f8dvendigvis kun skal v\u00e6re to diske. Der kan v\u00e6re tre diske, og der kan ogs\u00e5 v\u00e6re forskellige hybridlagringsformer, eksempelvis 3\/2. <\/p>\n<p>\n<img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/544ab79846539262e2d4dff6ab95ffff.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Par (pair) \u2014 enheder til opbevaring af objekter<\/em><\/p>\n<p><\/p>\n<p>Alle par gemmes i PairDB \u2014 en applikation baseret p\u00e5 Tarantool. Alle databaser i vores lager, fra de allerf\u00f8rste, er Tarantool, vi bruger ikke andre databaser.<\/p>\n<p><\/p>\n<p>PairDB gemmer alle par, deres tilstande, ledig plads, fejlmuligheder, seneste fejl. Den kan ogs\u00e5 selv tilg\u00e5 parene, opdatere deres tilstand, kontrollere, om de fungerer eller ej. S\u00e5 PairDB er et samlet \u00f8jebliksbillede af tilstanden for alle diske i vores system.<\/p>\n<p>\n<img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/d50781b8b51ed5fe126bc84e19c934d1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Pair DB: en database med tilstanden for par<\/em><\/p>\n<p><\/p>\n<p>Parterne gemmer filer, og for at vide, hvilke filer der er p\u00e5 hvilken par, er der brug for endnu en database - FileDB. Den gemmer mapping, hvilket definerer forholdet: filen s\u00e5dan og s\u00e5dan opbevares p\u00e5 par s\u00e5dan og s\u00e5dan, samt et lille antal n\u00f8dvendige attributter.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/b1a64737cf7f916bff446c10c1f01d4c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><em>File DB: stedet, hvor filen opbevares<\/em><\/p>\n<p>Et andet vigtigt element er service Nylon, en router til arbejde med databaser. Den fungerer som et enkelt punkt for adgang og tillader brug af et enhedligt interface til b\u00e5de PairDB og FileDB. Det er en stateless-service, den foretager belastningsbalancering af foresp\u00f8rgsler, forst\u00e5r hvilken shard FileDB der skal tilg\u00e5s, og ved, hvilke par der er aktive, og hvilke der ikke er.<\/p>\n<p>\n<img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/3e2225f229c8cfa462d620d2b5fb581e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Nylon: router til arbejde med databaser<\/em><\/p>\n<p><\/p>\n<p>Det er ogs\u00e5 n\u00f8dvendigt at placere indhold i lageret. For dette form\u00e5l findes der en service - Streamer. Den tilbyder to HTTP-metoder: PUT-metoden til at uploade indhold til lageret og GET-metoden til at hente det derfra. HTTP er et ret popul\u00e6rt og bekvemt protokol til dataoverf\u00f8rsel. <\/p>\n<p><\/p>\n<p>N\u00e5r vi henvender os til Streamer&#8217;y, kontakter den via Nylon PairDB for at finde ud af, hvilken par der kan modtage filen, hvorefter den sender data via WebDAV til denne par. <\/p>\n<p><\/p>\n<p>I bund og grund er enhver storage-server nginx plus diske, som er monteret p\u00e5 de angivne stier. Vi kan fra Streamer uploade en fil til lageret, slette den, omd\u00f8be den eller kontrollere dens integritet. Det er med andre ord et praktisk interface til lavtliggende interaktion med lageret. <\/p>\n<p>\n<img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/3722a89ed44cace36e9cb1f8bee4bd1e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Streamer: indgangspunkt til lageret<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-my-dobavili-chtoby-sdelat-s3-hranilische\">Hvad vi har tilf\u00f8jet for at skabe S3-lageret<\/h2>\n<p><\/p>\n<p>S\u00e5 vi har set p\u00e5 den grundl\u00e6ggende opbygning af lageret p\u00e5 det tidspunkt, vi planlagde at lancere S3-lageret. Ved hj\u00e6lp af PUT-metoden kunne vi placere vilk\u00e5rligt indhold d\u00e9r og modtage en hash som identifikator for disse data. Med denne identifikator kunne man senere komme og hente den originale fil. Men det er ikke tilstr\u00e6kkeligt til at implementere S3. I S3-protokollen, ud over selve opbevaringen af objekter, er der:<\/p>\n<p><\/p>\n<ul>\n<li>opbevaring af metadata - yderligere egenskaber for objekterne;<\/li>\n<li>organisering af adgang til objekterne via HTTP;<\/li>\n<li>gruppering af objekterne i samlinger - buckets;<\/li>\n<li>HTTP-S3 Endpoint. S3 organiserer data i bestemte strukturer - buckets, som hver is\u00e6r giver et indgangspunkt for opbevaring af filer.<\/li>\n<\/ul>\n<p><\/p>\n<p>For this logic to be implemented, a separate service was required. We also wanted to plan the architecture for the future growth of the service with linear scalability.<\/p>\n<p><\/p>\n<h2 id=\"pervye-komponenty\">The first components<\/h2>\n<p><\/p>\n<p>The daemon implementing the S3 API. This is the standard Amazon S3 API, which supports XML operations for metadata and allows direct content transfer. We didn't have to invent anything; everything is described and documented.<\/p>\n<p><\/p>\n<p>We also placed Nginx in front of the service. We used it for SSL termination, load balancing, and some logic in Lua (metrics, logging, and tracing).<\/p>\n<p><\/p>\n<p>For storing S3 metadata, we chose Tarantool. In the first version, the S3 daemon accessed this database for metadata, while the content was stored in a large storage through Streamer.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/03dddec282b5bb41eb63748ccfb6c9a4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>Nginx + S3 API + metadata<\/em><\/p>\n<p><\/p>\n<h2 id=\"obektnaya-model-hraneniya\">Object storage model<\/h2>\n<p><\/p>\n<p>Let\u2019s see how S3 works. A user can create a bucket \u2014 a collection of objects. A bucket is addressed by a hostname and is a subdomain of the service. Within a bucket, a user can create objects. The object identifier will be a URL. The content of the object is a blob, an array of binary data that we will store in the storage. The object also has attributes: the name \u2014 which is that URL, ACL (access control list), and other additional or custom attributes \u2014 all this is stored in metadata. <\/p>\n<p><\/p>\n<p>The normalized schema of this data might look like this: there are projects that own buckets, which own objects, and objects can be composite. Since one way to upload an object is by parts, there are two auxiliary tables for uploads and chunks. Projects also have credentials for access and billing. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/e2bede45ba4044f658b47a9840fd5224.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>Data schema<\/em><\/p>\n<p><\/p>\n<p>Since we were creating a B2B service with paid access, billing was necessary in this schema.<br \/>\nWe also implemented the billing service on Tarantool. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/d5b1a63e2273e933c95deecdb054bfe6.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h2 id=\"dorabotki-s3-hranilischa-shagi-k-prodakshenu\">Improvements to the S3 storage: steps to production<\/h2>\n<p><\/p>\n<p>We have already created a working model that can be used: objects and metadata were stored, but a few aspects were missing for going into production.<\/p>\n<p><\/p>\n<p>For det f\u00f8rste er der systemet med rate-limits. Hvis man k\u00f8rer tjenesten uden det, kan vi uforudsigeligt overbelaste et hvilket som helst omr\u00e5de af systemet under peakbelastning. Rate-limit b\u00f8r fungere s\u00e5dan, at enhver S3-foresp\u00f8rgsel kommer til en specifik v\u00e6rt, hvor denne v\u00e6rt er en identifikator for bucketten, og bucketten tilh\u00f8rer en bestemt kunde. Vi skal definere en funktion for bucketten, der g\u00f8r det muligt at beregne rate-limit. <\/p>\n<p><\/p>\n<p>Desuden skal systemet med rate-limits v\u00e6re tilstr\u00e6kkeligt effektivt til at h\u00e5ndtere den belastning, der kommer til S3.<\/p>\n<p><\/p>\n<p>Her har vi igen brugt Tarantool. Rate-limits er et cluster best\u00e5ende af 21 instanser, instanserne er opdelt i grupper, distribueret over tre fysiske noder og samlet i et stort topologisk cluster. Konfigurations\u00e6ndringer spredes automatisk: rate-limits, standarder og konfiguration fasts\u00e6ttes. Hver bucket serviceres strengt af \u00e9n instans. N\u00e5r en specifik bucket modtager en foresp\u00f8rgsel, beregnes den instans, der er ansvarlig for denne bucket. Inden for denne node t\u00e6lles den aktuelle foresp\u00f8rgselsrate med en algoritme, der ligner Token Bucket. Derefter fort\u00e6ller rate-limit-systemet, baseret p\u00e5 de aktuelle belastningsdata og egenskaberne, der er indstillet for den specifikke bucket, om foresp\u00f8rgslen kan udf\u00f8res eller ej. Gr\u00e6nsen kontrolleres p\u00e5 det tidligste stadie af udf\u00f8relsen af S3-foresp\u00f8rgslen for at beskytte de \u00f8vrige systemelementer mod overbelastning. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/1b91e5d1fe067c859ba9b36d58827579.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Derudover er det ret sv\u00e6rt at klare sig uden cache under belastning. I S3 foruds\u00e6ttes det gentagne anmodninger til de samme objekter, hvilket betyder, at det er et varmt lager. Normalt behandles anmodningen til en enkelt fil gennem hele k\u00e6den: Streamer, FileDB, PairDB, Storage. Men ved gentagne anmodninger til en fil optimerer vi adgangen til dette indhold ved hj\u00e6lp af lokal cache.<\/p>\n<p><\/p>\n<p>Cachen er lagdelt og implementeret ved hj\u00e6lp af nginx, lokale, SSD- og RAM-diske. Her har vi ikke brugt Tarantool, fordi det er lettere at levere objekter fra filsystemet, hvilket giver os mulighed for at lave caching tiering. Derudover har vi store objekter med en maksimal st\u00f8rrelse p\u00e5 32 gigabyte, og i Tarantool kan man kun cache sm\u00e5 objekter.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/faa02bd52a1d70642589d775f22c5e75.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette var det f\u00f8rste system, vi lancerede, og det havde en beregnet kapacitet, som var tilstr\u00e6kkelig til at udforske og forst\u00e5 produktet og sikre, at det ville fungere. <\/p>\n<p><\/p>\n<h2 id=\"dorabotki-boevoy-sistemy-feylover-i-masshtabirovanie\">Forbedringer af kampsystemet: failover og skalering<\/h2>\n<p><\/p>\n<p>Systemet var allerede i drift, men ved starten havde vi overset nogle ting \u2014 vi skulle have tilf\u00f8jet failover og skalering. <\/p>\n<p><\/p>\n<p>Vores S3-demon hentede metadata via Tarantool-protokollen. Vi satte Tarantool som proxy-router for foresp\u00f8rgsler efter metadata p\u00e5 stedet for den originale database. Set fra applikationens side, der implementerede API'en, \u00e6ndrede intet sig \u2014 den fortsatte med at tilg\u00e5 databasen via Tarantool-protokollen, men routeren kunne sikre aktiv failover. Det vil sige, vi kunne kontrollere tilg\u00e6ngeligheden af noderne, tage pauser ved skift og fejl, og s\u00e5 videre. Applikationen blev dog ikke \u00e6ndret. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/978ff8a458f8d48b98672121cf6eca5d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h2 id=\"podrobnee-o-tom-kak-my-realizovali-shardirovanie\">L\u00e6r mere om, hvordan vi implementerede sharding<\/h2>\n<p><\/p>\n<p>Det n\u00e6ste sp\u00f8rgsm\u00e5l, som vi m\u00e5tte tage os af \u2014 var sharding. Systemet voksede, antallet af objekter voksede, og vi m\u00e5tte sikre muligheder for yderligere v\u00e6kst.<\/p>\n<p><\/p>\n<p>Lad os vende tilbage til dataskemaet: der er projekter, buckets, credentials og billing. Dette er objekter, der h\u00f8jst sandsynligt ikke vil vokse ud over \u00e9n instans hverken i volumen eller foresp\u00f8rgsler inden for den n\u00e6rmeste fremtid. S\u00e5 der er ikke nogen grund til at sharde dem, og vi har flyttet dem til en separat instans, som forbliver usharded. Dette g\u00f8r det muligt at administrere projekter og buckets mere konsekvent, da der er et enkelt usharded punkt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/c5a1c1a875e756e3dceb5f885fbda2c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Der er ogs\u00e5 objekter i skemaet, som vokser line\u00e6rt \u2014 i starten var der hundrede tusinde, og nu m\u00e5les deres antal i milliarder. S\u00e5danne objekter og deres dele skulle flyttes til en sharded cluster. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/00bb418cc61ad2e3e8797caf5d1ab202.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi delte skemaet op, men objekterne skal arbejde med buckets: et objekt tilh\u00f8rer altid en specifik bucket, plus der anvendes ACL p\u00e5 bucketen. Derfor holder vi en skyggekopia af hver bucket for hver shard med objekter. Derudover, under modifikation af objekter og udf\u00f8relse af foresp\u00f8rgsler, skal vi t\u00e6lle volumen for billing, s\u00e5 hver shard har t\u00e6llere til billing.<\/p>\n<p><\/p>\n<p>Vi har ogs\u00e5 tilf\u00f8jet et par ekstra tabeller og komponenter:<\/p>\n<p><\/p>\n<ul>\n<li>en papirkurv til at slette gamle projekter, der bliver slettet eller fryset;<\/li>\n<li>en k\u00f8 for baggrundsopgaver, hvilket betyder, at det prim\u00e6re lager kan udf\u00f8re de n\u00f8dvendige baggrundsopgaver p\u00e5 klyngen;<\/li>\n<li>livscyklusst\u00f8tte \u2014 en mekanisme, der tillader arbejde med objekter og styring af deres livscyklus.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/933e98dc559eb8e6bac14003215a6836.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Da vi har flyttet nogle data til shards, havde vi brug for en shardering-proxy. Vi kunne have genbrugt routeren til denne rolle, men en separat shardering-proxy, der kun besk\u00e6ftiger sig med shardering af data, g\u00f8r, at routeren kan hente data i sin helhed uden at t\u00e6nke p\u00e5 shardering.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/4b181ed4629180e15558f25b1e4d5718.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Jeg vil specifikt fort\u00e6lle, hvorfor vi ikke tog en f\u00e6rdig l\u00f8sning, men \u00f8nskede at lave en tilpasset shardering-funktion. <\/p>\n<p><\/p>\n<p>Lad os se, hvordan det er opbygget. Vi har 256 tilg\u00e6ngelige shards. For hver bucket tildeler vi et interval ved hj\u00e6lp af en konsistent funktion. Det er enkelt \u2014 ligesom n\u00e5r du ved hj\u00e6lp af en konsistent funktion bestemmer tilh\u00f8rsforhold til en shard, bestemmer du den startende shard og tildeler et interval:<\/p>\n<p><\/p>\n<p><code>f(bucket, shards) = subset<\/code><\/p>\n<p><\/p>\n<p>Det vil sige, at hvis vi tager en bucket, kan vi sige, at den og dens data altid vil v\u00e6re placeret i et specifikt underudvalg af alle shards. Dette reducerer indflydelsen fra \u00e9n bucket p\u00e5 en anden og forenkler arbejdet med map-reduce foresp\u00f8rgsler, n\u00e5r det for eksempel skal laves en liste over objekter i en bucket. For dette skal vi foresp\u00f8rge alle shards, hvor disse objekter er gemt. Hvis objekterne l\u00e5 p\u00e5 alle shards, ville enhver listeoperation p\u00e5virke hele systemet, men her p\u00e5virker det kun et specifikt underudvalg.<\/p>\n<p><\/p>\n<p>Dern\u00e6st \u2014 hvert objekt tilh\u00f8rer en specifik bucket, s\u00e5 n\u00e5r vi anmoder om et objekt, anmoder vi om objektet med navn i den specifikke bucket. Det vil sige, at vi kan definere en funktion for objektet ikke fra hele det tilg\u00e6ngelige interval af shards, men kun fra underudvalget af dets bucket:<\/p>\n<p><\/p>\n<p><code>f(object, subset) = shard<\/code><\/p>\n<p><\/p>\n<p>Vi tager et specifikt objekt, og som argumenter for funktionen sender vi ikke alle shards, men et underudvalg af dets bucket \u2014 og f\u00e5r en specifik shard. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/10480ad2430c228c511ff3cdc5071596.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>S\u00e5, shardingen er implementeret, der er en shardering-proxy. Det, der er tilbage, er at hente fra routeren og database med metadata ind i shardering-proxien. For eksempel til oprettelse af objekter til skyggekopier \u2014 n\u00e5r vi opretter en bucket, skal det prim\u00e6re lager oprette en repr\u00e6sentant for denne bucket p\u00e5 alle shards, hvor den skal v\u00e6re til stede.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/bb34d1f747903a3c2f08f582e4424787.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h2 id=\"kak-my-realizovali-resharding\">Hvordan vi implementerede resharing<\/h2>\n<p><\/p>\n<p>Den st\u00f8rste udfordring ved sharding er resharding. Det var vigtigt for os at g\u00f8re det uden nedetid, da systemet allerede var i produktion. Jeg vil vise, hvordan vi l\u00f8ste problemet ved hj\u00e6lp af et tilsvarende eksempel med live migration af data fra et projekt til et andet.<\/p>\n<p><\/p>\n<p>Nedenfor er diagrammet over vores klynge, som det s\u00e5 ud efter implementeringen af sharding. Vi har nginx, S3 API, en router, en prim\u00e6r database med projekter, en sharding-proxy og selve shards.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/0e6bd16c7fc47437b3b7d96b6d9809a4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tidligere overs\u00e5 jeg det punkt, at der p\u00e5 et bestemt tidspunkt i projektet var en produktopgave: \u201eAt lancere endnu en opbevaring, Icebox, som Hotbox, men kun til kolde data\u201c. I bund og grund en lignende opbevaring, men med andre URL'er og uden caches.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/9ce9085e1d03e9a99b6b8ccc0717c653.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Icebox blev brugt mindre end Hotbox, derfor fungerede det forholdsvis l\u00e6nge uden nogen form for sharding. I sidste ende besluttede vi at opgive det og kombinere Hotbox og Icebox til en enkelt service ved blot at dele lagringsklasserne. <\/p>\n<p><\/p>\n<p>Buckets i opbevaringerne overlapper ikke, de kunne let smeltes sammen og flyttes, men kunderne brugte b\u00e5de det ene og det andet opbevaringssystem, s\u00e5 vi var n\u00f8dt til at l\u00f8se problemet med frav\u00e6ret af nedetid. Man kunne ikke bare slukke og kopiere. Vi udf\u00f8rte migration i flere trin.<\/p>\n<p><\/p>\n<p>I f\u00f8rste omgang synkroniserede vi de prim\u00e6re opbevaringer. Vi havde Tarantool, og vi kunne ved oprettelse af et objekt g\u00f8re det s\u00e5dan: <\/p>\n<p><\/p>\n<ul>\n<li>en anmodning om oprettelse af en bucket kommer til databasen, f.eks. i Hotbox;<\/li>\n<li>Tarantool kontrollerer i en anden database (i dette tilf\u00e6lde \u2013 i Icebox), at der ikke er nogen s\u00e5dan bucket;<\/li>\n<li>hvis bucket findes, meddeler databasen, at den ikke kan oprettes, og den synkroniseres som eksisterende.<br \/>\n<img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/6694c9804f09942416c1717b455b9fd3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>Synkronisering af buckets<\/em><\/li>\n<\/ul>\n<p><\/p>\n<p>I den opbevaring, der skulle modtage alle data, indf\u00f8rte vi for projekter og buckets et flag, der angav, hvor dette objekt opbevares. Det kunne v\u00e6re lokalt i Hotbox, i Icebox \u2013 s\u00e5 vil der ikke v\u00e6re nogen data i den nye opbevaring, eller det kunne v\u00e6re i en migrationsstatus.<\/p>\n<p><\/p>\n<p>Hvis et projekt eller en bucket havde flaget Migrating, blev anmodningen under migrationen f\u00f8rst udf\u00f8rt i den nye opbevaring, hvor dataene burde v\u00e6re, og hvis de ikke var der, blev anmodningerne sendt til den alternative opbevaring.<\/p>\n<p><\/p>\n<p>Derefter skiftede vi trafikken. Da API'et kunne betjene anmodninger fra b\u00e5de Icebox og Hotbox, kunne vi uden nedetid skifte trafikken ved blot at flytte v\u00e6rter og tilf\u00f8je de relevante poster i Nginx. <\/p>\n<p><\/p>\n<p>N\u00e5r trafikken var omdirigeret, kunne Nginx og API fra Icebox fjernes.<br \/>\nDerefter fjernede vi Icebox nginx og S3 API - og alt virkede:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/62d9f960fc1f11b875a8f8a5aa8e8152.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Derefter startede vi en baggrundsproces for migration, som k\u00f8rer inde i databasen - det gennemg\u00e5r element for element alle projekter og deres buckets, s\u00e6tter dem i status Migrating, overf\u00f8rer dataene, og efter overf\u00f8rslen s\u00e6tter det status til Local.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/1a3129136f7ccacfdcff260f10cb0605.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Efter dataoverf\u00f8rslen har vi ikke l\u00e6ngere brug for det gamle lagersystem, og vi fjerner de resterende dele af det gamle system samt fjerner underst\u00f8ttelsen af migreringsstatus fra koden.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/13b6f11add40c21a3b9afc05dd0dfea9.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Den samme tilgang blev anvendt til resharding fra det gamle lager til det sharded:<\/p>\n<p><\/p>\n<ul>\n<li>Vi markerede alle buckets som <code>Non-sharded<\/code>. Alle foresp\u00f8rgsler til dem gik til det originale, ikke-shardede lager.<\/li>\n<li>Nye buckets blev straks oprettet med status <code>Sharded<\/code>.<\/li>\n<li>Vi tog \u00e9n bucket ad gangen, satte status til <code>Migrating<\/code> og overf\u00f8rte dataene.<\/li>\n<\/ul>\n<p><\/p>\n<p>Foresp\u00f8rgsler blev behandlet med f\u00f8lgende princip:<\/p>\n<p><\/p>\n<ul>\n<li>L\u00e6s f\u00f8rst fra det nye, derefter fra det gamle.<\/li>\n<li>Opret kun i det nye.<\/li>\n<li>Opdater i to faser: hvis det nye ikke har det, overf\u00f8r fra det gamle til det nye, og derefter opdater.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"rabota-s-ssl-sertifikatami\">Arbejdet med SSL-certifikater<\/h2>\n<p><\/p>\n<blockquote><p>P\u00e5 frontend anvender vi Nginx. I vores tilf\u00e6lde er det ikke en almindelig Nginx, men OpenResty, Nginx med underst\u00f8ttelse af LuaJIT.<\/p><\/blockquote>\n<p>Et andet stykke af systemet - arbejdet med SSL-certifikater. I S3-lageret kan du tilf\u00f8je et eget dom\u00e6ne til adgang til en specifik bucket, blot ved hj\u00e6lp af <code>CNAME<\/code>. Men uden HTTPS kan man ikke i dag: et eget dom\u00e6ne foruds\u00e6tter et eget SSL-certifikat. <\/p>\n<p><\/p>\n<p>Som jeg allerede har sagt, er det Nginx, der st\u00e5r for belastningsbalancering og SSL-terminering. I vores tilf\u00e6lde er det ikke en almindelig Nginx, men OpenResty, Nginx med underst\u00f8ttelse af LuaJIT.<\/p>\n<p><\/p>\n<p>Dette gjorde det muligt for os at l\u00e6re vores Nginx at afgive vilk\u00e5rlige certifikater ret nemt. Desuden var det n\u00f8dvendigt at afgive certifikater dynamisk (uden at skulle angive dem i konfigurationsfilen). Vi brugte udvidelsen <code>ssl_certificate_by_lua<\/code>, som g\u00f8r det muligt at l\u00e6se certifikatet fra en vilk\u00e5rlig kilde under TLS-handshake. Til certifikatlagring anvendte vi ogs\u00e5 Tarantool: dette g\u00f8r det muligt at administrere certifikater udefra og sikrer ekstremt hurtig levering.<\/p>\n<p><\/p>\n<p>Der er ogs\u00e5 implementeret en separat daemon, hvis opgave er at opdatere certifikater regelm\u00e6ssigt, som er udstedt ved hj\u00e6lp af Let&#8217;s Encrypt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/8d61c1cb3084d9eb4eb8faa745e212db.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<h2 id=\"chto-by-ya-sohranil-a-chto-sdelal-po-drugomu-esli-razrabatyvat-hranilische-zanovo\">Hvad ville jeg have gemt, og hvad ville jeg have gjort anderledes, hvis jeg skulle udvikle lageret fra bunden<\/h2>\n<p><\/p>\n<h3 id=\"chto-nuzhno-bylo-ispolzovat-s-samogo-nachala\">Hvad skulle have v\u00e6ret brugt fra starten<\/h3>\n<p><\/p>\n<p><strong>Sharding med det samme<\/strong>. Der har v\u00e6ret en del problemer med resharding. Det er let at g\u00f8re, men hvis man starter projekter, der skal skaleres, er det bedre at tage en sharded klynge fra starten, selv p\u00e5 et minimum af noder. Implementeringen af sharding fra starten er n\u00e6sten gratis sammenlignet med at indf\u00f8re sharding i et driftsystem.<\/p>\n<p><\/p>\n<p><strong>At arbejde med Tarantool gennem load balancers<\/strong>. Nu kobler vi alle nye databaser til arbejdet gennem load balancers. Det giver mulighed for at udvide funktionaliteten og opn\u00e5 h\u00f8jere fejlresistens. <\/p>\n<p><\/p>\n<p><strong>Auto-failover<\/strong>. Jeg ville have installeret alle de v\u00e6rkt\u00f8jer, der kr\u00e6ves til auto-failover, da de f\u00f8rste fejlslag efter lanceringen var relateret til dets frav\u00e6r. Efter erfaringen med S3 blev alle efterf\u00f8lgende produkter lanceret med dette i tankerne.<\/p>\n<p><\/p>\n<p><strong>S3-funktionen \"Versioning\"<\/strong>. F\u00f8rst syntes det ikke at v\u00e6re en s\u00e6rlig efterspurgt funktionalitet. At integrere denne mulighed i arkitekturen af et fungerende system er ekstremt vanskeligt.<\/p>\n<p><\/p>\n<p><strong>Separat billing<\/strong>. Den m\u00e5de, vi integrerede billing i vores system, fungerede godt i starten, men senere blev det problematisk; det ville have v\u00e6ret bedre at have det som en helt separat service.<\/p>\n<p><\/p>\n<h3 id=\"chto-bylo-udachnym-resheniem\">Hvad der var en vellykket l\u00f8sning<\/h3>\n<p><\/p>\n<p><strong>Datamodel<\/strong>. Historien har vist, at vi i takt med udviklingen af tjenesten ret pr\u00e6cist passer til datamodellen fra Amazon, s\u00e5 vi kan implementere de funktioner, der findes der.<\/p>\n<p><\/p>\n<p><strong>Shardingskema<\/strong>. Jeg ville have st\u00f8ttet den samme sortering af sharding efter buckets, da det g\u00f8r det muligt at fordele foresp\u00f8rgsler fra forskellige buckets over en stor klynge.<\/p>\n<p><\/p>\n<p><strong>Brug af Tarantool<\/strong>. Tarantool har v\u00e6ret en stor hj\u00e6lp i udviklingen af tjenesten og dens modifikation; vi arbejdede nemt med dataene, transformerede og sharded lageret uden at skulle opbygge et lag i applikationen. <\/p>\n<p><\/p>\n<blockquote><p>Denne pr\u00e6sentation blev f\u00f8rste gang pr\u00e6senteret ved <noindex><a rel=\"nofollow\" href=\"https:\/\/corp.mail.ru\/ru\/press\/events\/databases-2\/\">@Databases Meetup<\/a><\/noindex> by Mail.ru Cloud Solutions&amp;Tarantool. Se <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=jM4hL2u6JM0&amp;list=PLQzTaxmOHjntyNRPWhaWHqlHp8UN_wgQ3\">en video<\/a><\/noindex> andre pr\u00e6sentationer og tilmeld dig nyhedsbreve om arrangementer p\u00e5 Telegram <noindex><a rel=\"nofollow\" href=\"https:\/\/t.me\/k8s_mail\">Omkring Kubernetes i Mail.ru Group<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Du kan ogs\u00e5 se mit gamle foredrag om S3 eller l\u00e6se min kollegas artikel om bloklagring.<\/p>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=O0iIADHgBVc\">Reverse engineering af Amazon S3-arkitekturen og hvordan S3-lageret i MCS s\u00e5 ud for 3 \u00e5r siden<\/a><\/noindex>.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/472694\/\">Mere end Ceph: bloklageret i MCS<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>Kilde: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/513356\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>Storage Corridor by St-Pete \u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u042f Mons Anderson, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b Mail.ru Cloud Solutions, \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u043d\u0430\u0448\u0435 S3-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u043a\u0430\u043a \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0443\u0434\u0430\u0447\u043d\u044b\u043c\u0438, \u0430 \u043a\u0430\u043a\u0438\u0435 \u0441\u0442\u043e\u0438\u043b\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u0431\u044b \u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u043d\u0443\u043b\u044f \u0441\u0435\u0439\u0447\u0430\u0441. \u0421\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430 @Databases Meetup by Mail.ru Cloud Solutions &amp; Tarantool. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":91091,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-91090","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 S3: 3 \u0433\u043e\u0434\u0430 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u0438 Mail.ru Cloud Storage | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-08-08T11:42:11+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-08-08T11:42:11+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47S3-arkitektur: 3 \u00e5rs evolution af Mail.ru Cloud Storage | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 S3: 3 \u0433\u043e\u0434\u0430 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u0438 Mail.ru Cloud Storage | ProHoster","og:url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-08-08T11:42:11+00:00","article:modified_time":"2020-08-08T11:42:11+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"91090","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:34:25","updated":"2022-10-02 13:27:50","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/91090","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=91090"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/91090\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/91091"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=91090"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=91090"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=91090"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}