{"id":84114,"date":"2020-06-05T07:42:55","date_gmt":"2020-06-05T05:42:55","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah"},"modified":"2020-06-05T07:42:55","modified_gmt":"2020-06-05T05:42:55","slug":"one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","title":{"rendered":"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/fa983acacec59ff2d4ed098f87223971.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aloha, gente! Mi chiamo Oleg Anastasyev e lavoro in Odnoklassniki nel team della Piattaforma. Inoltre, in Odnoklassniki c'\u00e8 un sacco di hardware. Abbiamo quattro datacenter, con circa 500 rack e oltre 8.000 server. Ad un certo punto abbiamo capito che implementare un nuovo sistema di gestione ci avrebbe permesso di utilizzare la tecnologia in modo pi\u00f9 efficiente, semplificando la gestione degli accessi, automatizzando la (ri)distribuzione delle risorse computazionali, accelerando il lancio di nuovi servizi e migliorando la risposta alle grandi emergenze. <\/p>\n<p><\/p>\n<p>Cosa \u00e8 venuto fuori da tutto ci\u00f2? <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Oltre a me e a un sacco di hardware, ci sono anche delle persone che lavorano con questo hardware: ingegneri che si trovano direttamente nei datacenter; network engineer che configurano l'infrastruttura di rete; amministratori, o SRE, che garantiscono la resilienza dell'infrastruttura; e team di sviluppatori, ciascuno responsabile di una parte delle funzionalit\u00e0 del portale. Il software che sviluppano funziona cos\u00ec:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/592fd0acfa7322eb80fbb85601a92918.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Le richieste degli utenti arrivano sia ai front-end del portale principale <noindex><a rel=\"nofollow\" href=\"http:\/\/www.ok.ru\/\">www.ok.ru<\/a><\/noindex>, sia ad altri, come ai front-end dell'API musicale. Per gestire la logica di business, richiamano il server delle applicazioni, che durante il trattamento della richiesta chiama i necessari microservizi specializzati: one-graph (grafico delle relazioni sociali), user-cache (cache dei profili utente) e cos\u00ec via.<\/p>\n<p><\/p>\n<p>Ciascuno di questi servizi \u00e8 distribuito su molte macchine, ed ognuno ha sviluppatori responsabili che si occupano del funzionamento dei moduli, della loro gestione e dello sviluppo tecnologico. Tutti questi servizi sono eseguiti su server fisici e, fino a poco tempo fa, eseguivamo esattamente un task per server, cio\u00e8 era specializzato per un compito specifico.<\/p>\n<p><\/p>\n<p>Perch\u00e9 \u00e8 cos\u00ec? Questo approccio ha avuto diversi vantaggi:<\/p>\n<p><\/p>\n<ul>\n<li>Facilita <strong>la gestione massiva<\/strong>. Supponiamo che un task richieda determinate librerie, determinate configurazioni. In tal caso, il server \u00e8 assegnato a un gruppo specifico, viene descritta una politica cfengine per quel gruppo (o \u00e8 gi\u00e0 stata descritta) e questa configurazione viene distribuita centralmente e automaticamente su tutti i server di quel gruppo.<\/li>\n<li>Semplifica <strong>la diagnosi<\/strong>. Supponiamo che tu stia esaminando un carico elevato della CPU e capisci che quel carico potrebbe essere generato solo dal task che gira su quella CPU fisica. La ricerca del colpevole termina molto rapidamente.<\/li>\n<li>Semplifica <strong>monitoraggio<\/strong>. Se c'\u00e8 qualcosa che non va con il server, il monitor lo segnala e sai esattamente chi \u00e8 il colpevole.<\/li>\n<\/ul>\n<p><\/p>\n<p>A un servizio composto da pi\u00f9 repliche, vengono assegnati pi\u00f9 server \u2014 uno per ciascuna. Allora, la risorsa computazionale per il servizio \u00e8 molto semplice da distribuire: quante pi\u00f9 server ha, tanto pi\u00f9 risorse pu\u00f2 consumare. \"Semplice\" non significa che sia facile da utilizzare, ma che la distribuzione delle risorse avviene manualmente.<\/p>\n<p><\/p>\n<p>Questo approccio ci ha anche permesso di creare <strong>configurazioni hardware specializzate<\/strong> per il compito che viene eseguito su quel server. Se un task deve gestire grandi volumi di dati, utilizziamo server 4U con chassis per 38 dischi. Se \u00e8 un task puramente computazionale, possiamo acquistare un server 1U pi\u00f9 economico. Questo \u00e8 efficace in termini di risorse computazionali. Questo approccio ci consente di utilizzare quattro volte meno macchine con un carico paragonabile a quello di una rete sociale amica. <\/p>\n<p><\/p>\n<p>Tale efficienza nell'uso delle risorse computazionali dovrebbe garantire anche efficienza economica, partendo dal presupposto che ci\u00f2 che costa di pi\u00f9 sono i server. A lungo, l'hardware \u00e8 stato il costo maggiore e abbiamo investito molto sforzo per ridurre il prezzo dell'hardware, ideando algoritmi per garantire la resilienza e abbassare i requisiti di affidabilit\u00e0 dell'hardware. Oggi siamo arrivati a un punto in cui il prezzo del server non \u00e8 pi\u00f9 determinante. A meno che non si consideri l'ultima esotica, la configurazione specifica dei server nel rack non ha importanza. Ora abbiamo un altro problema: il costo dello spazio occupato dal server nel datacenter, cio\u00e8 dello spazio nel rack.<\/p>\n<p><\/p>\n<p>Rendendoci conto di questo, abbiamo deciso di calcolare quanto efficacemente utilizziamo i rack.<br \/>\nAbbiamo preso il prezzo del server pi\u00f9 potente tra quelli economicamente giustificati, calcolato quanti di questi server possiamo inserire negli armadi, quante attivit\u00e0 potremmo avviare su di essi, seguendo il vecchio modello \"un server = un'attivit\u00e0\", e quanto queste attivit\u00e0 potrebbero sfruttare l'hardware. Abbiamo fatto i conti e ci siamo commossi. \u00c8 emerso che l'efficienza dell'utilizzo degli armadi \u00e8 circa dell'11%. La conclusione \u00e8 chiara: \u00e8 necessario aumentare l'efficacia nell'uso dei data center. Sembrerebbe che la soluzione sia ovvia: dovremmo eseguire pi\u00f9 attivit\u00e0 su un singolo server. Ma qui iniziano le complicazioni. <\/p>\n<p><\/p>\n<p>La configurazione massiva diventa di colpo molto pi\u00f9 complessa \u2014 ora non \u00e8 possibile assegnare un gruppo unico a un server. Infatti, ora su un singolo server possono essere eseguite pi\u00f9 attivit\u00e0 di diversi team. Inoltre, la configurazione pu\u00f2 essere in conflitto con diverse applicazioni. Anche la diagnostica diventa pi\u00f9 complicata: se si osserva un consumo elevato delle CPU o dei dischi su un server, non si sa quale delle attivit\u00e0 sta causando problemi.<\/p>\n<p><\/p>\n<p>Ma la cosa principale \u00e8 che non c'\u00e8 isolamento tra le attivit\u00e0 eseguite su una stessa macchina. Ecco, ad esempio, un grafico che mostra il tempo medio di risposta di un'attivit\u00e0 server prima e dopo che su quello stesso server \u00e8 stata avviata un'altra applicazione di calcolo non correlata alla prima \u2014 il tempo di risposta per l'attivit\u00e0 principale \u00e8 aumentato notevolmente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/c7c07359ae572ca8c84a4c63559e4083.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00c8 chiaro che \u00e8 necessario eseguire le attivit\u00e0 in contenitori o in macchine virtuali. Poich\u00e9 praticamente tutte le attivit\u00e0 vengono eseguite con un unico sistema operativo (Linux) o sono adatte per esso, non \u00e8 necessario mantenere molti sistemi operativi diversi. Di conseguenza, la virtualizzazione non \u00e8 necessaria e, a causa dei costi aggiuntivi, sar\u00e0 meno efficiente rispetto alla containerizzazione.<\/p>\n<p><\/p>\n<p>Come implementazione dei contenitori per eseguire le attivit\u00e0 direttamente sui server, Docker \u00e8 un buon candidato: le immagini dei file system risolvono bene i problemi di conflitti di configurazione. Il fatto che le immagini possano essere composte da pi\u00f9 strati ci consente di ridurre notevolmente la quantit\u00e0 di dati necessari per la loro distribuzione nell'infrastruttura, separando le parti comuni in strati di base distinti. In questo modo, gli strati di base (e i pi\u00f9 voluminosi) verranno memorizzati nella cache rapidamente su tutta l'infrastruttura e per distribuire molti tipi diversi di applicazioni e versioni sar\u00e0 necessario trasferire solo strati di piccole dimensioni. <\/p>\n<p><\/p>\n<p>Inoltre, il registro pronto e il tagging delle immagini in Docker ci offrono meccanismi pronti per la versioning e la distribuzione del codice in produzione.<\/p>\n<p><\/p>\n<p>Docker, come qualsiasi altra tecnologia simile, ci fornisce un certo livello di isolamento dei contenitori out of the box. Ad esempio, l'isolamento della memoria \u2014 a ogni contenitore viene assegnato un limite sull'uso della memoria del server, oltre il quale non pu\u00f2 consumarla. \u00c8 inoltre possibile isolare i contenitori per quanto riguarda l'uso della CPU. Per noi, per\u00f2, l'isolamento standard non era sufficiente. Ma ne parleremo pi\u00f9 avanti.<\/p>\n<p><\/p>\n<p>L'avvio diretto dei contenitori sui server \u00e8 solo una parte dei problemi. L'altra parte riguarda la collocazione dei contenitori sui server. \u00c8 necessario comprendere quale contenitore pu\u00f2 essere posizionato su quale server. Non \u00e8 affatto un compito semplice, perch\u00e9 i contenitori devono essere collocati sui server in modo il pi\u00f9 denso possibile senza compromettere le loro prestazioni. Tale collocazione pu\u00f2 essere complessa anche in termini di resilienza. Spesso vogliamo collocare le repliche dello stesso servizio in rack diversi o persino in sale di data center diverse, in modo da non perdere tutte le repliche del servizio in caso di guasti. <\/p>\n<p><\/p>\n<p>Distribuire i contenitori manualmente non \u00e8 un'opzione quando hai 8.000 server e 8.000-16.000 contenitori. <\/p>\n<p><\/p>\n<p>Inoltre, volevamo dare agli sviluppatori maggiore autonomia nella distribuzione delle risorse, affinch\u00e9 potessero collocare autonomamente i loro servizi in produzione, senza l'assistenza di un amministratore. Nel contempo, volevamo mantenere il controllo in modo che qualche servizio secondario non consumasse tutte le risorse dei nostri data center. <\/p>\n<p><\/p>\n<p>\u00c8 chiaro che \u00e8 necessario uno strato di gestione che si occupi di questo in modo automatico.<\/p>\n<p><\/p>\n<p>Ed ecco che arriviamo a un'immagine semplice e chiara che tutti gli architetti adorano: tre quadrati. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/079df6e79874ef55b0d967fde3d5feca.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>one-cloud masters \u2014 un cluster tollerante ai guasti che si occupa dell'orchestrazione del cloud. Lo sviluppatore invia al master un manifesto contenente tutte le informazioni necessarie per il \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435 del servizio. Sulla base di queste informazioni, il master invia comandi ai minion selezionati (macchine destinate a eseguire i container). Su queste macchine \u00e8 presente il nostro agente, che riceve il comando, invia i propri comandi a Docker e Docker configura il kernel Linux per avviare il container corrispondente. Oltre all'esecuzione dei comandi, l'agente informa continuamente il master sui cambiamenti di stato sia della macchina-minion che dei container eseguiti su di essa.<\/p>\n<p><\/p>\n<h2 id=\"raspredelenie-resursov\">Distribuzione delle risorse<\/h2>\n<p><\/p>\n<p>Analizziamo ora la questione di una distribuzione pi\u00f9 complessa delle risorse per molti minion.<\/p>\n<p><\/p>\n<p>La risorsa computazionale in one-cloud \u00e8:<\/p>\n<p><\/p>\n<ul>\n<li>La potenza di elaborazione della CPU consumata da un compito specifico. <\/li>\n<li>La quantit\u00e0 di memoria disponibile per il compito. <\/li>\n<li>Traffico di rete. Ognuno dei minion ha una specifica interfaccia di rete con una larghezza di banda limitata, quindi non \u00e8 possibile distribuire compiti senza tenere conto del volume di dati trasmessi in rete. <\/li>\n<li>Dischi. Oltre, ovviamente, allo spazio per i dati del compito, definiamo anche il tipo di disco: HDD o SSD. I dischi possono gestire un numero finale di richieste al secondo \u2014 IOPS. Pertanto, per compiti che generano pi\u00f9 IOPS di quanto un singolo disco possa gestire, riserviamo anche \"spindles\" \u2014 cio\u00e8 dispositivi di archiviazione che devono essere esclusivamente riservati per il compito.<\/li>\n<\/ul>\n<p><\/p>\n<p>Quindi, per un servizio come user-cache, possiamo registrare le risorse consumate in questo modo: 400 core CPU, 2,5 TB di memoria, 50 Gbps di traffico in entrambe le direzioni, 6 TB di spazio su HDD, distribuito su 100 spindles. O in una forma a noi pi\u00f9 familiare cos\u00ec:<\/p>\n<p><\/p>\n<pre><code>alloc:\n    cpu: 400\n    mem: 2500\n    lan_in: 50g\n    lan_out: 50g\n    hdd:100x6T<\/code><\/pre>\n<p><\/p>\n<p>Le risorse del servizio user-cache consumano solo una parte di tutte le risorse disponibili nell'infrastruttura di produzione. Pertanto, vogliamo assicurarci che, improvvisamente, a causa di un errore dell'operatore o meno, user-cache non consumi pi\u00f9 risorse di quelle assegnate. Dobbiamo quindi limitare le risorse. Ma a cosa potremmo legare la quota?<\/p>\n<p><\/p>\n<p>Torniamo al nostro schema semplificato di interazione dei componenti e ridisegniamolo con pi\u00f9 dettagli \u2014 cos\u00ec: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/27e5bfbffadd3d4b9fdc6bf138d135ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Cosa salta all'occhio:<\/p>\n<p><\/p>\n<ul>\n<li>Il front-end web e la musica utilizzano cluster isolati dello stesso server applicativo.<\/li>\n<li>Possiamo definire livelli logici, ai quali appartengono questi cluster: front-end, cache, livello di archiviazione e gestione dei dati.<\/li>\n<li>Il front-end non \u00e8 omogeneo, \u00e8 composto da diverse sottosistemi funzionali. <\/li>\n<li>Le cache possono essere distribuite tra le sottosistemi i cui dati stanno memorizzando.<\/li>\n<\/ul>\n<p><\/p>\n<p>Ridisegniamo di nuovo l'immagine:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/905dacc0aca859e65bd33ef751a557cf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ehi! Qui vediamo una gerarchia! Ci\u00f2 significa che possiamo distribuire le risorse in pezzi pi\u00f9 grandi: assegnare uno sviluppatore responsabile a un nodo di questa gerarchia, corrispondente al sottosistema funzionale (come \u201cmusic\u201d nell'immagine), e legare la quota a questo stesso livello di gerarchia. Tale gerarchia ci consente anche di organizzare i servizi in modo pi\u00f9 flessibile per la comodit\u00e0 della gestione. Ad esempio, tutto il web, poich\u00e9 \u00e8 un raggruppamento di server molto grande, lo suddividiamo in gruppi pi\u00f9 piccoli, mostrati nell'immagine come group1, group2.<\/p>\n<p><\/p>\n<p>Eliminando le linee superflue, possiamo rappresentare ogni nodo della nostra immagine in modo pi\u00f9 piatto: <strong>group1.web.front<\/strong>, <strong>api.music.front<\/strong>, <strong>user-cache.cache<\/strong>.<\/p>\n<p><\/p>\n<p>Cos\u00ec arriviamo al concetto di \"coda gerarchica\". Essa ha un nome, come \"group1.web.front\". Le viene assegnata una quota di risorse e diritti per gli utenti. A una persona del DevOps daremo diritti per inviare servizi nella coda, e questo dipendente pu\u00f2 avviare qualcosa nella coda, mentre a una persona di OpsDev verranno dati diritti di amministratore, e ora pu\u00f2 gestire la coda, designare persone a essa, assegnare diritti a queste persone, ecc. I servizi avviati in questa coda verranno eseguiti nel rispetto della quota della coda. Se la quota computazionale della coda non \u00e8 sufficiente per eseguire simultaneamente tutti i servizi, allora essi verranno eseguiti in sequenza, formando in tal modo la propria coda. <\/p>\n<p><\/p>\n<p>Esaminiamo i servizi in dettaglio. Ogni servizio ha un nome completo, che include sempre il nome della coda. Quindi il servizio del front-end web avr\u00e0 il nome <strong>ok-web.group1.web.front<\/strong>. Mentre il servizio del server applicativo a cui si rivolge avr\u00e0 il nome <strong>ok-app.group1.web.front<\/strong>. Ogni servizio ha un manifesto che indica tutte le informazioni necessarie per il deploy su macchine specifiche: quante risorse consuma questo compito, quale configurazione \u00e8 necessaria, quante repliche devono esserci, le propriet\u00e0 per la gestione dei guasti di questo servizio. Dopo aver distribuito il servizio sulle macchine, appaiono le sue istanze. Anche queste sono denominate in modo univoco - come numero dell'istanza e nome del servizio: <strong>1.ok-web.group1.web.front, 2.ok-web.group1.web.front, \u2026<\/strong><\/p>\n<p><\/p>\n<p>Questo \u00e8 molto comodo: guardando solo al nome del container in esecuzione, possiamo immediatamente scoprire molte cose.<\/p>\n<p><\/p>\n<p>E ora conosciamo meglio cosa fanno effettivamente queste istanze: i compiti.<\/p>\n<p><\/p>\n<h2 id=\"klassy-izolyacii-zadach\">Classi di isolamento dei compiti<\/h2>\n<p><\/p>\n<p>Tutti i compiti in OK (e probabilmente ovunque) possono essere suddivisi in gruppi:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Compiti a bassa latenza \u2014 prod<\/strong>. Per tali compiti e servizi, \u00e8 molto importante la latenza della risposta, ovvero quanto velocemente ciascuna richiesta sar\u00e0 elaborata dal sistema. Esempi di compiti: front-end web, cache, server di applicazioni, archivi OLTP e cos\u00ec via.<\/li>\n<li><strong>Compiti di calcolo \u2014 batch<\/strong>. Qui la velocit\u00e0 di elaborazione di ciascuna richiesta specifica non \u00e8 fondamentale. \u00c8 importante, invece, quanti calcoli totali vengono effettuati in un determinato (grande) intervallo di tempo (throughput). Questi includono compiti di MapReduce, Hadoop, apprendimento automatico, statistica.<\/li>\n<li><strong>Compiti in background \u2014 idle<\/strong>. Per questi compiti, n\u00e9 la latenza n\u00e9 il throughput sono particolarmente importanti. Qui rientrano vari test, migrazioni, ricalcoli, conversioni di dati da un formato all'altro. Da un lato, assomigliano ai compiti di calcolo, dall'altro, non ci importa molto quanto velocemente si completano. <\/li>\n<\/ul>\n<p><\/p>\n<p>Vediamo come questi compiti consumano risorse, ad esempio, della CPU.<\/p>\n<p><\/p>\n<p><strong>Compiti a bassa latenza.<\/strong> Il modello di consumo della CPU per tale compito sar\u00e0 simile a questo:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/1ed82c0df76325eb30056ad9af86e86e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Arriva una richiesta dall'utente, il compito inizia a utilizzare tutti i core disponibili della CPU, elabora, restituisce una risposta, attende la prossima richiesta e si ferma. Arriva una nuova richiesta \u2014 di nuovo sfrutta tutto quello che ha, elabora, aspettiamo la prossima.<\/p>\n<p><\/p>\n<p>Per garantire una latenza minima per tale compito, dobbiamo prendere il massimo delle risorse che consuma e riservare il numero necessario di core sulla macchina minion (macchina che eseguir\u00e0 il compito). Quindi la formula di riservazione per il nostro compito sar\u00e0:<\/p>\n<p><\/p>\n<pre><code>alloc: cpu = 4 (max)<\/code><\/pre>\n<p><\/p>\n<p>e se abbiamo una macchina minion con 16 core, possiamo allocare esattamente quattro di tali compiti. Si noti che il consumo medio della CPU per tali compiti \u00e8 spesso molto basso \u2014 il che \u00e8 ovvio, poich\u00e9 gran parte del tempo il compito \u00e8 in attesa di una richiesta e non fa nulla.<\/p>\n<p><\/p>\n<p><strong>Compiti di calcolo.<\/strong> Il loro modello sar\u00e0 leggermente diverso:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/35b37fa1d70a137287cafdbfe3bcfc2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Il consumo medio delle risorse della CPU per tali compiti \u00e8 abbastanza elevato. Spesso vogliamo che il compito di calcolo venga eseguito in un determinato tempo, quindi dobbiamo riservare il numero minimo di processori necessari affinch\u00e9 l'intero calcolo si completi in un tempo accettabile. La formula di riservazione sar\u00e0:<\/p>\n<p><\/p>\n<pre><code>alloc: cpu = [1,*)<\/code><\/pre>\n<p><\/p>\n<p><em>\"Per favore, allocane uno su una macchina minion dove ci sia almeno un core libero, e poi utilizza tutto il resto disponibile.\"<\/em><\/p>\n<p><\/p>\n<p>Qui l'efficienza dell'uso \u00e8 gi\u00e0 significativamente migliore rispetto ai compiti a bassa latenza. Ma il guadagno sar\u00e0 molto maggiore se combiniamo entrambi i tipi di compiti sulla stessa macchina minion e distribuiamo le sue risorse al volo. Quando un compito a bassa latenza richiede la CPU \u2014 la ottiene immediatamente, e quando le risorse non sono pi\u00f9 necessarie \u2014 vengono trasferite al compito di calcolo, cio\u00e8, in questo modo:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/875ad8d3f6a01e4fd0a89d0931e986c1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ma come si fa?<\/p>\n<p><\/p>\n<p>Iniziamo a esaminare prod e il suo alloc: cpu = 4. Dobbiamo riservare quattro core. In Docker run, possiamo farlo in due modi: <\/p>\n<p><\/p>\n<ul>\n<li>Utilizzando l'opzione <code>--cpuset=1-4<\/code>, cio\u00e8 riservare al compito quattro core specifici sulla macchina.<\/li>\n<li>Usa <code>--cpuquota=400_000 --cpuperiod=100_000<\/code>, assegnare una quota di tempo di CPU, ovvero indicare che ogni 100 ms di tempo reale il compito consuma non pi\u00f9 di 400 ms di tempo di CPU. Diventano gli stessi quattro core. <\/li>\n<\/ul>\n<p><\/p>\n<p>Ma quale di questi metodi sar\u00e0 adatto?<\/p>\n<p><\/p>\n<p>Il cpuset sembra piuttosto allettante. La macchina ha quattro core dedicati, il che significa che le cache del processore funzioneranno al massimo dell'efficienza. Questo ha anche un rovescio della medaglia: dovremmo prenderci la responsabilit\u00e0 di distribuire i calcoli sui core meno occupati della macchina anzich\u00e9 farlo gestire al sistema operativo, ed \u00e8 un compito piuttosto complesso, specialmente se proviamo a gestire lavori batch su una macchina del genere. I test hanno dimostrato che qui \u00e8 pi\u00f9 adatta l'opzione con la quota: in questo modo il sistema operativo ha maggiore libert\u00e0 nella scelta del core da utilizzare per l'esecuzione del compito in quel momento e il tempo di CPU viene distribuito in modo pi\u00f9 efficace.<\/p>\n<p><\/p>\n<p>Facciamo chiarezza su come effettuare la prenotazione di un numero minimo di core in Docker. La quota per i lavori batch non \u00e8 pi\u00f9 applicabile, perch\u00e9 non \u00e8 necessario limitare un massimo, \u00e8 sufficiente garantire solo un minimo. Qui l'opzione che si adatta bene \u00e8 <code>docker run --cpushares<\/code>.<\/p>\n<p><\/p>\n<p>Ci siamo accordati che se un lavoro batch richiede la garanzia di un minimo su un core, allora specifichiamo <code>--cpushares=1024<\/code>, e se \u00e8 necessario un minimo su due core, allora specifichiamo <code>--cpushares=2048<\/code>. I cpu shares non interferiscono nella distribuzione del tempo di CPU finch\u00e9 ce n'\u00e8 a sufficienza. Cos\u00ec, se il prod non sta utilizzando nel momento attuale tutti e quattro i suoi core, non ci sono limitazioni per i lavori batch, e possono utilizzare tempo di CPU aggiuntivo. Tuttavia, in caso di scarsit\u00e0 di CPU, se il prod ha consumato tutti e quattro i suoi core e ha raggiunto la quota, il tempo di CPU rimanente verr\u00e0 suddiviso in proporzione ai cpushares, cio\u00e8, in una situazione di tre core liberi, uno ricever\u00e0 il lavoro con 1024 cpushares, mentre gli altri due riceveranno il lavoro con 2048 cpushares.<\/p>\n<p><\/p>\n<p>Ma l'uso di quota e shares non \u00e8 sufficiente. Abbiamo bisogno di garantire che i compiti con bassa latenza ottengano priorit\u00e0 rispetto ai lavori batch nella distribuzione del tempo di CPU. Senza tale prioritizzazione, i lavori batch occuperanno tutto il tempo di CPU quando \u00e8 necessario al prod. In Docker run non ci sono opzioni per la prioritizzazione dei container, ma le politiche dello scheduler della CPU in Linux ci vengono in aiuto. Potete leggere in dettaglio su di esse <noindex><a rel=\"nofollow\" href=\"http:\/\/man7.org\/linux\/man-pages\/man2\/sched_setscheduler.2.html\">qui<\/a><\/noindex>, e in questo articolo daremo un'occhiata a breve:<\/p>\n<p><\/p>\n<ul>\n<li><strong>SCHED_OTHER<\/strong><br \/>\nDi default, vengono assegnati a tutti i normali processi utente su una macchina Linux.<\/li>\n<li><strong>SCHED_BATCH<\/strong><br \/>\n\u00c8 destinata a processi che consumano molte risorse. Quando un lavoro viene collocato nella CPU, viene introdotta una cos\u00ec detta penalit\u00e0 di attivazione: tale lavoro avr\u00e0 meno probabilit\u00e0 di ottenere risorse della CPU se al momento viene utilizzato da un processo con SCHED_OTHER.<\/li>\n<li><strong>SCHED_IDLE<\/strong><br \/>\n\u00c8 un processo in background con priorit\u00e0 molto bassa, anche inferiore a nice -19. Utilizziamo la nostra libreria open-source <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/odnoklassniki\/one-nio\">one-nio<\/a><\/noindex>, per impostare la politica necessaria all'avvio del container chiamando<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"java\">one.nio.os.Proc.sched_setscheduler( pid, Proc.SCHED_IDLE )<\/code><\/pre>\n<p><\/p>\n<p>. Ma anche se non programmi in Java, puoi fare lo stesso usando il comando chrt:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">chrt -i 0 $pid<\/code><\/pre>\n<p><\/p>\n<p>Riassumiamo tutti i nostri livelli di isolamento in una tabella per chiarezza:<\/p>\n<p><\/p>\n<p>Classe di isolamento<br \/>\nEsempio alloc<br \/>\nOpzioni Docker run<br \/>\nsched_setscheduler chrt*<\/p>\n<p>Prod<br \/>\ncpu = 4<br \/>\n<code>--cpuquota=400000<\/code> <code>--cpuperiod=100000<\/code><br \/>\nSCHED_OTHER<\/p>\n<p>Batch<br \/>\nCpu = [1, * )<br \/>\n<code>--cpushares=1024<\/code><br \/>\nSCHED_BATCH<\/p>\n<p>Idle<br \/>\nCpu= [2, *)<br \/>\n<code>--cpushares=2048<\/code><br \/>\nSCHED_IDLE<\/p>\n<p><\/p>\n<p>*Se esegui chrt dall'interno del container, potrebbe essere necessario il capability sys_nice, perch\u00e9 di default Docker rimuove questo capability all'avvio del container.<\/p>\n<p><\/p>\n<p>Ma i lavori non consumano solo CPU, ma anche traffico, che influisce maggiormente sulla latenza della task di rete rispetto a una distribuzione errata delle risorse CPU. Per questo motivo, naturalmente, vogliamo avere un quadro simile anche per il traffico. Vale a dire, quando il lavoro prod invia dei pacchetti in rete, limitiamo la velocit\u00e0 massima (formula <em>alloc: lan=[*,500mbps)<\/em> ), con cui il prod pu\u00f2 farlo. E per il batch garantiamo solo una larghezza di banda minima, ma non limitiamo la massima (formula <em>alloc: lan=[10Mbps,*)<\/em> ) In questo modo, il traffico del prod deve avere priorit\u00e0 rispetto ai lavori batch.<br \/>\nQui Docker non ha alcun primitivo che possiamo utilizzare. Ma ci viene in aiuto <noindex><a rel=\"nofollow\" href=\"http:\/\/lartc.org\/\">Linux Traffic Control<\/a><\/noindex>. Siamo riusciti a ottenere il risultato desiderato utilizzando la disciplina <noindex><a rel=\"nofollow\" href=\"http:\/\/linux-ip.net\/articles\/hfsc.en\/\">Hierarchical Fair Service Curve<\/a><\/noindex>. Con essa, classifichiamo due classi di traffico: alta priorit\u00e0 per il prod e bassa priorit\u00e0 per il batch\/idle. Alla fine, la configurazione per il traffico in uscita risulta essere la seguente:<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/gh\/5k\/kf\/gh5kkfwkhwv0ilmbdmdbo83dp6k.png\"><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/3f52a968118b6021bd0c920af17a00c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<p>qui 1:0 \u2014 &#171;qdisc radice&#187; della disciplina hsfc; 1:1 \u2014 classe secondaria hsfc con un limite di larghezza di banda totale di 8 Gbit\/s, sotto il quale si trovano le classi secondarie di tutti i contenitori; 1:2 \u2014 classe secondaria hsfc condivisa per tutti i lavori batch e idle con un limite &#171;dinamico&#187;, di cui si parler\u00e0 pi\u00f9 avanti. Le altre classi secondarie hsfc sono classi dedicate per i contenitori prod attualmente attivi, con limiti corrispondenti ai loro manifesti, pari a 450 e 400 Mbit\/s. A ciascuna classe hsfc \u00e8 assegnata una coda qdisc fq o fq_codel, in base alla versione del kernel linux, per evitare perdite di pacchetti durante i picchi di traffico. <\/p>\n<p><\/p>\n<p>Di solito, le discipline tc servono per dare priorit\u00e0 solo al traffico in uscita. Ma vogliamo dare priorit\u00e0 anche al traffico in entrata \u2014 dato che qualche task batch potrebbe facilmente saturare tutto il canale in entrata, raccogliendo, ad esempio, un grande pacchetto di dati in ingresso per map&amp;reduce. A tal fine utilizziamo il modulo <noindex><a rel=\"nofollow\" href=\"https:\/\/serverfault.com\/questions\/350023\/tc-ingress-policing-and-ifb-mirroring\">ifb<\/a><\/noindex>, che crea un'interfaccia virtuale ifbX per ogni interfaccia di rete e reindirizza il traffico in entrata dall'interfaccia a quello in uscita su ifbX. Successivamente, per ifbX, funzionano tutte le stesse discipline per il controllo del traffico in uscita, per le quali la configurazione hsfc sar\u00e0 molto simile:<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/iz\/ao\/-k\/izao-kgthgu_ptgyq9cjb1il0wm.png\"><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/967da9c0637cc70ba195af781db18adf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<p>Durante gli esperimenti, abbiamo scoperto che i migliori risultati di hsfc si ottengono quando la classe 1:2 del traffico batch\/idle non prioritario viene limitata sui minion a non pi\u00f9 di una certa banda libera. In caso contrario, il traffico non prioritario influisce troppo sulla latenza dei task prod. L'attuale importo della banda libera miniond viene determinato ogni secondo, misurando il consumo medio di traffico da tutti i task prod di quel minion <img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/9d6f38110d3b1693afe222b01430b9bb.jpg\" style=\"display:block;margin: 0 auto;\" \/> e sottraendolo dalla larghezza di banda dell'interfaccia di rete <img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/d5608ec4c58e44b8571ab0b1d0cc7701.jpg\" style=\"display:block;margin: 0 auto;\" \/> con un certo margine, cio\u00e8.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/fb01347c2224bd5bbd82169861eeb7e4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Le bande sono definite separatamente per il traffico in entrata e in uscita. E in base ai nuovi valori, miniond riconfigura il limite per la classe non prioritaria 1:2.<\/p>\n<p><\/p>\n<p>In questo modo, abbiamo implementato tutte e tre le classi di isolamento: prod, batch e idle. Queste classi influenzano notevolmente le prestazioni di esecuzione dei task. Pertanto, abbiamo deciso di posizionare questo attributo in cima all' gerarchia, in modo che, guardando il nome della coda gerarchica, fosse subito chiaro di cosa si trattasse: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/34dc89c461db711b19a0f4eccc50efce.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tutti i nostri noti <strong>web<\/strong> e <strong>music<\/strong> front-end vengono dunque collocati nella gerarchia sotto prod. Per esempio, sotto batch inseriamo il servizio <strong>music catalog<\/strong>, che crea periodicamente un catalogo delle tracce da un insieme di file mp3 caricati su \u00ab\u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0438\u00bb. Un esempio di servizio sotto idle pu\u00f2 essere il <strong>music transformer<\/strong>, che normalizza il livello del volume della musica.<\/p>\n<p><\/p>\n<p>Rimuovendo nuovamente le linee superflue, possiamo scrivere i nomi dei nostri servizi in modo pi\u00f9 piatto, aggiungendo la classe di isolamento del task alla fine del nome completo del servizio: <strong>web.front.prod<\/strong>, <strong>catalog.music.batch<\/strong>, <strong>transformer.music.idle<\/strong>.<\/p>\n<p><\/p>\n<p>E ora, guardando il nome del servizio, possiamo comprendere non solo quale funzione svolga, ma anche la sua classe di isolamento, e di conseguenza, la sua criticit\u00e0, ecc.<\/p>\n<p><\/p>\n<p>Tutto \u00e8 fantastico, ma c'\u00e8 una verit\u00e0 amara. \u00c8 impossibile isolare completamente le attivit\u00e0 che operano su una singola macchina.<\/p>\n<p><\/p>\n<p>Ci\u00f2 che siamo riusciti a ottenere: se un batch consuma intensamente <strong>solo<\/strong> risorse della CPU, allora lo scheduler integrato di CPU Linux svolge molto bene il proprio lavoro, e l'impatto sul task prod \u00e8 praticamente nullo. Ma se quel task batch inizia a lavorare attivamente con la memoria, allora gi\u00e0 si manifesta un'influenza reciproca. Questo accade perch\u00e9 per il task prod vengono \"svuotiti\" i cache processore della memoria \u2014 alla fine, si aumentano i miss nella cache, e la CPU elabora il task prod pi\u00f9 lentamente. Un tale task batch pu\u00f2 aumentare di circa il 10% la latenza del nostro tipico contenitore prod.<\/p>\n<p><\/p>\n<p>Isolare il traffico \u00e8 ancora pi\u00f9 difficile a causa del fatto che le moderne schede di rete hanno una coda interna di pacchetti. Se un pacchetto di un task batch \u00e8 arrivato per primo, significa che sar\u00e0 il primo a essere inviato attraverso il cavo, e non si pu\u00f2 farci nulla.<\/p>\n<p><\/p>\n<p>Inoltre, finora siamo riusciti a risolvere solo l'esigenza di dare priorit\u00e0 al traffico TCP: per l'UDP, l'approccio con hsfc non funziona. E persino nel caso del traffico TCP, se il task batch genera molto traffico, questo comporta ancora circa il 10% di aumento della latenza del task prod.<\/p>\n<p><\/p>\n<h2 id=\"otkazoustoychivost\">Affidabilit\u00e0<\/h2>\n<p><\/p>\n<p>Uno degli obiettivi nello sviluppo di one-cloud era migliorare la resilienza di \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0438. Pertanto, in seguito vorrei esaminare pi\u00f9 dettagliatamente i possibili scenari di guasto e di emergenza. Iniziamo con uno scenario semplice: il guasto di un contenitore. <\/p>\n<p><\/p>\n<p>Il contenitore stesso pu\u00f2 andare in crash in vari modi. Potrebbe trattarsi di un esperimento, un bug o un errore nel manifesto, che porta a far consumare alla job di produzione pi\u00f9 risorse di quelle indicate nel manifesto. Abbiamo avuto un caso: uno sviluppatore ha implementato un algoritmo complesso, lo ha rifatto molte volte, si \u00e8 complicato la vita e si \u00e8 incasinato fino a far s\u00ec che la job si bloccasse in modo piuttosto intricato. E poich\u00e9 la job di produzione ha una priorit\u00e0 maggiore rispetto alle altre sugli stessi nodi, ha iniziato a consumare tutte le risorse disponibili della CPU. In questa situazione, l'isolamento ha salvato la situazione, o meglio, la quota di tempo della CPU. Se alla job \u00e8 assegnata una quota, non consumer\u00e0 di pi\u00f9. Quindi le job batch e altre job di produzione che operavano sulla stessa macchina non se ne sono nemmeno accorte. <\/p>\n<p><\/p>\n<p>Il secondo possibile problema \u00e8 il crash del contenitore. E qui ci salvano le politiche di riavvio, che tutti conoscono, Docker gestisce il tutto perfettamente. Praticamente tutte le job di produzione hanno la politica di riavvio impostata su \u2018always\u2019. A volte utilizziamo \u2018on_failure\u2019 per le job batch o per il debug dei contenitori di produzione.<\/p>\n<p><\/p>\n<p>Cosa si pu\u00f2 fare in caso di indisponibilit\u00e0 di un intero nodo?<\/p>\n<p><\/p>\n<p>Ovviamente, lanciare il contenitore su un'altra macchina. La cosa pi\u00f9 interessante qui \u00e8 cosa succede agli indirizzi IP assegnati al contenitore. <\/p>\n<p><\/p>\n<p>Possiamo assegnare ai contenitori gli stessi indirizzi IP delle macchine nodo su cui questi contenitori vengono eseguiti. Quindi, quando il contenitore viene avviato su un'altra macchina, il suo indirizzo IP cambia, e tutti i clienti devono capire che il contenitore \u00e8 stato trasferito, ora devono puntare a un altro indirizzo, il che richiede un servizio di Service Discovery separato. <\/p>\n<p><\/p>\n<p>La Service Discovery \u00e8 conveniente. Ci sono molte soluzioni sul mercato con vari gradi di tolleranza ai guasti per l'organizzazione di un registro dei servizi. Spesso in tali soluzioni viene implementata la logica di un bilanciatore di carico, la memorizzazione di configurazioni aggiuntive sotto forma di KV-storage, ecc.<br \/>\nTuttavia, vorremmo evitare di dover implementare un registro separato, poich\u00e9 ci\u00f2 significherebbe introdurre un sistema critico utilizzato da tutti i servizi in produzione. Questo significa, quindi, che rappresenta un potenziale punto di guasto, e bisogna scegliere o sviluppare una soluzione molto affidabile, il che \u00e8 ovviamente molto difficile, lungo e costoso. <\/p>\n<p><\/p>\n<p>Un altro grande svantaggio: affinch\u00e9 la nostra vecchia infrastruttura funzionasse con la nuova, sarebbe stato necessario riscrivere assolutamente tutte le job per utilizzare un sistema di Service Discovery. Il lavoro \u00e8 ENORME, e in alcuni casi diventa impossibile, specialmente quando si tratta di dispositivi di basso livello che operano a livello del kernel del sistema operativo o direttamente con l'hardware. Implementare questa funzionalit\u00e0 con modelli di soluzioni consolidati, come ad esempio <noindex><a rel=\"nofollow\" href=\"https:\/\/linkerd.io\">side-car<\/a><\/noindex> significherebbe che in alcune circostanze si avrebbe un carico aggiuntivo, in altre un'ulteriore complessit\u00e0 operativa e scenari di guasto aggiuntivi. Non volevamo complicarci la vita, quindi abbiamo deciso di rendere l'uso della Service Discovery facoltativo. <\/p>\n<p><\/p>\n<p>In one-cloud, l'IP segue il contenitore, cio\u00e8 ogni istanza della job ha il proprio indirizzo IP. Questo indirizzo \u00e8 'statico': viene assegnato a ogni istanza nel momento della prima distribuzione del servizio nel cloud. Se nel corso della vita del servizio ha avuto un numero variabile di istanze, alla fine gli sar\u00e0 assegnato tante IP quante sono state le istanze massime.<\/p>\n<p><\/p>\n<p>Successivamente, questi indirizzi non cambiano: sono assegnati una volta e continuano ad esistere per tutta la vita del servizio in produzione. Gli indirizzi IP seguono i contenitori sulla rete. Se un contenitore viene spostato su un'altra macchina, anche l'indirizzo passer\u00e0 con esso. <\/p>\n<p><\/p>\n<p>In questo modo, l'associazione del nome del servizio con l'elenco dei suoi indirizzi IP cambia molto raramente. Se guardiamo ancora una volta ai nomi delle istanze del servizio che abbiamo menzionato all'inizio dell'articolo (<strong>1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, \u2026<\/strong>), allora noteremo che sembrano FQDN utilizzati in DNS. Ed \u00e8 proprio cos\u00ec, per mostrare i nomi delle istanze dei servizi nei loro indirizzi IP, utilizziamo il protocollo DNS. Inoltre, questo DNS restituisce tutti gli indirizzi IP riservati di tutti i container \u2014 sia in funzione che fermi (supponiamo che siano utilizzate tre repliche e abbiamo cinque indirizzi riservati \u2014 saranno restituiti tutti e cinque). I clienti, ricevendo queste informazioni, tenteranno di stabilire una connessione con tutte e cinque le repliche, determinando cos\u00ec quelle che sono attive. Questo metodo di determinazione della disponibilit\u00e0 \u00e8 significativamente pi\u00f9 affidabile, poich\u00e9 non coinvolge n\u00e9 DNS n\u00e9 Service Discovery, e quindi non ci sono problematiche difficili da risolvere relative alla tempestivit\u00e0 delle informazioni e alla resilienza di questi sistemi. Inoltre, nei servizi critici, da cui dipende il funzionamento dell'intero portale, possiamo non utilizzare affatto il DNS, ma semplicemente configurare gli indirizzi IP.<\/p>\n<p><\/p>\n<p>L'implementazione di questo trasferimento degli IP tra i container pu\u00f2 essere non banale \u2014 ci fermeremo a vedere come funziona nel seguente esempio:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/faf99c2609a57daa1bdc193cb0f4cb31.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Supponiamo che il master one-cloud dia ordine al minion M1 di avviare <strong>1.ok-web.group1.web.front.prod<\/strong> con l'indirizzo 1.1.1.1. Sul minion opera <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Bird_Internet_routing_daemon\">BIRD<\/a><\/noindex>, che annuncia questo indirizzo a server speciali <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Route_reflector\">route reflector<\/a><\/noindex>. Gli ultimi hanno una sessione BGP con l'hardware di rete, a cui viene trasmesso il percorso dell'indirizzo 1.1.1.1 su M1. M1 poi instrada i pacchetti all\u2019interno del container usando i mezzi di Linux. Ci sono tre server route reflector, poich\u00e9 questa \u00e8 una parte molto critica dell'infrastruttura one-cloud \u2014 senza di loro, la rete in one-cloud non funzionerebbe. Li posizioniamo in rack diversi, preferibilmente in diverse sale del data center, per ridurre al minimo la probabilit\u00e0 di un guasto simultaneo di tutti e tre.<\/p>\n<p><\/p>\n<p>Ora supponiamo che la connessione tra il master one-cloud e il minion M1 sia andata persa. Il master one-cloud agir\u00e0 ora presumendo che M1 abbia completamente fallito. Questo significa che dar\u00e0 ordine al minion M2 di avviare <strong>web.group1.web.front.prod<\/strong> con lo stesso indirizzo 1.1.1.1. Ora abbiamo due percorsi conflittuali nella rete per 1.1.1.1: su M1 e su M2. Per risolvere tali conflitti, utilizziamo il Multi Exit Discriminator, che \u00e8 indicato nell'annuncio BGP. Questo numero indica il peso del percorso annunciato. Tra i conflitti, verr\u00e0 scelto il percorso con il valore MED pi\u00f9 basso. Il master one-cloud gestisce il MED come parte integrante degli indirizzi IP dei container. La prima volta, l'indirizzo viene assegnato con un MED piuttosto alto = 1.000.000. In caso di un trasferimento di emergenza del container, il master riduce il MED, e M2 ricever\u00e0 quindi l'ordine di annunciare l'indirizzo 1.1.1.1 con MED = 999.999. L'istanza che opera su M1, nel frattempo, rimarr\u00e0 senza connessione, e il suo futuro ci interessa poco fino al momento del ripristino della connessione con il master, quando verr\u00e0 fermata come vecchia doppione.<\/p>\n<p><\/p>\n<h2 id=\"avarii\">Incidenti<\/h2>\n<p><\/p>\n<p>Tutti i sistemi di gestione dei data center gestiscono sempre adeguatamente piccoli guasti. Il fallimento di un container \u00e8 la norma praticamente ovunque.<\/p>\n<p><\/p>\n<p>Analizziamo come gestiamo un incidente, ad esempio un'interruzione di corrente in una o pi\u00f9 sale del data center.<\/p>\n<p><\/p>\n<p>Cosa significa un incidente per il sistema di gestione del data center? Innanzitutto, si tratta di un massiccio guasto simultaneo di molte macchine, e il sistema di gestione deve simultaneamente migrare un gran numero di container. Ma se l'incidente \u00e8 molto ampio, pu\u00f2 accadere che tutte le attivit\u00e0 non possano essere riassegnate ad altri minion, perch\u00e9 la capacit\u00e0 del data center scende sotto il 100% del carico. <\/p>\n<p><\/p>\n<p>Spesso gli incidenti sono accompagnati dal fallimento anche del livello di gestione. Questo pu\u00f2 accadere a causa del guasto della sua attrezzatura, ma pi\u00f9 frequentemente a causa del fatto che gli incidenti non vengono testati e il livello di gestione stesso crolla a causa dell'aumento del carico. <\/p>\n<p><\/p>\n<p>Cosa si pu\u00f2 fare con tutto questo?<\/p>\n<p><\/p>\n<p>Le migrazioni di massa significano che nell'infrastruttura si verificano molte azioni, migrazioni e collocamenti. Ciascuna di queste migrazioni pu\u00f2 richiedere un certo tempo, necessario per consegnare e decomprimere le immagini dei container sui minion, avviare e inizializzare i container, ecc. Pertanto, \u00e8 desiderabile che i compiti pi\u00f9 importanti vengano avviati prima di quelli meno importanti.<\/p>\n<p><\/p>\n<p>Rivisitando la nostra conosciuta gerarchia dei servizi, proviamo a decidere quali compiti vogliamo avviare per primi.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/2e827271adb8d3ff3d385e53553aaacf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Naturalmente, si tratta di quei processi che partecipano direttamente all'elaborazione delle richieste degli utenti, cio\u00e8 prod. Indichiamo questo tramite <strong>il numero di priorit\u00e0 di collocamento<\/strong> \u2014 un numero che pu\u00f2 essere assegnato a una coda. Se una coda ha una priorit\u00e0 pi\u00f9 alta, i suoi servizi vengono collocati per primi.<\/p>\n<p><\/p>\n<p>Su prod assegniamo priorit\u00e0 pi\u00f9 alte, 0; su batch - un po' pi\u00f9 basse, 100; su idle - ancora pi\u00f9 basse, 200. Le priorit\u00e0 vengono applicate in modo gerarchico. Tutti i compiti a un livello gerarchico inferiore avranno la relativa priorit\u00e0. Se vogliamo che all'interno di prod le cache vengano avviate prima dei frontend, assegniamo priorit\u00e0 a cache = 0 e ai frontend secondari = 1. Se, ad esempio, vogliamo che dal frontend venga avviato prima il portale principale e solo dopo il frontend musicale, possiamo assegnare una priorit\u00e0 pi\u00f9 bassa a quest'ultimo - 10.<\/p>\n<p><\/p>\n<p>Il problema successivo \u00e8 la mancanza di risorse. Quindi, abbiamo avuto un guasto a un gran numero di attrezzature, intere sale del data center, e abbiamo avviato cos\u00ec tanti servizi che ora non ci sono abbastanza risorse per tutti. Dobbiamo decidere quali compiti sacrificare affinch\u00e9 funzionino i servizi critici principali. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/1b1ad3da16df6677dd0ba4b038cdd7d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A differenza della priorit\u00e0 di assegnazione, non possiamo sacrificare indiscriminatamente tutti i compiti batch, alcuni di essi sono importanti per il funzionamento del portale. Pertanto, abbiamo individuato separatamente <strong>la priorit\u00e0 di esecuzione<\/strong> del compito. Durante l'assegnazione, un compito con priorit\u00e0 pi\u00f9 alta pu\u00f2 soppiantare, cio\u00e8 fermare un compito con priorit\u00e0 pi\u00f9 bassa, se non ci sono pi\u00f9 minion disponibili. In questo caso, il compito con priorit\u00e0 pi\u00f9 bassa rimarr\u00e0 probabilmente non assegnato, cio\u00e8 non ci sar\u00e0 pi\u00f9 un minion adatto con sufficienti risorse disponibili.<\/p>\n<p><\/p>\n<p>Nella nostra gerarchia, \u00e8 molto semplice specificare una priorit\u00e0 di esecuzione in modo che i compiti prod e batch possano sopprimere o fermare i compiti idle, ma non l'uno l'altro, impostando una priorit\u00e0 per idle pari a 200. Cos\u00ec come nel caso della priorit\u00e0 di assegnazione, possiamo usare la nostra gerarchia per descrivere regole pi\u00f9 complesse. Ad esempio, specifichiamo che per la funzione musicale sacrificiamo se non abbiamo risorse sufficienti per il portale web principale, impostando una priorit\u00e0 pi\u00f9 bassa per i nodi corrispondenti: 10.<\/p>\n<p><\/p>\n<h2 id=\"avarii-dc-celikom\">Guasti del data center completi<\/h2>\n<p><\/p>\n<p>Perch\u00e9 potrebbe guastarsi l'intero data center? Eventi naturali. C'era un buon post su come <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/dataline\/blog\/333578\/\">l'uragano ha influenzato il funzionamento del data center<\/a><\/noindex>. Gli eventi naturali possono includere senzatetto che una volta hanno incendiato la fibra ottica in un collettore, e il data center ha completamente perso contatto con le altre sedi. I guasti possono anche essere causati da errori umani: un operatore pu\u00f2 dare un comando tale che l'intero data center si fermer\u00e0. Questo pu\u00f2 succedere a causa di un grande bug. Insomma, i data center si bloccano: non \u00e8 raro. Ci\u00f2 accade da noi ogni pochi mesi. <\/p>\n<p><\/p>\n<p>Ecco cosa facciamo affinch\u00e9 nessuno #\u043e\u043a\u0436\u0438\u0432\u0438 pubblichi su Twitter.<\/p>\n<p><\/p>\n<p>La prima strategia \u00e8 l'isolamento. Ogni istanza one-cloud \u00e8 isolata e pu\u00f2 gestire macchine solo di un data center. Cio\u00e8, la perdita di un cloud a causa di bug o di un comando errato dell'operatore comporta la perdita di un solo data center. Siamo pronti a questo: abbiamo una politica di riserva, secondo la quale le repliche di applicazione e dati vengono ospitate in tutti i data center. Utilizziamo database a prova di errore e testiamo periodicamente i guasti.<br \/>\nPoich\u00e9 oggi abbiamo quattro data center, ci sono anche quattro istanze one-cloud distinte e completamente isolate.<\/p>\n<p><\/p>\n<p>Questo approccio non solo protegge da guasti fisici, ma pu\u00f2 anche proteggere da errori operatori.<\/p>\n<p><\/p>\n<p>Cosa si pu\u00f2 fare ancora riguardo al fattore umano? Quando un operatore d\u00e0 un comando strano o potenzialmente pericoloso al cloud, potrebbe essere improvvisamente richiesto di risolvere un compito minore per controllare quanto bene ha riflettuto. Ad esempio, se si tratta di un arresto massivo di molte repliche o semplicemente di un comando strano \u2014 ridurre il numero di repliche o cambiare il nome dell'immagine, e non solo il numero di versione nel nuovo manifesto.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/vh\/vw\/0d\/vhvw0dzobo9sd4x7zih_cnfnlu8.png\"><img decoding=\"async\" alt=\"One-cloud \u2014 un sistema operativo di livello data center su Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/f7ee44a77e30612a3cd99a6f7aee3820.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<h2 id=\"itogi\">Risultati<\/h2>\n<p><\/p>\n<p>Caratteristiche distintive di one-cloud: <\/p>\n<p><\/p>\n<ul>\n<li><strong>Uno schema gerarchico e visivo per la denominazione dei servizi e dei container<\/strong>, che consente di sapere molto rapidamente di che tipo di compito si tratta, a cosa si riferisce e come funziona e chi se ne occupa. <\/li>\n<li>Applichiamo la nostra <strong>tecnica di combinazione di compiti prod e batch<\/strong>sui minion per aumentare l'efficienza dell'uso condiviso delle macchine. Invece di cpuset, utilizziamo CPU quotas, shares, politiche dello scheduler CPU e Linux QoS.<\/li>\n<li>Non siamo riusciti a isolare completamente i container che operano su una macchina, ma la loro influenza reciproca rimane entro il 20%.<\/li>\n<li>L'organizzazione dei servizi in una gerarchia aiuta nell'eliminazione automatica delle emergenze tramite <strong>priorit\u00e0 di assegnazione e esecuzione<\/strong>.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"chavo\">FAQ<\/h2>\n<p><\/p>\n<p>Perch\u00e9 non abbiamo scelto una soluzione pronta.<\/p>\n<p><\/p>\n<ul>\n<li>Diverse classi di isolamento dei compiti richiedono logiche differenti per l'assegnazione ai minion. Se i compiti prod possono essere assegnati tramite una semplice riserva di risorse, batch e idle devono essere assegnati monitorando l'effettivo utilizzo delle risorse sui minion. <\/li>\n<li>La necessit\u00e0 di considerare le risorse utilizzate dalle attivit\u00e0 quali: \n<ul>\n<li>la larghezza di banda della rete;<\/li>\n<li>i tipi e i \"spindles\" dei dischi.<\/li>\n<\/ul>\n<\/li>\n<li>La necessit\u00e0 di specificare le priorit\u00e0 dei servizi durante la risoluzione delle emergenze, i diritti e le quote delle squadre sulle risorse, viene gestita mediante code gerarchiche in one-cloud.<\/li>\n<li>La necessit\u00e0 di avere nomi umani per i contenitori al fine di ridurre i tempi di reazione a emergenze e incidenti.<\/li>\n<li>L'impossibilit\u00e0 di implementare contemporaneamente il Service Discovery ovunque; la necessit\u00e0 di convivere a lungo con le attivit\u00e0 ospitate su server fisici \u2014 questo \u00e8 risolvibile tramite indirizzi IP \"statici\" che seguono i contenitori, e, di conseguenza, la necessit\u00e0 di un'integrazione unica con una grande infrastruttura di rete.<\/li>\n<\/ul>\n<p><\/p>\n<p>Tutte queste funzionalit\u00e0 richiederebbero significativi adattamenti delle soluzioni esistenti, e valutando la quantit\u00e0 di lavoro, ci siamo resi conto di poter sviluppare una nostra soluzione con circa lo stesso impegno. Ma la nostra soluzione sar\u00e0 notevolmente pi\u00f9 semplice da gestire e sviluppare \u2014 non presenta astratti inutili che supportano funzionalit\u00e0 non necessarie. <\/p>\n<p><\/p>\n<p>A coloro che leggono queste ultime righe, grazie per la pazienza e l'attenzione!<\/p>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/odnoklassniki\/blog\/346868\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u041e\u043b\u0435\u0433 \u0410\u043d\u0430\u0441\u0442\u0430\u0441\u044c\u0435\u0432, \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0410 \u043a\u0440\u043e\u043c\u0435 \u043c\u0435\u043d\u044f, \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0443\u0447\u0430 \u0436\u0435\u043b\u0435\u0437\u0430. \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0447\u0435\u0442\u044b\u0440\u0435 \u0426\u041e\u0414\u0430, \u0432 \u043d\u0438\u0445 \u043e\u043a\u043e\u043b\u043e 500 \u0441\u0442\u043e\u0435\u043a \u0431\u043e\u043b\u0435\u0435 \u0447\u0435\u043c \u0441 8 \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432. \u0412 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u044b \u043f\u043e\u043d\u044f\u043b\u0438, \u0447\u0442\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u043a\u0443, \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":84115,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-84114","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.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b!\" \/>\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\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.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\udd47One-cloud \u2014 \u041e\u0421 \u0443\u0440\u043e\u0432\u043d\u044f \u0434\u0430\u0442\u0430-\u0446\u0435\u043d\u0442\u0440\u0430 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah\" \/>\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-06-05T05:42:55+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-06-05T05:42:55+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\udd47One-cloud \u2014 un sistema operativo di livello data center in \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 | ProHoster","description":"Aloha, gente!","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","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\udd47One-cloud \u2014 \u041e\u0421 \u0443\u0440\u043e\u0432\u043d\u044f \u0434\u0430\u0442\u0430-\u0446\u0435\u043d\u0442\u0440\u0430 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 | ProHoster","og:description":"\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b!","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","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-06-05T05:42:55+00:00","article:modified_time":"2020-06-05T05:42:55+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"84114","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 15:04:42","updated":"2022-10-02 14:53:14","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\/84114","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=84114"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/84114\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/84115"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=84114"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=84114"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=84114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}