{"id":56365,"date":"2020-02-11T00:00:00","date_gmt":"2020-02-10T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike"},"modified":"2020-02-18T14:04:37","modified_gmt":"2020-02-18T11:04:37","slug":"highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","title":{"rendered":"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>La prossima conferenza HighLoad++ si svolger\u00e0 il 6 e 7 aprile 2020 a San Pietroburgo. <br \/>\nDettagli e biglietti <noindex><a rel=\"nofollow\" href=\"http:\/\/bit.ly\/2sSxgBx\">al link<\/a><\/noindex>. HighLoad++ Siberia 2019. Sala \u00abKrasnoyarsk\u00bb. 25 giugno, 12:00. Sintesi e <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/siberia\/2019\/abstracts\/5253\">presentazione<\/a><\/noindex>.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/cded9c5434d670db7295aadf5da0a9f1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCapita che i requisiti pratici siano in conflitto con la teoria, dove non sono considerati aspetti importanti per un prodotto commerciale. In questa presentazione viene illustrato il processo di selezione e combinazione di vari approcci per la creazione di componenti per la consistenza causale, basandosi su ricerche accademiche e sulle esigenze di un prodotto commerciale. Gli ascoltatori apprenderanno gli approcci teorici esistenti riguardo agli orologi logici, al tracciamento delle dipendenze, alla sicurezza dei sistemi, alla sincronizzazione degli orologi e sul perch\u00e9 MongoDB abbia scelto determinate soluzioni.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><b>Mikhail Tyulenev (di seguito \u2013 MT):<\/b> \u2013 Parler\u00f2 della consistenza causale: \u00e8 una funzione su cui abbiamo lavorato in MongoDB. Lavoro nel team dei sistemi distribuiti, l'abbiamo realizzata circa due anni fa.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/b8d0a5b64e715f53b033fa8c398e2eb4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDurante il processo, ho dovuto familiarizzare con una grande quantit\u00e0 di ricerche accademiche, poich\u00e9 questa funzionalit\u00e0 \u00e8 stata ampiamente studiata. Ho scoperto che nessun articolo si adatta a ci\u00f2 che \u00e8 richiesto in produzione, data la presenza di requisiti piuttosto specifici che si trovano in praticamente tutte le applicazioni di produzione.<\/p>\n<p>Parler\u00f2 di come noi, in qualit\u00e0 di consumatori di ricerche accademiche, prepariamo qualcosa che possiamo poi presentare ai nostri utenti come un piatto pronto da utilizzare in modo comodo e sicuro.<\/p>\n<h3>Coerenza causale (Causal consistency). Definiamo i concetti<\/h3>\n<p>\nPer iniziare, voglio spiegare brevemente cosa sia la coerenza causale. Ci sono due personaggi \u2013 Leonard e Penny (dalla serie \"The Big Bang Theory\"):<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/ee0835b604ae5d5d6c0fa1bc369e6b18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSupponiamo che Penny si trovi in Europa e Leonard voglia farle una sorpresa, una festa. E non gli viene in mente nulla di meglio che toglierla dalla lista degli amici e inviare a tutti gli amici un aggiornamento nel feed: \u00abFacciamo una sorpresa a Penny!\u00bb (lei \u00e8 in Europa, mentre dorme, non vede tutto questo e non pu\u00f2 vederlo perch\u00e9 non \u00e8 l\u00ec). Alla fine, elimina questo post, rimuove dal \u00abFeed\u00bb e ripristina l'accesso, in modo che non si accorga di nulla e non ci siano scandali.<br \/>\nTutto ci\u00f2 \u00e8 fantastico, ma supponiamo che il sistema sia distribuito e che gli eventi non siano andati del tutto come previsto. Pu\u00f2 succedere, ad esempio, che la restrizione dell'accesso a Penny sia avvenuta dopo che questo post \u00e8 apparso, se gli eventi non sono connessi da legami di causa ed effetto. In effetti, questo \u00e8 un esempio di quando \u00e8 necessaria la coerenza causale per eseguire una funzione aziendale (in questo caso).<\/p>\n<p>In realt\u00e0, queste sono propriet\u00e0 piuttosto complesse del database \u2013 poche di esse sono supportate. Passiamo ai modelli.<\/p>\n<h3>Modelli di coerenza (Consistency Models)<\/h3>\n<p>\nCos'\u00e8 esattamente un modello di coerenza nei database? Si tratta di alcune garanzie che un sistema distribuito fornisce riguardo ai dati che un cliente pu\u00f2 ricevere e in quale sequenza.<\/p>\n<p>In sostanza, tutti i modelli di coerenza si riducono a quanto un sistema distribuito assomigli a un sistema che funziona, ad esempio, su un singolo nodo su un laptop. Ecco quanto un sistema che opera su migliaia di nodi geograficamente distribuiti si avvicina a un laptop, dove tutte queste propriet\u00e0 vengono sostanzialmente eseguite in modo automatico.<\/p>\n<p>Pertanto, i modelli di coerenza si applicano esclusivamente ai sistemi distribuiti. Tutti i sistemi esistenti in precedenza che operavano su uno scale-up verticale non presentavano tali problemi. L\u00ec c'era una sola Buffer Cache, da cui si estraevano sempre i dati.<\/p>\n<h3>Modello Strong<\/h3>\n<p>\nIn effetti, il primo modello \u00e8 il Strong (o linea di risalita, come viene spesso chiamato). Questo \u00e8 un modello di coerenza che garantisce che ogni modifica, non appena si riceve la conferma che \u00e8 avvenuta, diventa visibile a tutti gli utenti del sistema.<\/p>\n<p>Questo crea un ordine globale di tutti gli eventi nel database. Questa \u00e8 una propriet\u00e0 di coerenza molto forte e in generale \u00e8 molto costosa. Tuttavia, \u00e8 ben supportata. \u00c8 semplicemente molto costosa e lenta \u2013 infatti \u00e8 raramente utilizzata. Questo \u00e8 chiamato 'rise ability'.<\/p>\n<p>C'\u00e8 un'altra propriet\u00e0, ancora pi\u00f9 forte, che \u00e8 supportata in 'Spanner' \u2013 si chiama Coerenza Esterna. Di questo ne parleremo pi\u00f9 tardi.<\/p>\n<h3>Causale<\/h3>\n<p>\nIl prossimo \u00e8 Causale, proprio quello di cui stavo parlando. Tra Strong e Causale ci sono diversi sotto-livelli, di cui non parler\u00f2, ma tutti si riconduscono a Causale. Questo \u00e8 un modello importante, perch\u00e9 \u00e8 il pi\u00f9 forte di tutti i modelli, la coerenza pi\u00f9 forte in presenza di reti o partizioni.<\/p>\n<p>I Causali sono in realt\u00e0 situazioni in cui gli eventi sono legati da una relazione di causa ed effetto. Spesso vengono percepiti come le 'Read your own rights' dal punto di vista del cliente. Se un cliente ha osservato certi valori, non pu\u00f2 vedere i valori che erano nel passato. Inizia a vedere letture prefissate. Tutto si riduce a questo.<br \/>\nCausals come modello di coerenza \u2013 una parziale ordinazione degli eventi sul server, in cui gli eventi da tutti i client vengono osservati nella stessa sequenza. In questo caso \u2013 Leonardo e Penny.<\/p>\n<h3>Eventual<\/h3>\n<p>\nIl terzo modello \u00e8 l'Eventual Consistency. Questa \u00e8 supportata da praticamente tutti i sistemi distribuiti, essendo il modello minimo che ha senso. Essa implica quanto segue: quando ci sono alcune modifiche nei dati, in un certo momento diventano coerenti.<\/p>\n<p>In quel momento non dice nulla, altrimenti si trasformerebbe in External Consistency \u2013 sarebbe una storia completamente diversa. Tuttavia, questo \u00e8 un modello molto popolare, il pi\u00f9 comune. Per impostazione predefinita, tutti gli utenti dei sistemi distribuiti utilizzano proprio l'Eventual Consistency.<\/p>\n<p>Vorrei fornire alcuni esempi comparativi:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/c23e59b30d96de6ec456aaa76c67ad61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCosa significano queste frecce?<\/p>\n<ul>\n<li><b>Latency.<\/b> Aumentando la forza di consistenza, diventa pi\u00f9 grande per motivi comprensibili: \u00e8 necessario registrare di pi\u00f9, ottenere conferma da tutti gli host e nodi coinvolti nel cluster che i dati sono gi\u00e0 presenti. Pertanto, nella Consistenza Eventuale, la risposta \u00e8 la pi\u00f9 veloce, poich\u00e9 generalmente \u00e8 possibile anche effettuare un commit in memoria e questo sar\u00e0, in linea di principio, sufficiente.<\/li>\n<li><b>Disponibilit\u00e0.<\/b> Se questo \u00e8 inteso come la capacit\u00e0 del sistema di rispondere in presenza di interruzioni di rete, partizioni o altri guasti, la resilienza aumenta riducendo il modello di consistenza, poich\u00e9 \u00e8 sufficiente che un host funzioni e fornisca alcuni dati. La Consistenza Eventuale non garantisce nulla riguardo ai dati: potrebbe essere qualsiasi cosa.<\/li>\n<li><b>Anomalie.<\/b> Tuttavia, aumenta naturalmente il numero di anomalie. Nella Strong Consistency non dovrebbero praticamente essercene affatto, mentre nella Eventual Consistency possono presentarsi in qualsiasi forma. Si pone la domanda: perch\u00e9 le persone scelgono l'Eventual Consistency se contiene anomalie? La risposta \u00e8 che i modelli di Eventual Consistency sono praticabili e le anomalie esistono, ad esempio, per brevi intervalli di tempo; esiste la possibilit\u00e0 di utilizzare un master per la lettura e ottenere dati abbastanza consistenti; spesso c'\u00e8 l'opportunit\u00e0 di utilizzare modelli di forte consistenza. Praticamente funziona e, spesso, il numero di anomalie \u00e8 limitato nel tempo.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Teorema CAP<\/h3>\n<p>\nQuando sentite le parole consistenza e disponibilit\u00e0, cosa vi viene in mente? Esatto, il teorema CAP! Voglio sfatare un mito... Non sono io, ma \u00e8 Martin Kleppmann, che ha scritto un ottimo articolo e un ottimo libro.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/02a9b84585218c4e85afd65f7e88aa26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl teorema CAP \u00e8 un principio formulato negli anni 2000, riguardante Consistenza, Disponibilit\u00e0, Partizioni: prendi due qualunque, e non puoi scegliere tre. Era un principio di questo tipo. \u00c8 stato dimostrato come teorema alcuni anni dopo, ad opera di Gilbert e Lynch. Da allora \u00e8 stato utilizzato come mantra: i sistemi sono stati divisi in CA, CP, AP e cos\u00ec via.<\/p>\n<p>Questo teorema \u00e8 stato dimostrato in realt\u00e0 per i seguenti casi... Prima di tutto, la Disponibilit\u00e0 non \u00e8 stata considerata come un valore continuo da zero a cento (0 \u2013 sistema \"mortale\", 100 \u2013 risponde rapidamente; noi tendiamo a vederla in questo modo), ma come una propriet\u00e0 dell'algoritmo che garantisce che in tutte le sue esecuzioni restituisce dati.<\/p>\n<p>Non si parla affatto del tempo di risposta! C'\u00e8 un algoritmo che restituisce dati dopo 100 anni \u2013 \u00e8 un algoritmo disponibile meraviglioso, che fa parte del teorema CAP.<br \/>\nIn secondo luogo: il teorema \u00e8 stato dimostrato per variazioni nei valori di una stessa chiave, considerando che queste variazioni sono una linea ridimensionabile. Questo significa che in realt\u00e0 non vengono praticamente utilizzati, poich\u00e9 i modelli sono altri, come la Consistenza Eventuale, la Consistenza Forte (forse).<\/p>\n<p>A cosa serve tutto questo? Serve a capire che il teorema CAP, nella forma in cui \u00e8 stato dimostrato, \u00e8 praticamente inapplicabile e viene raramente utilizzato. Nella sua forma teorica, limita in qualche modo tutto. Si tratta di un principio che \u00e8 intuitivamente corretto, ma che non \u00e8 dimostrato in generale.<\/p>\n<h3>La coerenza causale \u2013 il modello pi\u00f9 forte<\/h3>\n<p>\nQuello che sta accadendo adesso \u00e8 che \u00e8 possibile ottenere tutte e tre le cose: Coerenza, Disponibilit\u00e0 e gestire le Partizioni. In particolare, la coerenza causale \u00e8 il modello di coerenza pi\u00f9 forte, che continua a funzionare anche in presenza di Partizioni (interruzioni nella rete). Per questo suscita tanto interesse, ed \u00e8 per questo che ci siamo dedicati a essa.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/c4320294320261858a6d22faa97b9e23.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn primo luogo, semplifica il lavoro degli sviluppatori di applicazioni. In particolare, offre un ampio supporto dal server: quando tutte le operazioni effettuate da un singolo cliente arrivano in una sequenza garantita all'altro cliente. In secondo luogo, resiste alle partizioni.<\/p>\n<h3>La cucina interna di MongoDB<\/h3>\n<p>\nRicordando che \u00e8 ora di pranzo, ci spostiamo in cucina. Vi parler\u00f2 del modello di sistema, cio\u00e8 di cosa sia MongoDB per coloro che sentono parlare di questo tipo di database per la prima volta.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/a1784442ff1c44403b5347f4f43a1197.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/a1f9bcb4daebb43e4fc848a5f5f07c60.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMongoDB (di seguito \u2013 \u00abMongoDB\u00bb) \u00e8 un sistema distribuito che supporta la scalabilit\u00e0 orizzontale, ovvero lo sharding; e all'interno di ogni shard supporta anche la ridondanza dei dati, cio\u00e8 la replica.<\/p>\n<p>Lo sharding in \u00abMongoDB\u00bb (database non relazionale) esegue un bilanciamento automatico, ovvero ogni collezione di documenti (o \u00abtabella\u00bb nei termini dei dati relazionali) viene suddivisa in parti, e il server si occupa automaticamente di spostarle tra gli shard.<\/p>\n<p>Il Query Router, che distribuisce le richieste, per il cliente rappresenta un'interfaccia attraverso cui lavora. Sa gi\u00e0 dove si trovano i dati e li indirizza verso il corretto shard.<\/p>\n<p>Un altro punto importante: MongoDB \u00e8 un single master. C'\u00e8 un Primary \u2013 pu\u00f2 acquisire registrazioni che supportano le chiavi che contiene. Non \u00e8 possibile effettuare scritture Multi-master.<\/p>\n<p>Abbiamo rilasciato la versione 4.2 \u2013 ci sono nuove funzionalit\u00e0 interessanti. In particolare, abbiamo integrato Lucene \u2013 per la ricerca \u2013 direttamente in \u00abMongoDB\u00bb, rendendo possibile eseguire ricerche attraverso Lucene, simili a quelle in \u00abElasticsearch\u00bb.<\/p>\n<p>Abbiamo creato un nuovo prodotto \u2013 Charts, che \u00e8 disponibile anche su \u00ab\u0410\u0442\u043b\u0430\u0441\u00bb (il nostro Cloud \u00ab\u041c\u043e\u043d\u0433\u043e\u00bb). Offrono un Free Tier \u2013 puoi provare a giocare con questo. Charts mi \u00e8 piaciuto molto \u2013 visualizzazione dei dati, molto intuitiva.<\/p>\n<h3>Ingredienti della coerenza causale<\/h3>\n<p>\nHo contato circa 230 articoli pubblicati su questo tema \u2013 da Leslie Lampert. Ora cercher\u00f2 di ricordarne alcune parti dai miei appunti.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/e88b34b7a724e94837b944a4ddd21a04.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTutto \u00e8 iniziato con un articolo di Leslie Lampert, scritto negli anni '70. Come puoi vedere, ci sono ancora ricerche in corso su questo argomento. Attualmente, la coerenza causale sta suscitando interesse a causa dello sviluppo dei sistemi distribuiti.<\/p>\n<h3>Limitazioni<\/h3>\n<p>\nQuali sono i limiti? Questo \u00e8 uno dei punti principali, infatti i limiti imposti dai sistemi di produzione differiscono notevolmente da quelli presenti negli articoli accademici. Spesso risultano piuttosto artificiali.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/9583ba9ff870e4ddc7aad4ba4c59ecc1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Innanzitutto, \u00ab\u041c\u043e\u043d\u0433\u043e\u0414\u0411\u00bb \u00e8 un master singolo, come ho gi\u00e0 detto (questo semplifica notevolmente).<\/li>\n<li>Riteniamo che il sistema debba supportare circa 10.000 shard. Non possiamo prendere decisioni architetturali che limiterebbero chiaramente questo valore.<\/li>\n<li>Abbiamo una soluzione cloud, ma crediamo che l'utente debba avere la possibilit\u00e0 di scaricare il binary, avviarlo sul proprio laptop e farlo funzionare senza problemi.<\/li>\n<li>Riteniamo che nel Research venga raramente utilizzato: i clienti esterni possono fare qualsiasi cosa. MongoDB \u00e8 open source. Di conseguenza, i clienti possono essere abbastanza intelligenti, ma anche vendicativi \u2013 potrebbero voler rompere tutto. Pensiamo che possano verificarsi dei Byzantine Failures.<\/li>\n<li>Per i clienti esterni, che si trovano al di fuori del perimetro \u2013 un'importante restrizione: se questa funzione \u00e8 disattivata, non ci devono essere degradazioni delle performance.<\/li>\n<li>Un altro punto \u2013 del tutto antiaccademico: compatibilit\u00e0 tra versioni precedenti e future. I vecchi driver devono supportare i nuovi aggiornamenti e il database deve supportare i vecchi driver.<\/li>\n<\/ul>\n<p>\nInsomma, tutto ci\u00f2 impone delle limitazioni.<\/p>\n<h3>Componenti di Causal consistency<\/h3>\n<p>\nOra parler\u00f2 di alcuni componenti. Se consideriamo la coerenza causale, possiamo distinguere dei blocchi. Abbiamo scelto tra i lavori che appartengono a un certo blocco: Dependency Tracking, la scelta dell'orologio, come questi orologi possono essere sincronizzati tra loro e come garantiamo la sicurezza \u2013 questo \u00e8 un piano generico di ci\u00f2 di cui parler\u00f2:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/10c2631d6e61a280139b448628db763e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Tracciamento completo delle dipendenze (Full Dependency Tracking)<\/h3>\n<p>\nA cosa serve? Serve affinch\u00e9, quando i dati vengono replicati, ogni registrazione, ogni modifica dei dati contenga informazioni su quali modifiche dipende. La modifica pi\u00f9 semplice e ingenua \u00e8 quando ogni messaggio che contiene una registrazione include informazioni sui messaggi precedenti:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/fa5d0086c3c77e33631d8a2cd5c217fa.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn questo esempio il numero tra parentesi graffe rappresenta i numeri delle registrazioni. A volte queste registrazioni con valori vengono trasmesse anche per intero, a volte vengono trasmessi determinati versioni. La sostanza \u00e8 che ogni modifica contiene in s\u00e9 informazioni sulla precedente (implicitamente porta tutto questo con s\u00e9).<\/p>\n<p>Perch\u00e9 abbiamo deciso di non adottare questo approccio (tracciamento completo)? \u00c8 ovvio che questo metodo \u00e8 poco pratico: qualsiasi modifica in un social network dipende da tutte le modifiche precedenti in quel social network, passando, ad esempio, da \"Facebook\" o \"VKontakte\" in ciascun aggiornamento. Tuttavia, ci sono molti studi su Full Dependency Tracking \u2013 questi sono presocial networks, e in alcune situazioni pu\u00f2 funzionare davvero.<\/p>\n<h3>Tracciamento delle dipendenze esplicito (Explicit Dependency Tracking)<\/h3>\n<p>\nIl successivo \u00e8 pi\u00f9 limitato. Qui si considera anch'esso il trasferimento di informazioni, ma solo quelle che dipendono esplicitamente. Ci\u00f2 da cui dipende, di norma, \u00e8 gi\u00e0 definito dall'Application. Quando i dati vengono replicati, durante la richiesta vengono forniti solo risposte quando le dipendenze precedenti sono state soddisfatte, ovvero mostrate. Questo \u00e8 il nocciolo di come funziona la coerenza causale.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/7fe101b998c1a0c922788d8d36a5243f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEssa vede che la registrazione 5 dipende dalle registrazioni 1, 2, 3, 4 \u2013 quindi, attende prima che il cliente acceda alle modifiche apportate dal provvedimento di accesso di Penny, quando tutte le modifiche precedenti sono gi\u00e0 passate nel database.<\/p>\n<p>Anche questo non ci soddisfa, perch\u00e9 ci sono comunque troppe informazioni, e questo rallenter\u00e0. C'\u00e8 un altro approccio\u2026<\/p>\n<h3>Orologi di Lamport (Lamport Clock)<\/h3>\n<p>\nSono molto antichi. Il Lamport Clock implica che queste dipendenze si comprimano in una funzione scalare, la quale \u00e8 nota come Lamport Clock.<\/p>\n<p>Una funzione scalare \u00e8 un numero astratto. Spesso viene chiamato tempo logico. Ad ogni evento, questo contatore aumenta. Il contatore, conosciuto attualmente dal processo, invia ogni messaggio. \u00c8 chiaro che i processi possono essere dissincronizzati, avere orari completamente diversi. Tuttavia, attraverso questo scambio di messaggi, il sistema bilancia in qualche modo gli orologi. Cosa succede in questo caso?<\/p>\n<p>Ho diviso quel grande shard in due per chiarire: i Friends possono vivere in un nodo che contiene un pezzo della collezione, mentre il Feed pu\u00f2 trovarsi in un altro nodo, che contiene un'altra parte di questa collezione. \u00c8 chiaro come possano non essere in coda? Prima il Feed dir\u00e0: \u00abReplicato\u00bb, e poi i Friends. Se il sistema non garantisce che il Feed non venga mostrato finch\u00e9 le dipendenze dei Friends nella collezione Friends non siano state consegnate, ci troveremo esattamente nella situazione di cui ho parlato.<\/p>\n<p>Vedete come aumenta logicamente il tempo del counter sul Feed:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/bae152d1890b53804f2cb28122983df6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCos\u00ec, la principale propriet\u00e0 di questo Lamport Clock e della Causal consistency (spiegata attraverso il Lamport Clock) \u00e8 la seguente: se abbiamo eventi A e B, e l'evento B dipende dall'evento A *, allora segue che il LogicalTime dell'Evento A \u00e8 minore del LogicalTime dell'Evento B.<\/p>\n<p><i>* A volte si dice anche che A \u00e8 accaduto prima di B, cio\u00e8 A \u00e8 successa prima di B \u2013 questo \u00e8 un certo rapporto che ordina parzialmente l'intero insieme di eventi che si sono verificati.<\/i><\/p>\n<p>Al contrario, \u00e8 sbagliato. Questo \u00e8 davvero uno dei principali svantaggi del Lamport Clock: l'ordinamento parziale. C'\u00e8 il concetto di eventi simultanei, ovvero eventi in cui n\u00e9 (A \u00e8 accaduto prima di B) n\u00e9 (A \u00e8 accaduto dopo B). Un esempio pu\u00f2 essere l'aggiunta da parte di Leonard di un'altra persona tra gli amici (non Leonard, ma Sheldon, per esempio).<br \/>\nQuesto \u00e8 proprio il principio che viene frequentemente utilizzato quando si lavora con i Lamport Clock: si guarda precisamente alla funzione e da essa si trae la conclusione che tali eventi possono essere dipendenti. Perch\u00e9 in un verso \u00e8 vero: se LogicalTime A \u00e8 minore di LogicalTime B, allora B non pu\u00f2 essere accaduto prima di A; mentre se \u00e8 maggiore, allora potrebbe esserlo.<\/p>\n<h3>Orologi vettoriali (Vector Clock)<\/h3>\n<p>\nLo sviluppo logico degli orologi di Lamport \u00e8 rappresentato dagli Orologi Vettoriali. Si distinguono perch\u00e9 ogni nodo in questo caso contiene i propri orologi separati, che vengono trasmessi come un vettore.<br \/>\nIn questo caso, si vede che l'indice zero del vettore corrisponde a Feed, mentre il primo indice del vettore \u00e8 per Friends (ognuno di questi nodi). E ora saranno incrementati: l'indice zero 'Feed' aumenta durante la registrazione \u2013 1, 2, 3:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/d89292686ed8dd41aef06090f16db1c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCosa rende migliori gli orologi vettoriali? Il fatto che permettano di capire quali eventi si svolgono simultaneamente e quando avvengono su diverse nodi. Questo \u00e8 molto importante per un sistema di sharding, come MongoDB. Tuttavia, non lo abbiamo scelto, anche se \u00e8 una cosa eccellente, funziona splendidamente e probabilmente sarebbe stata utile per noi\u2026<\/p>\n<p>Se abbiamo 10.000 shard, non possiamo trasmettere 10.000 componenti, anche se comprimiamo o troviamo altre soluzioni: il carico utile sar\u00e0 comunque di gran lunga inferiore al volume totale di questo vettore. Quindi, con molte esitazioni, ci siamo allontanati da questo approccio e ci siamo spostati su un altro.<\/p>\n<h3>Spanner TrueTime. Orologi atomici<\/h3>\n<p>\nHo detto che parler\u00f2 di Spanner. \u00c8 una cosa incredibile, proprio del XXI secolo: orologi atomici, sincronizzazione GPS.<\/p>\n<p>Qual \u00e8 l'idea? Spanner \u00e8 il sistema di Google, che di recente \u00e8 diventato anche accessibile agli utenti (hanno aggiunto SQL). Ogni transazione ha un proprio time stamp. Poich\u00e9 il tempo \u00e8 sincronizzato*, a ciascun evento pu\u00f2 essere assegnato un determinato orario - gli orologi atomici hanno un tempo di attesa, dopo il quale si verifica garantitamente un altro orario.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/707b5998fbb500d201aafffccc666f0e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn questo modo, registrando semplicemente nel database e aspettando un certo periodo di tempo, si garantisce automaticamente la serializzabilit\u00e0 degli eventi. Hanno il modello di coerenza pi\u00f9 forte che si possa immaginare \u2013 una coerenza esterna.<\/p>\n<p>* Questo \u00e8 il problema principale degli orologi di Lamport \u2013 non sono mai sincronizzati nei sistemi distribuiti. Possono divergere, anche con NTP non funzionano molto bene. Il \"Spanner\" ha orologi atomici e sincronizzazione, sembra a livello di microsecondi.<\/p>\n<p>Perch\u00e9 non abbiamo scelto? Non presupponiamo che i nostri utenti abbiano orologi atomici integrati. Quando saranno presenti, integrati in ogni laptop, ci sar\u00e0 una sincronizzazione GPS superveloce \u2013 allora s\u00ec\u2026 Ma per ora, la migliore opzione possibile \u00e8 \"Amazon\", le stazioni base \u2013 per i fanatici\u2026 Pertanto, abbiamo utilizzato orologi diversi.<\/p>\n<h3>Orologi ibridi (Hybrid Clock)<\/h3>\n<p>\nQuesto \u00e8 in realt\u00e0 ci\u00f2 che ticchetta in \"MongoDB\" per garantire la coerenza causale. In cosa sono ibridi? L'ibrido \u00e8 un valore scalare, ma \u00e8 composto da due componenti:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/dab03a87d9f6ee2e716f75baff1736bc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>La prima \u2013 \u00e8 l'epoca unix (quante secondi sono trascorsi dall'inizio del \"mondo computazionale\").<\/li>\n<li>Secondo: un certo incremento, anch'esso un intero unsigned a 32 bit.<\/li>\n<\/ul>\n<p>\nQuesto \u00e8 tutto. C'\u00e8 un approccio in cui la parte che tiene traccia del tempo si sincronizza costantemente con l'orologio; ogni volta che avviene un aggiornamento, questa parte si sincronizza con l'orologio e si verifica che il tempo sia sempre pi\u00f9 o meno corretto, mentre l'incremento consente di distinguere gli eventi che si sono verificati nello stesso momento.<\/p>\n<p>Perch\u00e9 \u00e8 importante per MongoDB? Perch\u00e9 consente di effettuare backup e ripristini a un certo punto nel tempo, ossia l'evento viene indicizzato nel tempo. Questo \u00e8 importante quando sono necessari alcuni eventi; per un database, gli eventi sono le modifiche nel database che si sono verificate in determinati intervalli di tempo.<\/p>\n<p>La ragione principale te la dir\u00f2 solo a te (per favore, non dirlo a nessuno)! Abbiamo fatto cos\u00ec perch\u00e9 cos\u00ec appaiono i dati ordinati e indicizzati nel MongoDB OpLog. L'OpLog \u00e8 una struttura dati che contiene tutte le modifiche nel database: prima vengono inserite nell'OpLog e poi vengono applicate al Storage, nel caso in cui si tratti di dati replicati o shard.<\/p>\n<p>Questa era la ragione principale. Ci sono anche requisiti pratici per lo sviluppo della base, il che significa che deve essere semplice: poco codice, il minor numero possibile di elementi rotti da riscrivere e testare. Il fatto che i nostri oplog siano stati indicizzati da orologi ibridi \u00e8 stato molto utile e ci ha permesso di fare la scelta giusta. Questo si \u00e8 rivelato davvero efficace e ha in qualche modo funzionato magicamente al primo prototipo. \u00c8 stato davvero fantastico!<\/p>\n<h3>Sincronizzazione degli orologi<\/h3>\n<p>\nEsistono diversi metodi di sincronizzazione descritti nella letteratura scientifica. Parlo di sincronizzazione quando abbiamo due shard diversi. Se c'\u00e8 un replica set, non c'\u00e8 bisogno di sincronizzazione: \u00e8 un 'singolo master'; abbiamo un OpLog, in cui tutte le modifiche vengono registrate \u2013 in questo caso tutto \u00e8 gi\u00e0 ordinato sequenzialmente nell'OpLog. Ma se abbiamo due shard diversi, la sincronizzazione temporale \u00e8 importante. Qui gli orologi vettoriali sono stati di grande aiuto! Ma noi non li abbiamo.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/7d3306747490ac044b7f8130defea0c9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl secondo \u00e8 \"Heartbeats\". Si possono scambiare alcuni segnali che avvengono a intervalli di tempo regolari. Ma i \"Heartbeats\" sono troppo lenti, non possiamo garantire la latenza al nostro cliente.<\/p>\n<p>Il tempo reale \u00e8 chiaramente una cosa straordinaria. Ma, di nuovo, \u00e8 probabilmente il futuro... Anche se in \"Atlas\" \u00e8 gi\u00e0 possibile farlo, ci sono gi\u00e0 sincronizzatori di tempo rapidi di tipo \"Amazon\". Ma non sar\u00e0 accessibile a tutti.<\/p>\n<p>Il Gossiping \u00e8 quando tutti i messaggi includono un timestamp. \u00c8 fondamentalmente ci\u00f2 che usiamo. Ogni messaggio tra i nodi, driver, router di nodi dati, assolutamente tutto per \"MongoDB\" \u2013 sono elementi, componenti del database, che contengono orologi che scorrono. Hanno ovunque un valore di tempo ibrido, che viene trasmesso. 64 bit? \u00c8 possibile, si pu\u00f2 fare.<\/p>\n<h3>Come funziona tutto questo insieme?<\/h3>\n<p>\nQui prendo in considerazione un replica set per semplificare. C'\u00e8 il Primary e il Secondary. Il Secondary esegue la replica e non \u00e8 sempre completamente sincronizzato con il Primary.<\/p>\n<p>Si sta eseguendo un'inserzione (insert) in \u00abPrymer\u00bb con un certo valore temporale. Questo inserimento aumenta il contatore interno di 11, se \u00e8 il massimo. Oppure controller\u00e0 i valori delle ore e si sincronizzer\u00e0 in base alle ore, se i valori delle ore sono superiori. Questo consente di ordinare in base al tempo.<\/p>\n<p>Dopo che viene effettuata la registrazione, si verifica un momento importante. Le ore in \u00abMongoDB\u00bb vengono incrementate solo in caso di registrazione nell'\u00abOplog\u00bb. Questo \u00e8 l'evento che cambia lo stato del sistema. In tutti gli articoli classici, un evento \u00e8 considerato l'arrivo di un messaggio in un nodo: se un messaggio \u00e8 arrivato, significa che il sistema ha cambiato il suo stato.<\/p>\n<p>Questo \u00e8 collegato al fatto che, durante l'analisi, non \u00e8 sempre possibile comprendere come verr\u00e0 interpretato questo messaggio. Sappiamo con certezza che se non \u00e8 riflesso nell'\u00abOplog\u00bb, non verr\u00e0 interpretato in alcun modo, e l'unico cambiamento nello stato del sistema \u00e8 la registrazione nell'\u00abOplog\u00bb. Questo semplifica tutto: semplifica il modello, consente di mantenere un ordinamento all'interno di un singolo replica set e molte altre cose utili.<\/p>\n<p>Viene restituito un valore gi\u00e0 registrato in \u00abOpLog\u00bb - sappiamo che in \u00abOpLog\u00bb \u00e8 gi\u00e0 presente questo valore, e il suo timestamp \u00e8 12. Ora, diciamo che la lettura inizia da un altro nodo (Secondary), e lui passa gi\u00e0 l'afterClusterTime nel messaggio. Dice: \u00abHo bisogno di tutto ci\u00f2 che \u00e8 successo almeno dopo le 12 o alle dodici\u00bb (vedi figura sopra).<\/p>\n<p>Questo \u00e8 ci\u00f2 che si chiama Causal a consistent (CAT). C'\u00e8 un concetto nella teoria secondo cui si tratta di un certo intervallo di tempo che \u00e8 autonomamente consistente. In questo caso si pu\u00f2 dire che si tratta di uno stato del sistema che \u00e8 stato osservato al momento 12.<\/p>\n<p>Attualmente qui non c'\u00e8 nulla, perch\u00e9 simula una situazione in cui \u00e8 necessario che il Secondario replichi i dati dal Primario. Sta aspettando... Ed ecco che i dati sono arrivati - restituisce indietro questi valori.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/54d9de3e2696c1e5d19f4da206be090b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEcco come funziona approssimativamente. Quasi.<\/p>\n<p>Cosa significa \"quasi\"? Immaginiamo che ci sia una persona che ha letto e compreso come funziona tutto questo. Ha capito che ogni volta avviene il ClusterTime, aggiorna gli orologi logici interni e poi la registrazione successiva aumenta di uno. Questa funzione occupa 20 righe. Supponiamo che questa persona passi il numero intero a 64 bit pi\u00f9 grande possibile, meno uno.<\/p>\n<p>Perch\u00e9 \"meno uno\"? Perch\u00e9 gli orologi interni verranno impostati su questo valore (ovviamente, \u00e8 il massimo possibile e pi\u00f9 dell'attuale tempo), poi si registrer\u00e0 nel \"OpLog\", e gli orologi verranno incrementati di nuovo di uno \u2013 e ci sar\u00e0 gi\u00e0 il valore massimo (l\u00ec ci sono solo tutti uno, non c'\u00e8 spazio oltre, unsaint int).<\/p>\n<p>\u00c8 chiaro che dopo questo il sistema diventa completamente inaccessibile per qualsiasi cosa. Pu\u00f2 essere solo scaricato, ripulito \u2013 molto lavoro manuale. Disponibilit\u00e0 completa:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/634b25fe0ef1e0af39181cd59c7b522f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nInoltre, se questo viene replicato altrove, semplicemente si blocca l'intero cluster. Una situazione assolutamente inaccettabile, che chiunque pu\u00f2 organizzare molto rapidamente e facilmente! Perci\u00f2 abbiamo considerato questo aspetto come uno dei pi\u00f9 importanti. Come possiamo prevenirlo?<\/p>\n<h3>Il nostro obiettivo \u00e8 firmare clusterTime<\/h3>\n<p>\nCos\u00ec viene trasmesso nel messaggio (fino al testo blu). Ma abbiamo anche iniziato a generare una firma (testo blu):<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/c16e985f9610e01a61293e0d6dde459b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa firma \u00e8 generata da una chiave che viene conservata all'interno del database, all'interno di un perimetro sicuro; viene generata e aggiornata (questo non \u00e8 visibile agli utenti). Viene generato un hash, e ogni messaggio viene firmato al momento della creazione e validato al momento della ricezione.<br \/>\nProbabilmente le persone si chiedono: \u00abQuanto rallenta tutto questo?\u00bb Ho gi\u00e0 detto che deve funzionare rapidamente, specialmente in assenza di questa funzionalit\u00e0.<\/p>\n<p>Cosa significa utilizzare la coerenza causale in questo caso? Si tratta di mostrare il parametro afterClusterTime. E senza di esso, trasmetter\u00e0 semplicemente i valori comunque. Il gossiping, a partire dalla versione 3.6, funziona sempre.<\/p>\n<p>Se lasciamo la generazione costante di firme, ci\u00f2 rallenter\u00e0 il sistema anche in assenza della funzionalit\u00e0, il che non \u00e8 in linea con i nostri approcci e requisiti. E cosa abbiamo fatto?<\/p>\n<h3>Fallo rapidamente!<\/h3>\n<p>\nUna cosa abbastanza semplice, ma il trucco \u00e8 interessante \u2013 condivider\u00f2, magari a qualcuno interesser\u00e0.<br \/>\nAbbiamo un hash in cui vengono memorizzati i dati firmati. Tutti i dati passano attraverso la cache. La cache non firma specificamente il tempo, ma il Range. Quando viene ricevuto un certo valore, generiamo il Range, mascheriamo gli ultimi 16 bit e firmiamo quel valore:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/f4810456f08ba1cc69730ac0079d4206.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nRicevendo una tale firma, acceleriamo il sistema (in modo ipotetico) di 65 mila volte. Funziona splendidamente: quando abbiamo condotto esperimenti, il tempo per un aggiornamento sequenziale si \u00e8 effettivamente ridotto di 10 mila volte. \u00c8 chiaro che quando sono disordinati, questo non funziona. Ma nella maggior parte dei casi pratici, funziona. La combinazione della firma Range insieme alla firma ha risolto il problema della sicurezza.<\/p>\n<h3>Cosa abbiamo imparato?<\/h3>\n<p>\nLe lezioni che ne abbiamo tratto:<\/p>\n<ul>\n<li>\u00c8 importante leggere materiali, storie, articoli, perch\u00e9 ci sono molte cose interessanti. Quando lavoriamo su una funzione (soprattutto ora, quando abbiamo fatto delle transazioni, ecc.), bisogna leggere e approfondire. Questo richiede tempo, ma \u00e8 davvero molto utile perch\u00e9 diventa chiaro dove ci troviamo. Non abbiamo inventato nulla di nuovo \u2013 abbiamo semplicemente preso ingredienti.\n<p>C'\u00e8 una certa differenza di pensiero quando si tratta di una conferenza accademica (come ad esempio \u00abSigmon\u00bb) \u2013 l\u00ec tutti si concentrano su nuove idee. Qual \u00e8 la novit\u00e0 del nostro algoritmo? Qui non c'\u00e8 nulla di particolarmente nuovo. La novit\u00e0 risiede piuttosto nel modo in cui abbiamo combinato approcci esistenti. Quindi, prima di tutto, \u00e8 necessario leggere i classici, partendo da Lamport.<\/li>\n<li>In produzione ci sono requisiti completamente diversi. Sono sicuro che molti di voi non affrontano database 'sferici' in un vuoto astratto, ma cose normali e reali, che presentano problemi di disponibilit\u00e0, latenza e resilienza agli errori.<\/li>\n<li>Infine, abbiamo dovuto considerare diverse idee e combinare insieme articoli anche molto diversi in un unico approccio. L'idea della firma, ad esempio, proviene da un articolo che trattava il protocollo Paxos, per i failover non byzantini all'interno di un protocollo di autorizzazione, e per quelli byzantini \u2013 al di fuori del protocollo di autorizzazione\u2026 In sostanza, \u00e8 esattamente quello che abbiamo realizzato.\n<p>Non c'\u00e8 assolutamente nulla di nuovo qui! Ma una volta che mescoliamo tutto insieme... \u00c8 come dire che la ricetta dell'insalata russa non conta, perch\u00e9 le uova, la maionese e i cetrioli erano gi\u00e0 stati inventati... \u00c8 pi\u00f9 o meno la stessa storia.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/2f9e5cb77079f9a0f7bdf76430c3386e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCon questo concludo. Grazie!<\/p>\n<h3>Domande<\/h3>\n<p>\n<b>Domanda dal pubblico (d'ora in poi - D):<\/b> \u2013 Grazie, Michail, per la presentazione! L'argomento del tempo \u00e8 interessante. Utilizzate il Gossiping. Avete detto che tutti hanno il proprio tempo, tutti conoscono il proprio orario locale. Ho capito che abbiamo un driver: ci possono essere molti clienti con i loro driver, anche molti query-planner, molti shard... A cosa porta il sistema se dovesse emergere una discrepanza: qualcuno decide che \u00e8 un minuto avanti, qualcun altro \u00e8 un minuto indietro? Dove ci ritroveremo?<\/p>\n<p><b>MT:<\/b> \u2013 Ottima domanda in realt\u00e0! Volevo proprio parlare degli shard. Se ho capito bene la domanda, abbiamo questa situazione: c'\u00e8 lo shard 1 e lo shard 2, la lettura avviene da questi due shard - ci sono delle discrepanze, non interagiscono perch\u00e9 il tempo che conoscono \u00e8 diverso, specialmente il tempo che esiste nei loro log.<br \/>\nSupponiamo che il shard 1 abbia registrato un milione di record, mentre il shard 2 non ne abbia registrato nessuno, e una richiesta sia arrivata a entrambi i shard. Se il primo shard ha un afterClusterTime superiore a un milione, in questa situazione, come ho spiegato, il shard 2 non risponder\u00e0 mai.<\/p>\n<p><b>D:<\/b> \u2013 Volevo sapere come si sincronizzano e scelgono un orario logico?<\/p>\n<p><b>MT:<\/b> \u2013 \u00c8 molto semplice sincronizzarsi. Quando a un shard arriva un afterClusterTime e non trova un'ora nel \"Op-log\", inizia un no approved. In altre parole, imposta manualmente il suo tempo a quel valore. Ci\u00f2 significa che non ha eventi che rispondono a quella richiesta. Crea questo evento artificialmente e diventa quindi Causal Consistent.<\/p>\n<p><b>D:<\/b> \u2013 E se dopo arrivassero ancora eventi che sono stati persi nella rete?<\/p>\n<p><b>MT:<\/b> \u2013 I shard sono progettati in modo tale che non arriveranno, poich\u00e9 si tratta di un single master. Se ha gi\u00e0 registrato, non arriveranno pi\u00f9, ma solo in seguito. Non pu\u00f2 succedere che qualcosa si sia bloccato, poi far\u00e0 un no write e successivamente quegli eventi arriveranno, infrangendo cos\u00ec la Causal consistency. Quando fa un no write, tutti devono arrivare dopo (li attender\u00e0).<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/dbbc7c5c653f0c9fa449cceb88ed62ef.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>D:<\/b> \u2013 Ho alcune domande riguardo alle code. La causal consistency implica che esista una certa sequenza di azioni da eseguire. Cosa succede se un pacchetto va perso? Ecco, va il 10\u00b0, l'11\u00b0\u2026 il 12\u00b0 \u00e8 scomparso, e tutti gli altri stanno aspettando che venga eseguito. E improvvisamente la macchina si guasta, non possiamo fare nulla. C'\u00e8 una lunghezza massima della coda che si accumula prima che venga eseguita? Quale errore fatale si verifica nella perdita di uno stato qualsiasi? Inoltre, se registriamo che c'\u00e8 uno stato precedente, da esso dobbiamo in qualche modo partire? E da esso non siamo partiti!<\/p>\n<p><b>MT:<\/b> \u2013 Anche questa \u00e8 un'ottima domanda! Cosa facciamo? In MongoDB esiste il concetto di scritture in quorum e letture in quorum. In quali circostanze un messaggio potrebbe andare perso? Quando la scrittura non \u00e8 in quorum o quando la lettura non \u00e8 in quorum (potrebbe anche rimanere qualche spazzatura).<br \/>\nRiguardo alla causal consistency, abbiamo effettuato un'ampia verifica sperimentale, i cui risultati hanno mostrato che quando le scritture e le letture non sono in quorum, si verificano violazioni della causal consistency. Esattamente ci\u00f2 che stai dicendo!<\/p>\n<p>Il nostro consiglio: utilizzare almeno la lettura a quorum quando si utilizza la consistenza causale. In questo caso, non verr\u00e0 perso nulla, anche se la scrittura a quorum fallisce... Questa \u00e8 una situazione ortogonale: se un utente non vuole perdere dati, deve usare la scrittura a quorum. La consistenza causale non garantisce durabilit\u00e0. La garanzia di durabilit\u00e0 \u00e8 fornita dalla replica e dalle macchine associate alla replica.<\/p>\n<p><b>D:<\/b> \u2013 Quando creiamo un'istanza che esegue lo sharding (non master, ma slave rispettivamente), si basa sul tempo unix della propria macchina o sul tempo del \"master\"; si sincronizza la prima volta o periodicamente?<\/p>\n<p><b>MT:<\/b> \u2013 Ora chiarir\u00f2. Uno shard (cio\u00e8 una partizione orizzontale) ha sempre un Primary. In uno shard pu\u00f2 esserci un \"master\" e ci possono essere repliche. Ma lo shard supporta sempre la scrittura, perch\u00e9 deve mantenere un certo dominio (in uno shard c'\u00e8 un Primary).<\/p>\n<p><b>D:<\/b> \u2013 Quindi tutto dipende esclusivamente dal \"master\"? Viene sempre usato il tempo del \"master\"?<\/p>\n<p><b>MT:<\/b> \u2013 S\u00ec. Si potrebbe dire metaforicamente: gli orologi ticchettano quando avviene una scrittura nel \"master\", nell'\"Op-log\".<\/p>\n<p><b>D:<\/b> \u2013 Abbiamo un cliente che si connette e non ha bisogno di sapere nulla riguardo al tempo?<\/p>\n<p><b>MT:<\/b> \u2013 Non \u00e8 necessario sapere nulla! Parlando di come funziona per il cliente: il cliente, quando desidera utilizzare la Causal consistency, deve aprire una sessione. Adesso ci sono tutto: sia le transazioni nella sessione, sia il retrieve a rights\u2026 La sessione \u00e8 un ordinamento di eventi logici che avvengono con il cliente.<\/p>\n<p>Se apre questa sessione e afferma di volere la Causal consistency (se per impostazione predefinita la sessione supporta la Causal consistency), tutto funziona automaticamente. Il driver memorizza questo tempo e lo aumenta quando riceve un nuovo messaggio. Ricorda quale risposta ha restituito il server che ha fornito i dati. La richiesta successiva conterr\u00e0 afterCluster (\u00abtempo superiore a questo\u00bb).<\/p>\n<p>Il cliente non deve sapere davvero nulla! \u00c8 completamente opaco per lui. Se le persone utilizzano queste funzionalit\u00e0, cosa potrebbe permettere? Prima di tutto, \u00e8 possibile leggere in modo sicuro dai secondari: si pu\u00f2 scrivere sul Primary e leggere da secondari replicati geograficamente, ed essere certi che funzioni. In questo modo, le sessioni registrate sul Primary possono essere trasferite anche ai Secondary, cio\u00e8 si possono utilizzare pi\u00f9 sessioni invece di una sola.<\/p>\n<p><b>D:<\/b> \u2013 \u00c8 strettamente correlata al tema della coerenza eventuale una nuova branca della scienza computazionale: i tipi di dati CRDT (Conflict-free Replicated Data Types). Avete considerato l'integrazione di questi tipi di dati nel database e cosa ne pensate?<\/p>\n<p><b>MT:<\/b> \u2013 Ottima domanda! CRDT ha senso per i conflitti durante la scrittura: in MongoDB \u2013 single master.<\/p>\n<p><b>D:<\/b> \u2013 Ho una domanda dagli sviluppatori DevOps. Nel mondo reale ci sono situazioni subdole, in cui si verifica un fallimento bizantino, e persone malintenzionate all'interno di un perimetro protetto iniziano a interferire con il protocollo, inviando pacchetti craftati in modo speciale?<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/99a521d04b416e6978aa68ce7c4a4c46.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>MT:<\/b> \u2013 Le persone malintenzionate all'interno del perimetro sono come un cavallo di Troia! Possono fare molte cose cattive.<\/p>\n<p><b>D:<\/b> \u2013 \u00c8 evidente che lasciare nel server, per cos\u00ec dire, un varco attraverso cui pu\u00f2 passare uno zoo di elefanti, pu\u00f2 andare a compromettere l'intero cluster per sempre... Ci vorr\u00e0 tempo per un ripristino manuale... Questo, a dir poco, \u00e8 inaccettabile. D'altra parte, \u00e8 curioso sapere: nella vita reale, nella pratica, si verificano situazioni in cui attacchi interni di questo tipo accadono realmente?<\/p>\n<p><b>MT:<\/b> \u2013 Poich\u00e9 non mi capita spesso di affrontare violazioni della sicurezza nella vita reale, non posso dire se accadano. Ma parlando della filosofia di sviluppo, riteniamo questo: abbiamo un perimetro che garantisce a coloro che si occupano della sicurezza \u2013 \u00e8 un lucchetto, un muro; e all'interno del perimetro si pu\u00f2 fare tutto ci\u00f2 che si vuole. \u00c8 chiaro che ci sono utenti con la possibilit\u00e0 solo di visualizzare e altri che possono eliminare il catalogo.<\/p>\n<p>A seconda dei privilegi, il danno che gli utenti possono infliggere pu\u00f2 variare da un clic del mouse a una distruzione totale. \u00c8 chiaro che un utente con pieni diritti pu\u00f2 fare praticamente qualsiasi cosa. Un utente con diritti limitati pu\u00f2 causare un danno significativamente inferiore. In particolare, non pu\u00f2 rompere il sistema.<\/p>\n<p><b>D:<\/b> \u2013 All'interno di un perimetro sicuro, ci sono persone che creano protocolli inaspettati per il server, per metterlo sotto stress, e se va bene, anche l'intero cluster... \u00c8 mai cos\u00ec \"buono\"?<\/p>\n<p><b>MT:<\/b> \u2013 Non ho mai sentito parlare di queste cose. Che sia possibile sovraccaricare un server in questo modo non \u00e8 un segreto. Sovraccaricarlo dall'interno, essendo un utente autorizzato che pu\u00f2 registrare un messaggio... In realt\u00e0 non \u00e8 possibile, perch\u00e9 comunque ci sar\u00e0 una verifica. C'\u00e8 la possibilit\u00e0 di disattivare questa autenticazione per quegli utenti che non la vogliono \u2013 sono affari loro; in un certo senso, hanno abbattuto le mura e possono farci entrare un elefante che schiaccer\u00e0... In effetti, si pu\u00f2 vestire da tecnico, venire e rimuovere!<\/p>\n<p><b>D:<\/b> \u2013 Grazie per la relazione. Sergey (\"Yandex\"). In \"Mongo\" c'\u00e8 una costante che limita il numero di membri votanti nel Replica Set, e questa costante \u00e8 7 (sette). Perch\u00e9 \u00e8 una costante? Perch\u00e9 non \u00e8 un parametro qualsiasi?<\/p>\n<p><b>MT:<\/b> \u2013 Nel Replica Set abbiamo anche 40 nodi. C'\u00e8 sempre una maggioranza. Non so quale versione...<\/p>\n<p><b>D:<\/b> \u2013 Nel Replica Set si possono avviare membri non votanti, ma per i votanti il massimo \u00e8 7. Come ci si comporta in questo caso in caso di spegnimento, se il nostro Replica Set \u00e8 distribuito su 3 data center? Un data center pu\u00f2 facilmente spegnersi e un'altra macchina pu\u00f2 andare offline.<\/p>\n<p><b>MT:<\/b> \u2013 Questo \u00e8 gi\u00e0 un po' oltre il rapporto. \u00c8 una questione generale. Forse posso parlarne pi\u00f9 tardi.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Michail Tuleev (MongoDB): Coerenza causale: dalla teoria alla pratica\" src=\"\/wp-content\/uploads\/2020\/02\/161966c7e77704dc619674ff0302ff57.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<center><div class=\"youtube-placeholder\" data-id=\"UnAprFMX1d4\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/UnAprFMX1d4\/hqdefault.jpg\" alt=\"Riproduci video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><\/p>\n<h3>Un po' di pubblicit\u00e0 \ud83d\ude42<\/h3>\n<p>\nGrazie per essere con noi. Ti piacciono i nostri articoli? Vuoi vedere pi\u00f9 contenuti interessanti? Supportaci effettuando un ordine o raccomandandoci ai tuoi conoscenti, <noindex><a rel=\"nofollow\" href=\"https:\/\/ua-hosting.company\/cloudvps\/nl\">VPS cloud per sviluppatori a partire da $4,99<\/a><\/noindex>, <b>un'alternativa unica ai server entry-level, che abbiamo creato per te:<\/b> <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/ua-hosting\/blog\/347386\/\">Tutta la verit\u00e0 su VPS (KVM) E5-2697 v3 (6 Core) 10GB DDR4 480GB SSD 1Gbps a partire da $19. Come dividere il server correttamente?<\/a><\/noindex> (disponibili opzioni con RAID1 e RAID10, fino a 24 core e fino a 40GB DDR4).<\/p>\n<p><b>Dell R730xd a met\u00e0 prezzo nel data center Equinix Tier IV ad Amsterdam?<\/b> Solo da noi <b><noindex><a rel=\"nofollow\" href=\"https:\/\/ua-hosting.company\/serversnl\">2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TB a partire da $199<\/a><\/noindex> nei Paesi Bassi! <b>Dell R420 \u2014 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB \u2014 a partire da $99!<\/b><\/b> Scopri di pi\u00f9 su <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/ua-hosting\/blog\/329618\/\">Come costruire un'infrastruttura di classe enterprise con server Dell R730xd E5-2650 v4 dal costo di 9000 euro a prezzi stracciati?<\/a><\/noindex><br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ua-hosting\/blog\/487638\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435. HighLoad++ Siberia 2019. \u0417\u0430\u043b \u00ab\u041a\u0440\u0430\u0441\u043d\u043e\u044f\u0440\u0441\u043a\u00bb. 25 \u0438\u044e\u043d\u044f, 12:00. \u0422\u0435\u0437\u0438\u0441\u044b \u0438 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u044f. \u0411\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u0443\u044e\u0442 \u0441 \u0442\u0435\u043e\u0440\u0438\u0435\u0439, \u0433\u0434\u0435 \u043d\u0435 \u0443\u0447\u0442\u0435\u043d\u044b \u0432\u0430\u0436\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u0430\u0441\u043f\u0435\u043a\u0442\u044b. \u0412 \u044d\u0442\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u044b\u0431\u043e\u0440\u0430 \u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-56365","post","type-post","status-publish","format-standard","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=\"\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435.\" \/>\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\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike\" \/>\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\udd47HighLoad++, \u041c\u0438\u0445\u0430\u0438\u043b \u0422\u044e\u043b\u0435\u043d\u0435\u0432 (MongoDB): Causal consistency: \u043e\u0442 \u0442\u0435\u043e\u0440\u0438\u0438 \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike\" \/>\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-02-10T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:04:37+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\udd47HighLoad++, Michail Tjulenjev (MongoDB): Coerenza causale: dalla teoria alla pratica | ProHoster","description":"La prossima conferenza HighLoad++ si terr\u00e0 il 6 e 7 aprile 2020 a San Pietroburgo. Maggiori dettagli e biglietti sono disponibili al link.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","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\udd47HighLoad++, \u041c\u0438\u0445\u0430\u0438\u043b \u0422\u044e\u043b\u0435\u043d\u0435\u0432 (MongoDB): Causal consistency: \u043e\u0442 \u0442\u0435\u043e\u0440\u0438\u0438 \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 | ProHoster","og:description":"\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435.","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","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-02-10T21:00:00+00:00","article:modified_time":"2020-02-18T11:04:37+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"56365","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 19:26:38","updated":"2022-09-29 16:36:31","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\/56365","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=56365"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/56365\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=56365"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=56365"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=56365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}