{"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\/it\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage","title":{"rendered":"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di 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\">Corridor di Storage<\/a><\/noindex> di St-Pete<\/em><\/p>\n<p><\/p>\n<p>Ciao a tutti! Sono Mons Anderson, architetto della piattaforma <noindex><a rel=\"nofollow\" href=\"https:\/\/mcs.mail.ru\/\">Mail.ru Cloud Solutions<\/a><\/noindex>, racconter\u00f2 come abbiamo costruito il nostro storage S3, come funziona, quali soluzioni si sono rivelate efficaci e quali avremmo dovuto cambiare se avessimo iniziato lo stesso progetto da zero ora.<\/p>\n<p><\/p>\n<p>Questo articolo \u00e8 stato preparato sulla base di una presentazione a <noindex><a rel=\"nofollow\" href=\"https:\/\/corp.mail.ru\/ru\/press\/events\/databases-2\/\">@Databases Meetup<\/a><\/noindex> di Mail.ru Cloud Solutions &amp; Tarantool. In questo articolo parleremo di:<\/p>\n<p><\/p>\n<ul>\n<li>come era strutturato lo storage di Mail.ru, su cui abbiamo costruito lo storage S3;<\/li>\n<li>cosa abbiamo aggiunto per creare Mail.ru Cloud Storage;<\/li>\n<li>come funziona il modello di storage a oggetti e quali passi sono stati compiuti per il passaggio in produzione;<\/li>\n<li>sulle modifiche al sistema operativo: failover e scalabilit\u00e0;<\/li>\n<li>come abbiamo implementato lo sharding e la resharing;<\/li>\n<li>e anche sul lavoro con i certificati SSL.<\/li>\n<\/ul>\n<p><\/p>\n<p>Se non vuoi leggere, puoi <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/NEgm1nsv-qg\">guardare<\/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\">Come era strutturato lo storage di Mail.ru, su cui abbiamo costruito lo storage S3<\/h2>\n<p><\/p>\n<p>Lo sviluppo del nostro S3 \u00e8 iniziato sopra lo storage di Mail.ru Cloud, quindi \u00e8 importante raccontare come \u00e8 strutturato e cosa pu\u00f2 fare.<\/p>\n<p><\/p>\n<p>Lo storage cloud di Mail.ru \u00e8 composto da server con dischi. In media, un server di storage moderno ha 36 dischi da 12\u201314 terabyte. Prima i dischi erano pi\u00f9 piccoli, ma in tre anni la capacit\u00e0 dei dischi \u00e8 aumentata e oggi siamo quasi a mezzo petabyte di dati grezzi. <\/p>\n<p><\/p>\n<p>I dischi di diversi server di storage vengono uniti in quelle che chiamiamo \"coppie\" (pair). Una coppia \u00e8 una unit\u00e0 di archiviazione dei file. In sostanza, \u00e8 un disco montato in una certa partizione a un certo percorso, dove possono risiedere file identificati tramite hash. <\/p>\n<p><\/p>\n<p>Coppia \u00e8 un nome storico, rimasto fino ad oggi, anche se ora in una coppia non ci devono essere necessariamente solo due dischi. Possono essercene tre, e possono esserci anche varie forme di storage ibride, come 3\/2. <\/p>\n<p>\n<img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/544ab79846539262e2d4dff6ab95ffff.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Coppie (pair) \u2014 unit\u00e0 di archiviazione degli oggetti<\/em><\/p>\n<p><\/p>\n<p>Tutte le coppie sono memorizzate in PairDB \u2014 un'applicazione basata su Tarantool. Tutte le banche dati nel nostro storage, a partire dalle prime, sono Tarantool, non usiamo altre banche dati.<\/p>\n<p><\/p>\n<p>PairDB memorizza tutte le coppie, i loro stati, lo spazio libero, le possibilit\u00e0 di failover, gli ultimi errori. Pu\u00f2 anche controllare autonomamente le coppie, aggiornare il loro stato, verificare se funzionano o meno. Quindi PairDB \u00e8 una sorta di snapshot generale dello stato di tutti i dischi del nostro sistema.<\/p>\n<p>\n<img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/d50781b8b51ed5fe126bc84e19c934d1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Pair DB: database con lo stato delle coppie<\/em><\/p>\n<p><\/p>\n<p>Nei corsi sono archiviati dei file e, per sapere quale file si trova in quale corso, \u00e8 necessaria un'altra base \u2014 FileDB. Essa memorizza il mapping, la definizione di corrispondenza: questo file si trova in questo corso, oltre a una piccola quantit\u00e0 di attributi necessari.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/b1a64737cf7f916bff446c10c1f01d4c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><em>File DB: luogo in cui \u00e8 archiviato il file<\/em><\/p>\n<p>Un altro anello importante \u00e8 il servizio Nylon, un router per lavorare con i database. \u00c8 un unico punto di accesso, permette di lavorare attraverso un'interfaccia unica sia con PairDB che con FileDB. Questo \u00e8 un servizio stateless, esegue il bilanciamento delle richieste, comprende a quale shard di FileDB \u00e8 necessario andare, sa quali corsi sono attivi e quali no.<\/p>\n<p>\n<img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/3e2225f229c8cfa462d620d2b5fb581e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Nylon: router per lavorare con i database<\/em><\/p>\n<p><\/p>\n<p>Inoltre, \u00e8 necessario in qualche modo caricare i contenuti nell'archivio. A questo scopo esiste il servizio \u2014 Streamer. Esso fornisce due metodi HTTP: il metodo PUT per caricare contenuti nell'archivio e il metodo GET per prelevarli da l\u00ec. HTTP \u00e8 un protocollo piuttosto popolare e comodo per la trasmissione dei dati. <\/p>\n<p><\/p>\n<p>Quando ci rivolgiamo a Streamer, esso tramite Nylon si interfaccia con PairDB per scoprire su quale coppia \u00e8 possibile caricare il file, dopodich\u00e9 trasferisce i dati via WebDAV su quella coppia. <\/p>\n<p><\/p>\n<p>In sostanza, qualsiasi server di storage \u00e8 un nginx pi\u00f9 i dischi montati secondo i percorsi specificati. Possiamo caricare un file nell'archivio da Streamer, eliminarlo, rinominarlo o verificarne l'integrit\u00e0. Quindi, \u00e8 un'interfaccia comoda per l'interazione a basso livello con l'archivio. <\/p>\n<p>\n<img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/3722a89ed44cace36e9cb1f8bee4bd1e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Streamer: punto di accesso all'archivio<\/em><\/p>\n<p><\/p>\n<h2 id=\"chto-my-dobavili-chtoby-sdelat-s3-hranilische\">Cosa abbiamo aggiunto per realizzare l'archivio S3<\/h2>\n<p><\/p>\n<p>Quindi, abbiamo esaminato la struttura di base dell'archivio al momento in cui ci siamo preparati a lanciare l'archivio S3. Con il metodo PUT potevamo caricare contenuti arbitrari e ottenere come identificatore di quei dati un hash. Con questo identificatore si poteva successivamente andare a prelevare il file originale. Ma questo non \u00e8 sufficiente per implementare S3. Nel protocollo S3, oltre al semplice stoccaggio degli oggetti, ci sono:<\/p>\n<p><\/p>\n<ul>\n<li>stoccaggio dei metadati \u2014 propriet\u00e0 aggiuntive degli oggetti;<\/li>\n<li>organizzazione dell'accesso agli oggetti tramite HTTP;<\/li>\n<li>raggruppamento degli oggetti in collezioni \u2014 bucket;<\/li>\n<li>HTTP-S3 Endpoint. S3 organizza i dati in strutture specifiche \u2014 bucket, ognuno dei quali fornisce un punto di accesso per l'archiviazione dei file.<\/li>\n<\/ul>\n<p><\/p>\n<p>Per implementare questa logica era necessario un servizio separato. Volevamo anche prevedere subito un'architettura per una futura crescita del servizio con scalabilit\u00e0 lineare.<\/p>\n<p><\/p>\n<h2 id=\"pervye-komponenty\">I primi componenti<\/h2>\n<p><\/p>\n<p>Un demone che implementa l'API S3. Questo \u00e8 il standard S3 API di Amazon, che supporta l'elaborazione XML per i metadati e consente di trasmettere contenuti direttamente. Non abbiamo dovuto inventare nulla, tutto \u00e8 descritto e documentato.<\/p>\n<p><\/p>\n<p>Davanti al servizio abbiamo anche installato Nginx. L'abbiamo utilizzato per la terminazione SSL, il bilanciamento del carico, e per alcune logiche in Lua (metriche, logging e tracciamento).<\/p>\n<p><\/p>\n<p>Per memorizzare i metadati S3 abbiamo scelto Tarantool. Nella prima versione, il demone S3 accedeva a questo database per i metadati, conservando il contenuto in un grande deposito tramite Streamer.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/03dddec282b5bb41eb63748ccfb6c9a4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>Nginx + API S3 + metadati<\/em><\/p>\n<p><\/p>\n<h2 id=\"obektnaya-model-hraneniya\">Modello oggetto per la memorizzazione<\/h2>\n<p><\/p>\n<p>Vediamo come funziona S3. L'utente pu\u00f2 creare un bucket \u2014 una raccolta di oggetti. Il bucket \u00e8 indirizzato con il nome dell'host e costituisce un sottodominio del servizio. All'interno del bucket, l'utente pu\u00f2 creare oggetti. L'identificatore dell'oggetto sar\u00e0 l'URL. Il contenuto dell'oggetto \u00e8 un blob, un array di dati binari che memorizzeremo nel deposito. Inoltre, l'oggetto ha attributi: il nome \u2014 appunto l'URL, ACL (lista di controllo degli accessi), altri attributi aggiuntivi o arbitrari \u2014 tutto questo \u00e8 salvato nei metadati. <\/p>\n<p><\/p>\n<p>Uno schema normalizzato di questi dati pu\u00f2 apparire cos\u00ec: ci sono progetti cui appartengono i bucket, a cui appartengono gli oggetti, e gli oggetti possono essere composti. Poich\u00e9 uno dei modi per caricare un oggetto \u00e8 a pezzi, ci sono due tabelle ausiliarie per il caricamento: uploads e chunks. Inoltre, i progetti hanno credenziali di accesso e billing. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/e2bede45ba4044f658b47a9840fd5224.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>Schema dei dati<\/em><\/p>\n<p><\/p>\n<p>Poich\u00e9 stavamo creando un servizio b2b con accesso a pagamento, era necessario il billing in questo schema.<br \/>\nIl servizio di billing \u00e8 stato implementato anche su Tarantool. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di 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\">Modifiche allo storage S3: passi verso la produzione<\/h2>\n<p><\/p>\n<p>Abbiamo gi\u00e0 realizzato un modello funzionante che pu\u00f2 essere utilizzato: gli oggetti e i metadati erano memorizzati, ma per il rilascio in produzione mancavano alcuni aspetti.<\/p>\n<p><\/p>\n<p>In primo luogo, il sistema di rate limiting. Se avviassimo il servizio senza di esso, durante i picchi di carico potremmo sovraccaricare in modo imprevedibile una parte del sistema. Il rate limit dovrebbe funzionare in questo modo: ogni richiesta S3 arriva a un host specifico, questo host \u00e8 l'identificatore del bucket e il bucket appartiene a un determinato cliente. Dobbiamo definire una funzione per il bucket che consenta di calcolare il rate limit. <\/p>\n<p><\/p>\n<p>Inoltre, il sistema di rate limiting deve essere abbastanza performante da gestire il carico che arriva su S3.<\/p>\n<p><\/p>\n<p>Qui abbiamo nuovamente utilizzato Tarantool. I rate limit sono un cluster di 21 istanze, suddivise in gruppi, distribuite su tre nodi fisici e unite in un grande cluster topologico. Le modifiche di configurazione vengono propagate automaticamente: vengono impostati i rate limit, i valori predefiniti e la configurazione. Ogni bucket \u00e8 servito da una sola istanza. Quando arriva una richiesta per un determinato bucket, viene calcolata l'istanza responsabile di quel bucket. All'interno di questo nodo, viene effettuato il conteggio del rate attuale delle richieste attraverso un algoritmo simile al Token Bucket. Successivamente, il sistema di rate limiting, in base ai dati attuali di carico e alle caratteristiche impostate per quel bucket specifico, determina se la richiesta pu\u00f2 essere eseguita o meno. Il controllo dei limiti viene eseguito alla fase pi\u00f9 iniziale dell'elaborazione della richiesta S3, proteggendo tutti gli altri elementi del sistema da sovraload. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/1b91e5d1fe067c859ba9b36d58827579.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Inoltre, sotto carico \u00e8 piuttosto difficile fare a meno della cache. In S3 si prevede l'accesso ripetuto agli stessi oggetti, quindi si tratta di uno storage a caldo. Di norma, l'accesso a un file singolo \u00e8 gestito dall'intera catena: Streamer, FileDB, PairDB, Storage. Tuttavia, nel caso di accessi ripetuti a un file, ottimizziamo l'accesso a questo contenuto utilizzando una cache locale.<\/p>\n<p><\/p>\n<p>La cache \u00e8 multilivello e realizzata con nginx, dischi locali, SSD e RAM. Non abbiamo utilizzato Tarantool qui, poich\u00e9 \u00e8 pi\u00f9 comodo servire gli oggetti dal filesystem, consentendo di fare tiering della cache. Inoltre, abbiamo oggetti di grandi dimensioni con una dimensione massima di 32 gigabyte, mentre in Tarantool \u00e8 possibile memorizzare solo oggetti di piccole dimensioni.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/faa02bd52a1d70642589d775f22c5e75.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Questo primo sistema con cui abbiamo avviato aveva una certa capacit\u00e0 calcolata, sufficiente per l'indagine, la comprensione del prodotto e per verificare che funzionasse. <\/p>\n<p><\/p>\n<h2 id=\"dorabotki-boevoy-sistemy-feylover-i-masshtabirovanie\">Miglioramenti del sistema di combattimento: failover e scalabilit\u00e0<\/h2>\n<p><\/p>\n<p>Il sistema era gi\u00e0 in esercizio, ma all'avvio abbiamo trascurato qualcosa: dovevamo aggiungere il failover e la scalabilit\u00e0. <\/p>\n<p><\/p>\n<p>Il nostro demone S3 raccoglieva metadati tramite il protocollo Tarantool. Al posto del database originale, abbiamo implementato Tarantool, che fungeva da router proxy per le richieste di metadati. Dal punto di vista dell'applicazione che implementa l'API, nulla \u00e8 cambiato: continuava a comunicare con il database tramite il protocollo Tarantool, ma il router poteva garantire un failover attivo. Ci\u00f2 significava che potevamo verificare la disponibilit\u00e0 dei nodi, mantenere una pausa durante il passaggio e le interruzioni, e cos\u00ec via. Allo stesso tempo, non abbiamo modificato l'applicazione stessa. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di 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\">Maggiore dettagli su come abbiamo implementato il partizionamento<\/h2>\n<p><\/p>\n<p>La prossima questione che ci siamo posti era il partizionamento. Il sistema cresceva, aumentava il numero di oggetti e dovevamo garantire possibilit\u00e0 per una ulteriore crescita.<\/p>\n<p><\/p>\n<p>Torniamo allo schema dei dati: ci sono progetti, ci sono bucket, credenziali e fatturazione. Questi sono oggetti che con grande probabilit\u00e0 nel prossimo futuro non cresceranno oltre un'istanza, n\u00e9 per volume n\u00e9 per richieste. Pertanto, non ha senso partizionarli, e li abbiamo spostati in un'istanza separata che rimarr\u00e0 non partizionata. Questo consente una gestione pi\u00f9 coerente dei progetti e dei bucket, poich\u00e9 esiste un'unica istanza non partizionata. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/c5a1c1a875e756e3dceb5f885fbda2c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ci sono anche oggetti nello schema che crescono linearmente: inizialmente erano centinaia di migliaia, ora il loro numero si misura in miliardi. Tali oggetti, insieme alle loro parti, dovevano essere spostati in un cluster partizionato. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/00bb418cc61ad2e3e8797caf5d1ab202.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Abbiamo separato lo schema, ma gli oggetti devono lavorare con i bucket: ogni oggetto appartiene sempre a un bucket specifico, e su ogni bucket opera un ACL. Pertanto, per ciascun shard con oggetti, manteniamo una copia secondaria di ogni bucket. Inoltre, durante la modifica degli oggetti e l'esecuzione delle richieste, \u00e8 necessario calcolare il volume per la fatturazione, quindi in ogni shard ci sono contatori per la fatturazione.<\/p>\n<p><\/p>\n<p>Abbiamo anche aggiunto ulteriori tabelle e componenti:<\/p>\n<p><\/p>\n<ul>\n<li>il cestino, per distruggere vecchi progetti che vengono eliminati o congelati;<\/li>\n<li>coda per attivit\u00e0 di background, cio\u00e8 lo storage principale pu\u00f2 eseguire attivit\u00e0 di background che devono essere effettuate nel cluster;<\/li>\n<li>supporto per il lifecycle - un meccanismo che consente di lavorare con gli oggetti, gestendo il loro ciclo di vita.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/933e98dc559eb8e6bac14003215a6836.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poich\u00e9 parte dei dati \u00e8 stata trasferita su shard, \u00e8 necessaria una proxy di sharding. Si potrebbe riutilizzare il router per questo ruolo, ma una proxy di sharding separata, responsabile solo per lo sharding dei dati, consente di accedere ai dati nel router senza preoccuparsi dello sharding.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/4b181ed4629180e15558f25b1e4d5718.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Racconter\u00f2 a parte perch\u00e9 non abbiamo scelto una soluzione pronta, ma volevamo realizzare una funzione di sharding personalizzata. <\/p>\n<p><\/p>\n<p>Vediamo come \u00e8 strutturata. Abbiamo 256 sharding disponibili. Per ciascun bucket, allocchiamo un intervallo usando una funzione consistente. \u00c8 semplice: proprio come usate una funzione consistente per determinare a quale shard appartiene un bucket, definite lo shard iniziale e allocate un intervallo:<\/p>\n<p><\/p>\n<p><code>f(bucket, shards) = subset<\/code><\/p>\n<p><\/p>\n<p>Quindi, se prendiamo un bucket, possiamo dire che esso e i suoi dati risiederanno sempre su un sottoinsieme specifico di tutti gli shard. Questo riduce l'impatto di alcuni bucket su altri e semplifica il lavoro delle query map-reduce, quando ad esempio \u00e8 necessario elencare gli oggetti del bucket. Per fare questo, \u00e8 necessario interrogare tutti gli shard in cui questi oggetti sono memorizzati. Se gli oggetti fossero memorizzati su tutti gli shard, qualsiasi elenco influenzerebbe l'intero sistema, mentre qui influenzerebbe solo un sottoinsieme specifico.<\/p>\n<p><\/p>\n<p>Inoltre, ogni oggetto appartiene a un bucket specifico, quindi quando richiediamo un oggetto, ci rivolgiamo a un oggetto per nome nel bucket specifico. Possiamo quindi definire una funzione per l'oggetto non su tutto l'intervallo disponibile di shard, ma solo su un sottoinsieme del suo bucket:<\/p>\n<p><\/p>\n<p><code>f(object, subset) = shard<\/code><\/p>\n<p><\/p>\n<p>Prendiamo un oggetto specifico e come argomenti della funzione passiamo non tutti gli shard, ma solo il sottoinsieme del suo bucket, e otteniamo uno shard specifico. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/10480ad2430c228c511ff3cdc5071596.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dunque, lo sharding \u00e8 implementato, c'\u00e8 una proxy di sharding. Resta solo da far interagire il router e il database dei metadati con la proxy di sharding. Ad esempio, per creare oggetti di copie shadow - quando creiamo un bucket, lo storage principale deve creare un rappresentante di questo bucket su tutti gli shard in cui deve essere presente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di 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\">Come abbiamo implementato il resharding<\/h2>\n<p><\/p>\n<p>Il problema principale del sharding \u00e8 il reshading. Era importante per noi realizzarlo senza downtime, poich\u00e9 il sistema era gi\u00e0 in produzione. Vi mostrer\u00f2 come abbiamo risolto il problema con un esempio simile di migrazione dal vivo dei dati da un progetto a un altro.<\/p>\n<p><\/p>\n<p>Di seguito \u00e8 riportato lo schema del nostro cluster, che abbiamo ottenuto dopo l'implementazione del sharding. Abbiamo nginx, l'API S3, un router, un database principale con i progetti, un proxy di sharding e, infine, gli shard.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/0e6bd16c7fc47437b3b7d96b6d9809a4.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>In precedenza ho trascurato di menzionare che in un certo momento del progetto c'era un compito di prodotto: \"Lanciare un altro storage, Icebox, come Hotbox, ma solo per i dati freddi\". Fondamentalmente, uno storage simile, ma con URL diversi e senza cache.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di 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 \u00e8 stato utilizzato meno di Hotbox, quindi \u00e8 rimasto per molto tempo senza alcun sharding. Alla fine abbiamo deciso di eliminarlo e di unire Hotbox e Icebox in un unico servizio, semplicemente separando le classi di archiviazione. <\/p>\n<p><\/p>\n<p>I bucket negli storage non si sovrapponevano, potevano essere facilmente uniti e spostati, ma i clienti usavano entrambi gli storage, quindi dovevamo risolvere il problema dell'assenza di downtime. Non potevamo semplicemente spegnere e copiare. Abbiamo effettuato la migrazione in pi\u00f9 fasi.<\/p>\n<p><\/p>\n<p>Per cominciare, abbiamo sincronizzato gli storage principali. Avevamo Tarantool e potevamo, durante la creazione di un oggetto, fare cos\u00ec: <\/p>\n<p><\/p>\n<ul>\n<li>il database riceve una richiesta per la creazione di un bucket, ad esempio in Hotbox;<\/li>\n<li>Tarantool verifica in un altro database (in questo caso, Icebox) se quel bucket non esiste;<\/li>\n<li>se il bucket esiste, il database comunica che non pu\u00f2 essere creato, e si sincronizza come esistente.<br \/>\n<img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/6694c9804f09942416c1717b455b9fd3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>Sincronizzazione dei bucket<\/em><\/li>\n<\/ul>\n<p><\/p>\n<p>Nello storage che doveva ricevere tutti i dati, abbiamo introdotto per progetti e bucket un attributo che indicava dove si trovava quell'oggetto. Poteva essere archiviato localmente, cio\u00e8 in Hotbox, in Icebox \u2014 in quel caso, non c'erano dati al riguardo nel nuovo storage, oppure poteva essere in stato di migrazione.<\/p>\n<p><\/p>\n<p>Se un progetto o un bucket aveva l'attributo Migrating, durante la migrazione la richiesta veniva inizialmente eseguita nel nuovo storage, dove i dati dovevano trovarsi, e se non c'erano, le richieste venivano reindirizzate allo storage alternativo.<\/p>\n<p><\/p>\n<p>Successivamente abbiamo reindirizzato il traffico. Poich\u00e9 l'API poteva gestire sia le richieste di Icebox che quelle di Hotbox, siamo riusciti a reindirizzare il traffico senza downtime, semplicemente spostando gli host e aggiungendo le registrazioni appropriate in Nginx. <\/p>\n<p><\/p>\n<p>Dopo che il traffico \u00e8 stato reindirizzato, Nginx e l'API di Icebox potevano essere rimossi.<br \/>\nPoi abbiamo rimosso Icebox nginx e S3 API \u2014 e tutto ha iniziato a funzionare:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/62d9f960fc1f11b875a8f8a5aa8e8152.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Successivamente abbiamo avviato un processo di migrazione in background che lavora all'interno del database \u2014 analizza progetto per progetto e i loro bucket, imposta il segno Migrating per loro, trasferisce i dati e, al termine del trasferimento, imposta il segno Local.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/1a3129136f7ccacfdcff260f10cb0605.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dopo il trasferimento dei dati, non abbiamo pi\u00f9 bisogno del vecchio storage, e rimuoviamo le parti rimanenti del vecchio sistema, oltre a rimuovere dal codice il supporto per lo stato di migrazione.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage\" src=\"\/wp-content\/uploads\/2020\/08\/13b6f11add40c21a3b9afc05dd0dfea9.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Con gli stessi principi \u00e8 stata effettuata anche la rishardizzazione dallo storage vecchio a quello shardato:<\/p>\n<p><\/p>\n<ul>\n<li>Abbiamo contrassegnato tutti i bucket come <code>Non-sharded<\/code>. Tutte le richieste a loro andavano nello storage originale, non shardato.<\/li>\n<li>I nuovi bucket venivano creati immediatamente con stato <code>Sharded<\/code>.<\/li>\n<li>Prendevamo i bucket uno per uno, impostavamo lo stato <code>Migrating<\/code> e trasferivamo i dati.<\/li>\n<\/ul>\n<p><\/p>\n<p>Le richieste venivano servite secondo il principio:<\/p>\n<p><\/p>\n<ul>\n<li>Leggiamo nel nuovo, poi nel vecchio.<\/li>\n<li>Creiamo solo nel nuovo.<\/li>\n<li>Aggiorniamo in due fasi: se non c'\u00e8 nel nuovo, trasferiamo dal vecchio al nuovo, poi aggiorniamo.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"rabota-s-ssl-sertifikatami\">Lavorare con i certificati SSL<\/h2>\n<p><\/p>\n<blockquote><p>Nel front-end utilizziamo Nginx. Nel nostro caso non si tratta di un normale Nginx, ma di OpenResty, Nginx con supporto per LuaJIT.<\/p><\/blockquote>\n<p>Un altro pezzo del sistema \u00e8 il lavoro con i certificati SSL. Nel storage S3 puoi impostare un dominio personalizzato per l'accesso a un particolare bucket, semplicemente utilizzando <code>CNAME<\/code>. Ma senza HTTPS al giorno d'oggi non \u00e8 possibile: un dominio personalizzato implica un certificato SSL personale. <\/p>\n<p><\/p>\n<p>Come ho gi\u00e0 detto, Nginx \u00e8 responsabile del bilanciamento e della terminazione SSL. Nel nostro caso non si tratta di un normale Nginx, ma di OpenResty, Nginx con supporto per LuaJIT.<\/p>\n<p><\/p>\n<p>Questo ci ha permesso di insegnare al nostro Nginx a fornire certificati arbitrari in modo abbastanza semplice. Inoltre, avevamo bisogno di fornire certificati dinamicamente (senza la necessit\u00e0 di registrarli nel file di configurazione). Abbiamo utilizzato l'estensione <code>ssl_certificate_by_lua<\/code>, che consente di leggere il certificato da una fonte arbitraria direttamente durante il handshake TLS. Come deposito di certificati abbiamo anche utilizzato Tarantool: questo consente di gestire i certificati esternamente e garantisce una resa estremamente rapida.<\/p>\n<p><\/p>\n<p>\u00c8 stato anche implementato un demone separato, il cui compito \u00e8 quello di aggiornare regolarmente i certificati rilasciati tramite Let's Encrypt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Architettura S3: 3 anni di evoluzione di 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\">Cosa salverei e cosa farei diversamente se sviluppassi il sistema di storage da zero<\/h2>\n<p><\/p>\n<h3 id=\"chto-nuzhno-bylo-ispolzovat-s-samogo-nachala\">Cosa sarebbe stato necessario utilizzare fin dall'inizio<\/h3>\n<p><\/p>\n<p><strong>Sharding immediato<\/strong>. Ha causato parecchi problemi il re-sharding. \u00c8 facile da implementare, ma, se si avviano progetti che necessitano di scalabilit\u00e0, \u00e8 meglio iniziare subito con un cluster sharded, anche se con un numero minimo di nodi. L'implementazione dello sharding all'inizio \u00e8 quasi gratuita rispetto all'integrazione dello sharding in un sistema esistente.<\/p>\n<p><\/p>\n<p><strong>Lavorare con Tarantool tramite bilanciatori<\/strong>. Attualmente colleghiamo subito tutti i nuovi database attraverso i bilanciatori. Questo ci consente di espandere la funzionalit\u00e0 e ottenere una maggiore resilienza. <\/p>\n<p><\/p>\n<p><strong>Auto-failover<\/strong>. Avrei installato tutti gli strumenti necessari per l'auto-failover, poich\u00e9 i primi fallimenti dopo il lancio erano legati alla sua assenza. Dopo l'esperienza con S3, tutti i prodotti successivi sono stati avviati tenendo conto di questo.<\/p>\n<p><\/p>\n<p><strong>Funzionalit\u00e0 S3 \u00abVersioning\u00bb<\/strong>. Inizialmente sembrava che non fosse una funzionalit\u00e0 molto richiesta. Integrare questa possibilit\u00e0 nell'architettura di un sistema esistente \u00e8 estremamente complicato.<\/p>\n<p><\/p>\n<p><strong>Fatturazione separata<\/strong>. Il modo in cui abbiamo integrato la fatturazione nel nostro sistema ha funzionato bene all'inizio, ma in seguito \u00e8 diventato un ostacolo; sarebbe stato meglio impostarla come un servizio completamente separato.<\/p>\n<p><\/p>\n<h3 id=\"chto-bylo-udachnym-resheniem\">Cosa \u00e8 stata una decisione riuscita<\/h3>\n<p><\/p>\n<p><strong>Modello dei dati<\/strong>. La storia ha dimostrato che durante lo sviluppo del servizio ci allineiamo abbastanza precisamente con il modello di dati di Amazon, quindi possiamo implementare le funzionalit\u00e0 presenti l\u00ec.<\/p>\n<p><\/p>\n<p><strong>Schema di sharding<\/strong>. Sosterrei gli stessi sharding a intervallo per i bucket, poich\u00e9 questo consente di distribuire bene le richieste tra diversi bucket su un grande cluster.<\/p>\n<p><\/p>\n<p><strong>Uso di Tarantool<\/strong>. Tarantool ha dato un grande supporto durante lo sviluppo e la modifica del servizio; abbiamo lavorato facilmente con i dati, trasformato e shardato lo storage senza dover salire al livello dell'applicazione. <\/p>\n<p><\/p>\n<blockquote><p>Questa presentazione \u00e8 stata pronunciata per la prima volta a <noindex><a rel=\"nofollow\" href=\"https:\/\/corp.mail.ru\/ru\/press\/events\/databases-2\/\">@Databases Meetup<\/a><\/noindex> da Mail.ru Cloud Solutions&amp;Tarantool. Vedi <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=jM4hL2u6JM0&amp;list=PLQzTaxmOHjntyNRPWhaWHqlHp8UN_wgQ3\">video<\/a><\/noindex> altre presentazioni e iscriviti agli annunci di eventi su Telegram <noindex><a rel=\"nofollow\" href=\"https:\/\/t.me\/k8s_mail\">Attorno a Kubernetes in Mail.ru Group<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Puoi anche guardare la mia vecchia presentazione su S3 o leggere l'articolo del mio collega sullo storage a blocchi.<\/p>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=O0iIADHgBVc\">Reverse engineering dell'architettura di Amazon S3 e com'era lo storage S3 di MCS 3 anni fa<\/a><\/noindex>.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/472694\/\">Pi\u00f9 di Ceph: archiviazione su cloud MCS<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>Fonte: <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.1.1 - 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\/it\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\udd47Architettura S3: 3 anni di evoluzione di Mail.ru Cloud Storage | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/arhitektura-s3-3-goda-evolyuczii-mail-ru-cloud-storage","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/91090","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=91090"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/91090\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/91091"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=91090"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=91090"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=91090"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}