{"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\/pt\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","title":{"rendered":"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>A pr\u00f3xima confer\u00eancia HighLoad++ ocorrer\u00e1 nos dias 6 e 7 de abril de 2020 em S\u00e3o Petersburgo. <br \/>\nDetalhes e ingressos <noindex><a rel=\"nofollow\" href=\"http:\/\/bit.ly\/2sSxgBx\">no link<\/a><\/noindex>. HighLoad++ Sib\u00e9ria 2019. Sala \"Krasnoyarsk\". 25 de junho, 12:00. Teses e <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/siberia\/2019\/abstracts\/5253\">apresenta\u00e7\u00e3o<\/a><\/noindex>.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/cded9c5434d670db7295aadf5da0a9f1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c0s vezes, as demandas pr\u00e1ticas entram em conflito com a teoria, onde aspectos importantes para um produto comercial n\u00e3o s\u00e3o considerados. Nesta apresenta\u00e7\u00e3o, ser\u00e1 apresentado o processo de sele\u00e7\u00e3o e combina\u00e7\u00e3o de diferentes abordagens para a cria\u00e7\u00e3o de componentes de consist\u00eancia causal com base em pesquisas acad\u00eamicas, levando em considera\u00e7\u00e3o os requisitos de um produto comercial. Os ouvintes aprender\u00e3o sobre as abordagens te\u00f3ricas existentes em rel\u00f3gios l\u00f3gicos, rastreamento de depend\u00eancias, seguran\u00e7a de sistemas, sincroniza\u00e7\u00e3o de rel\u00f3gios e por que o MongoDB optou por determinadas solu\u00e7\u00f5es.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><b>Mikhail Tyulenev (daqui em diante \u2013 MT):<\/b> \u2013 Vou falar sobre a consist\u00eancia causal \u2013 \u00e9 um recurso em que trabalhamos no MongoDB. Eu trabalho no grupo de sistemas distribu\u00eddos, n\u00f3s o desenvolvemos h\u00e1 cerca de dois anos.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/b8d0a5b64e715f53b033fa8c398e2eb4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDurante o processo, tive que me familiarizar com uma grande quantidade de pesquisa acad\u00eamica, porque esse recurso \u00e9 bastante estudado. Ficou claro que nenhum artigo se encaixa exatamente no que \u00e9 necess\u00e1rio em produ\u00e7\u00e3o, considerando os requisitos bastante espec\u00edficos que existem, provavelmente, em qualquer aplicativo de produ\u00e7\u00e3o.<\/p>\n<p>Vou falar sobre como n\u00f3s, enquanto consumidores de pesquisa acad\u00eamica, preparamos algo que podemos apresentar aos nossos usu\u00e1rios como um prato acabado, que seja conveniente e seguro para uso.<\/p>\n<h3>Consist\u00eancia causal (Causal consistency). Vamos definir os conceitos<\/h3>\n<p>\nPara come\u00e7ar, quero falar em termos gerais sobre o que \u00e9 a consist\u00eancia causal. Existem dois personagens \u2013 Leonard e Penny (da s\u00e9rie \"The Big Bang Theory\"):<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/ee0835b604ae5d5d6c0fa1bc369e6b18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSuponha que Penny esteja na Europa, e Leonard queira fazer uma surpresa para ela, uma festa. E n\u00e3o consegue pensar em nada melhor do que retir\u00e1-la da lista de amigos, enviar a todos os amigos uma atualiza\u00e7\u00e3o no feed: \"Vamos alegrar a Penny!\" (ela est\u00e1 na Europa, enquanto dorme, n\u00e3o v\u00ea nada disso e n\u00e3o pode ver, porque n\u00e3o est\u00e1 l\u00e1). No final, ele exclui essa postagem, apaga do \"Feed\" e restaura o acesso, para que ela n\u00e3o perceba nada e n\u00e3o haja esc\u00e2ndalo.<br \/>\nIsso tudo \u00e9 maravilhoso, mas vamos supor que o sistema seja distribu\u00eddo e os eventos n\u00e3o ocorreram exatamente como planejado. Por exemplo, pode acontecer que a limita\u00e7\u00e3o de acesso de Penny tenha ocorrido depois que esta postagem foi publicada, caso os eventos n\u00e3o estejam relacionados por uma causalidade. Na verdade, isso \u00e9 um exemplo de quando a consist\u00eancia causal \u00e9 necess\u00e1ria para que uma fun\u00e7\u00e3o de neg\u00f3cios (neste caso) seja executada.<\/p>\n<p>Na verdade, essas s\u00e3o propriedades bastante n\u00e3o triviais de bancos de dados \u2013 muito poucas as suportam. Vamos passar para os modelos.<\/p>\n<h3>Modelos de consist\u00eancia<\/h3>\n<p>\nO que \u00e9 um modelo de consist\u00eancia em bancos de dados? S\u00e3o algumas garantias que um sistema distribu\u00eddo oferece sobre quais dados e em que sequ\u00eancia o cliente pode receber.<\/p>\n<p>Basicamente, todos os modelos de consist\u00eancia se resumem a qu\u00e3o similar um sistema distribu\u00eddo \u00e9 a um sistema que opera, por exemplo, em um \u00fanico n\u00f3 em um laptop. E o quanto um sistema que opera em milhares de \"n\u00f3s\" geograficamente distribu\u00eddos se assemelha ao laptop, onde todas essas propriedades s\u00e3o cumpridas automaticamente.<\/p>\n<p>Portanto, os modelos de consist\u00eancia se aplicam apenas a sistemas distribu\u00eddos. Todos os sistemas existentes anteriormente, que operavam em escalabilidade vertical, n\u00e3o enfrentavam esses problemas. Havia um \u00fanico Buffer Cache, e tudo era sempre lido dele.<\/p>\n<h3>Modelo Forte<\/h3>\n<p>\nNa verdade, o primeiro modelo \u00e9 o Forte (ou a linha de capacidade, como muitas vezes \u00e9 chamado). Este \u00e9 um modelo de consist\u00eancia que garante que cada altera\u00e7\u00e3o, assim que recebe a confirma\u00e7\u00e3o de sua realiza\u00e7\u00e3o, se torna vis\u00edvel para todos os usu\u00e1rios do sistema.<\/p>\n<p>Isso cria uma ordem global de todos os eventos no banco de dados. Esta \u00e9 uma propriedade de consist\u00eancia muito forte e, na verdade, \u00e9 bastante cara. No entanto, \u00e9 muito bem suportada. \u00c9 apenas muito cara e lenta \u2013 e portanto raramente utilizada. Isso \u00e9 chamado de capacidade.<\/p>\n<p>H\u00e1 outra propriedade, ainda mais forte, que \u00e9 suportada no \"Spanner\" \u2013 chamada de Consist\u00eancia Externa. Vamos falar sobre isso um pouco mais tarde.<\/p>\n<h3>Causal<\/h3>\n<p>\nA seguir est\u00e1 o Causal, exatamente do que eu estava falando. Entre Strong e Causal existem v\u00e1rios subn\u00edveis, dos quais n\u00e3o vou falar, mas todos eles se referem ao Causal. Este \u00e9 um modelo importante, pois \u00e9 o mais forte de todos os modelos, apresentando a mais forte consist\u00eancia em caso de rede ou parti\u00e7\u00f5es.<\/p>\n<p>Causals s\u00e3o, propriamente dito, a situa\u00e7\u00e3o em que os eventos est\u00e3o relacionados por uma rela\u00e7\u00e3o de causa e efeito. Muitas vezes, eles s\u00e3o percebidos como Read your on rights do ponto de vista do cliente. Se o cliente observou alguns valores, ele n\u00e3o pode ver os valores que estavam no passado. Ele j\u00e1 come\u00e7a a ver leituras prefixadas. Tudo isso se resume \u00e0 mesma quest\u00e3o.<br \/>\nCausals como modelo de consist\u00eancia \u2013 uma ordena\u00e7\u00e3o parcial de eventos no servidor, onde eventos de todos os clientes s\u00e3o observados na mesma sequ\u00eancia. Neste caso \u2013 Leonard e Penny.<\/p>\n<h3>Eventual<\/h3>\n<p>\nO terceiro modelo \u00e9 a Eventual Consistency. Este \u00e9 o que todas as sistemas distribu\u00eddos absolutamente suportam, sendo o modelo m\u00ednimo que faz sentido. Isso significa o seguinte: quando temos algumas altera\u00e7\u00f5es nos dados, elas, em algum momento, se tornam consistentes.<\/p>\n<p>Nesse momento, ela n\u00e3o diz nada, caso contr\u00e1rio, se tornaria External Consistency \u2013 seria uma hist\u00f3ria completamente diferente. No entanto, este \u00e9 um modelo muito popular, o mais amplamente utilizado. Por padr\u00e3o, todos os usu\u00e1rios de sistemas distribu\u00eddos utilizam a Eventual Consistency.<\/p>\n<p>Quero trazer alguns exemplos comparativos:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/c23e59b30d96de6ec456aaa76c67ad61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO que essas setas significam?<\/p>\n<ul>\n<li><b>Lat\u00eancia.<\/b> Com o aumento da for\u00e7a da consist\u00eancia, ela se torna maior por raz\u00f5es compreens\u00edveis: \u00e9 necess\u00e1rio fazer mais grava\u00e7\u00f5es, obter confirma\u00e7\u00e3o de todos os hosts e n\u00f3s que participam do cluster que os dados j\u00e1 est\u00e3o l\u00e1. Assim, na Eventual Consistency, a resposta \u00e9 a mais r\u00e1pida, pois, geralmente, pode-se at\u00e9 mesmo fazer o commit em mem\u00f3ria e isso ser\u00e1, em princ\u00edpio, suficiente.<\/li>\n<li><b>Disponibilidade.<\/b> Se compreendermos isso como a capacidade do sistema de responder na presen\u00e7a de falhas na rede, parti\u00e7\u00f5es ou alguma outra falha \u2013 a resili\u00eancia aumenta \u00e0 medida que o modelo de consist\u00eancia diminui, uma vez que \u00e9 suficiente que um host esteja ativo e forne\u00e7a alguns dados. A Eventual Consistency n\u00e3o garante nada em rela\u00e7\u00e3o aos dados \u2013 pode ser qualquer coisa.<\/li>\n<li><b>Anomalias.<\/b> Ao mesmo tempo, \u00e9 claro que o n\u00famero de anomalias aumenta. Na consist\u00eancia forte, elas praticamente n\u00e3o deveriam existir, enquanto na consist\u00eancia eventual, podem ocorrer de qualquer forma. Surge a pergunta: por que as pessoas escolhem a consist\u00eancia eventual, se ela cont\u00e9m anomalias? A resposta \u00e9 que os modelos de consist\u00eancia eventual s\u00e3o aplic\u00e1veis, e as anomalias existem, por exemplo, por um curto per\u00edodo; h\u00e1 a possibilidade de usar uma c\u00f3pia para leitura e obter dados mais ou menos consistentes; frequentemente h\u00e1 a op\u00e7\u00e3o de utilizar modelos de consist\u00eancia mais robustos. Na pr\u00e1tica, isso funciona, e muitas vezes o n\u00famero de anomalias \u00e9 limitado no tempo.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Teorema CAP<\/h3>\n<p>\nQuando voc\u00ea v\u00ea as palavras consist\u00eancia, disponibilidade \u2013 o que vem \u00e0 sua mente? Certo \u2013 o teorema CAP! Agora quero desmistificar\u2026 N\u00e3o sou eu \u2013 \u00e9 Martin Kleppmann, que escreveu um excelente artigo, um \u00f3timo livro.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/02a9b84585218c4e85afd65f7e88aa26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO teorema CAP \u00e9 um princ\u00edpio formulado nos anos 2000, que diz que Consist\u00eancia, Disponibilidade, Parti\u00e7\u00f5es: escolha qualquer dois, e n\u00e3o \u00e9 poss\u00edvel ter os tr\u00eas. Essa foi uma esp\u00e9cie de princ\u00edpio. Ele foi provado como um teorema alguns anos depois, feito por Gilbert e Lynch. Depois, passou a ser utilizado como um mantra \u2013 os sistemas come\u00e7aram a se dividir em CA, CP, AP, e assim por diante.<\/p>\n<p>Esse teorema foi realmente provado para os seguintes casos... Primeiro, a Disponibilidade n\u00e3o foi considerada como um valor cont\u00ednuo de zero a cem (0 \u2013 sistema 'morto', 100 \u2013 responde rapidamente; \u00e9 assim que estamos acostumados a ver), mas como uma propriedade do algoritmo, que garante que em todas as suas execu\u00e7\u00f5es, ele retorna dados.<\/p>\n<p>N\u00e3o se fala nada sobre o tempo de resposta! H\u00e1 um algoritmo que retorna dados em 100 anos \u2013 um algoritmo dispon\u00edvel absolutamente maravilhoso, que \u00e9 parte do teorema CAP.<br \/>\nEm segundo lugar: o teorema foi provado para altera\u00e7\u00f5es nos valores de uma mesma chave, sendo essas altera\u00e7\u00f5es uma linha redimension\u00e1vel. Isso significa que na pr\u00e1tica, elas s\u00e3o raramente utilizadas, pois existem outros modelos como Consist\u00eancia Eventual, Consist\u00eancia Forte (pode ser).<\/p>\n<p>Para que tudo isso? Para mostrar que o teorema CAP, na forma em que foi provado, \u00e9 praticamente inapplic\u00e1vel, raramente utilizado. Na forma te\u00f3rica, ele de alguma forma limita tudo. Surge assim um princ\u00edpio que \u00e9 intuitivamente verdadeiro, mas n\u00e3o est\u00e1 de fato provado.<\/p>\n<h3>Consist\u00eancia causal \u2013 \u00e9 o modelo mais forte<\/h3>\n<p>\nO que est\u00e1 acontecendo agora \u00e9 que se pode obter as tr\u00eas coisas: Consist\u00eancia, Disponibilidade com a ajuda de Parti\u00e7\u00f5es. Em particular, a consist\u00eancia causal \u2013 \u00e9 o modelo de consist\u00eancia mais forte, que mesmo na presen\u00e7a de Parti\u00e7\u00f5es (interrup\u00e7\u00f5es na rede) ainda funciona. Por isso, \u00e9 de grande interesse, e foi por isso que nos dedicamos a isso.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/c4320294320261858a6d22faa97b9e23.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIsso, em primeiro lugar, simplifica o trabalho dos desenvolvedores de aplicativos. Em particular, a grande quantidade de suporte do servidor: quando todos os registros que ocorrem dentro de um \u00fanico cliente chegam garantidamente em tal sequ\u00eancia para outro cliente. Em segundo lugar, ela suporta parti\u00e7\u00f5es.<\/p>\n<h3>Os bastidores do MongoDB<\/h3>\n<p>\nLembrando que \u00e9 hora do almo\u00e7o, n\u00f3s nos dirigimos \u00e0 cozinha. Eu vou explicar o modelo do sistema, ou seja, o que \u00e9 o MongoDB para aqueles que est\u00e3o ouvindo sobre esse banco de dados pela primeira vez.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/a1784442ff1c44403b5347f4f43a1197.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/a1f9bcb4daebb43e4fc848a5f5f07c60.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMongoDB (daqui em diante \u2013 \u00abMongoDB\u00bb) \u00e9 um sistema distribu\u00eddo que suporta escalabilidade horizontal, ou seja, sharding; e dentro de cada shard, tamb\u00e9m suporta redund\u00e2ncia de dados, ou seja, replica\u00e7\u00e3o.<\/p>\n<p>O sharding no \u00abMongoDB\u00bb (um banco de dados n\u00e3o relacional) realiza balanceamento autom\u00e1tico, ou seja, cada cole\u00e7\u00e3o de documentos (ou \u00abtabela\u00bb nos termos de dados relacionais) \u00e9 dividida em peda\u00e7os, e o servidor automaticamente os movimenta entre os shards.<\/p>\n<p>O Query Router, que distribui as requisi\u00e7\u00f5es, \u00e9 um cliente atrav\u00e9s do qual o cliente trabalha. Ele j\u00e1 sabe onde e quais dados est\u00e3o, e direciona todas as requisi\u00e7\u00f5es para o shard correto.<\/p>\n<p>Outro ponto importante: o MongoDB \u00e9 um \u00fanico master. H\u00e1 um Primary \u2013 ele pode receber registros que suportam as chaves que possui. N\u00e3o \u00e9 poss\u00edvel fazer a grava\u00e7\u00e3o em m\u00faltiplos mestres.<\/p>\n<p>Lan\u00e7amos a vers\u00e3o 4.2 \u2013 l\u00e1 apareceram novas coisas interessantes. Em particular, inserimos o Lucene \u2013 busca \u2013 exatamente o java execut\u00e1vel dentro do \u00abMongo\u00bb, e agora \u00e9 poss\u00edvel fazer buscas atrav\u00e9s do Lucene, assim como no \u00abEl\u00e1stico\u00bb.<\/p>\n<p>E criamos um novo produto \u2013 Charts, que tamb\u00e9m est\u00e1 dispon\u00edvel no \u00abAtlas\u00bb (o pr\u00f3prio Cloud do \u00abMongo\u00bb). Eles t\u00eam uma Free Tier \u2013 pode-se brincar com isso. Eu gostei muito do Charts \u2013 visualiza\u00e7\u00e3o de dados muito intuitiva.<\/p>\n<h3>Ingredientes da consist\u00eancia causal<\/h3>\n<p>\nEu contei cerca de 230 artigos que foram publicados sobre esse tema \u2013 de Leslie Lampert. Agora, da minha mem\u00f3ria, eu vou compartilhar algumas partes desses materiais com voc\u00eas.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/e88b34b7a724e94837b944a4ddd21a04.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTudo come\u00e7ou com o artigo de Leslie Lampert, escrito na d\u00e9cada de 1970. Como voc\u00ea pode ver, ainda h\u00e1 pesquisas em andamento sobre esse tema. Atualmente, a consist\u00eancia causal est\u00e1 despertando interesse devido ao desenvolvimento de sistemas distribu\u00eddos.<\/p>\n<h3>Restri\u00e7\u00f5es<\/h3>\n<p>\nQuais s\u00e3o as restri\u00e7\u00f5es? Este \u00e9 realmente um dos principais pontos, pois as limita\u00e7\u00f5es impostas por sistemas de produ\u00e7\u00e3o diferem muito das restri\u00e7\u00f5es existentes em artigos acad\u00eamicos. Muitas vezes, elas s\u00e3o bastante artificiais.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/9583ba9ff870e4ddc7aad4ba4c59ecc1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Primeiro, \u2018MongoDB\u2019 \u00e9 um mestre \u00fanico, como j\u00e1 mencionei (isso simplifica bastante).<\/li>\n<li>Acreditamos que o sistema deve suportar cerca de 10 mil shards. N\u00e3o podemos tomar decis\u00f5es arquitet\u00f4nicas que limitem esse valor.<\/li>\n<li>Temos uma nuvem, mas acreditamos que o usu\u00e1rio deve ter a capacidade de baixar um bin\u00e1rio e execut\u00e1-lo em seu laptop, e tudo deve funcionar perfeitamente.<\/li>\n<li>Supomos que na pesquisa raramente se use: clientes externos podem fazer o que quiserem. \u2018MongoDB\u2019 \u00e9 open source. Portanto, os clientes podem ser inteligentes ou maliciosos \u2013 podem querer quebrar tudo. Supomos que podem ocorrer falhas bizantinas.<\/li>\n<li>Para clientes externos, que est\u00e3o fora do per\u00edmetro \u2013 uma limita\u00e7\u00e3o importante: se esse recurso estiver desativado, n\u00e3o deve haver degrada\u00e7\u00e3o de desempenho.<\/li>\n<li>Outro ponto \u2013 completamente anti-acad\u00eamico: compatibilidade de vers\u00f5es anteriores e futuras. Drivers antigos devem suportar novas atualiza\u00e7\u00f5es, e o banco de dados deve suportar drivers antigos.<\/li>\n<\/ul>\n<p>\nNo geral, tudo isso imp\u00f5e restri\u00e7\u00f5es.<\/p>\n<h3>Componentes da consist\u00eancia causal<\/h3>\n<p>\nAgora falarei sobre alguns componentes. Se considerarmos a consist\u00eancia causal em geral, podemos destacar blocos. Escolhemos trabalhos que se relacionam a cada bloco: rastreamento de depend\u00eancias, escolha de rel\u00f3gios, como sincronizar esses rel\u00f3gios entre si e como garantimos a seguran\u00e7a \u2013 este \u00e9 um plano geral do que discutirei:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/10c2631d6e61a280139b448628db763e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Rastreamento completo de depend\u00eancias (Full Dependency Tracking)<\/h3>\n<p>\nPara que serve isso? Para que, quando os dados s\u00e3o replicados, cada registro e cada altera\u00e7\u00e3o contenham informa\u00e7\u00f5es sobre as mudan\u00e7as das quais dependem. A primeira e mais ing\u00eanua altera\u00e7\u00e3o \u00e9 quando cada mensagem que cont\u00e9m um registro tamb\u00e9m traz informa\u00e7\u00f5es sobre mensagens anteriores:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/fa5d0086c3c77e33631d8a2cd5c217fa.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNeste exemplo, o n\u00famero entre chaves \u00e9 o n\u00famero dos registros. \u00c0s vezes, esses registros com valores s\u00e3o transmitidos inteiros, \u00e0s vezes, algumas vers\u00f5es s\u00e3o passadas. A ess\u00eancia \u00e9 que cada altera\u00e7\u00e3o cont\u00e9m informa\u00e7\u00f5es sobre a anterior (isso est\u00e1 claramente impl\u00edcito).<\/p>\n<p>Por que decidimos n\u00e3o usar essa abordagem (rastreamento completo)? Obviamente, porque essa abordagem \u00e9 impr\u00e1tica: qualquer altera\u00e7\u00e3o em uma rede social depende de todas as altera\u00e7\u00f5es anteriores nessa rede social, transmitindo, por exemplo, \"Facebook\" ou \"Vkontakte\" em cada atualiza\u00e7\u00e3o. No entanto, existem muitos estudos sobre o Full Dependency Tracking \u2013 isso \u00e9 pre-rede social, para algumas situa\u00e7\u00f5es realmente funciona.<\/p>\n<h3>Rastreamento de Depend\u00eancias Expl\u00edcitas (Explicit Dependency Tracking)<\/h3>\n<p>\nO pr\u00f3ximo \u00e9 mais limitado. Aqui tamb\u00e9m se analisa a transmiss\u00e3o de informa\u00e7\u00f5es, mas apenas aquelas que s\u00e3o explicitamente dependentes. O que depende de qu\u00ea \u00e9, geralmente, definido pela Aplica\u00e7\u00e3o. Quando os dados s\u00e3o replicados, respostas s\u00e3o fornecidas apenas quando as depend\u00eancias anteriores foram atendidas, ou seja, exibidas. Essa \u00e9 a ess\u00eancia de como funciona a consist\u00eancia causal.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/7fe101b998c1a0c922788d8d36a5243f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEla v\u00ea que o registro 5 depende dos registros 1, 2, 3, 4 \u2013 portanto, ela espera antes que o cliente acesse as mudan\u00e7as feitas pela decis\u00e3o de acesso de Penny, quando todas as mudan\u00e7as anteriores j\u00e1 passaram pelo banco de dados.<\/p>\n<p>Isso tamb\u00e9m n\u00e3o nos agrada, porque ainda assim h\u00e1 informa\u00e7\u00e3o demais, e isso acabar\u00e1 tornando tudo mais lento. Existe outra abordagem\u2026<\/p>\n<h3>Rel\u00f3gio de Lamport (Lamport Clock)<\/h3>\n<p>\nEles s\u00e3o muito antigos. O Rel\u00f3gio de Lamport implica que essas depend\u00eancias se condensam em uma fun\u00e7\u00e3o escalar, que \u00e9 chamada de Rel\u00f3gio de Lamport.<\/p>\n<p>A fun\u00e7\u00e3o escalar \u00e9 um n\u00famero abstrato. Muitas vezes \u00e9 chamado de tempo l\u00f3gico. A cada evento, esse contador aumenta. O contador que \u00e9 conhecido pelo processo atualmente envia cada mensagem. \u00c9 claro que os processos podem estar dessincronizados e ter tempos completamente diferentes. No entanto, esse tipo de troca de mensagens permite que o sistema balanceie os rel\u00f3gios de alguma forma. O que acontece neste caso?<\/p>\n<p>Eu dividi aquele grande shard em dois para ficar mais claro: os Friends podem viver em um n\u00f3 que cont\u00e9m uma parte da cole\u00e7\u00e3o, enquanto o Feed pode estar em um outro n\u00f3 que cont\u00e9m uma parte dessa cole\u00e7\u00e3o. Como eles podem n\u00e3o ficar na fila? Primeiro o Feed dir\u00e1: 'Replicado', e depois os Friends. Se o sistema n\u00e3o oferecer garantias de que o Feed n\u00e3o ser\u00e1 mostrado at\u00e9 que as depend\u00eancias dos Friends na cole\u00e7\u00e3o de Friends tamb\u00e9m sejam entregues, teremos exatamente a situa\u00e7\u00e3o que mencionei.<\/p>\n<p>Voc\u00ea pode ver como o tempo l\u00f3gico do contador aumenta no Feed:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/bae152d1890b53804f2cb28122983df6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAssim, a propriedade principal desse Rel\u00f3gio de Lamport e Consist\u00eancia Causal (explicada atrav\u00e9s do Rel\u00f3gio de Lamport) \u00e9 a seguinte: se temos os eventos A e B, e o evento B depende do evento A *, ent\u00e3o isso implica que o LogicalTime do Evento A \u00e9 menor que o LogicalTime do Evento B.<\/p>\n<p><i>* \u00c0s vezes, diz-se que A aconteceu antes de B, ou seja, A ocorreu antes de B \u2013 esse \u00e9 um relacionamento que parcialmente ordena todo o conjunto de eventos que realmente aconteceram.<\/i><\/p>\n<p>O inverso n\u00e3o \u00e9 verdade. Esse \u00e9, na verdade, um dos principais contras do Rel\u00f3gio de Lamport \u2013 a ordem parcial. H\u00e1 o conceito de eventos simult\u00e2neos, ou seja, eventos em que nem (A aconteceu antes de B) nem (A aconteceu depois de B) se aplicam. Um exemplo pode ser a adi\u00e7\u00e3o paralela de algu\u00e9m como amigo por Leonard (n\u00e3o por Leonard, mas por Sheldon, por exemplo).<br \/>\nEssa \u00e9 uma propriedade que \u00e9 frequentemente utilizada ao trabalhar com rel\u00f3gios de Lamport: observa-se precisamente a fun\u00e7\u00e3o e a partir disso se deduz \u2013 pode ser que esses eventos sejam dependentes. Porque em uma dire\u00e7\u00e3o isso \u00e9 verdade: se o LogicalTime A \u00e9 menor que o LogicalTime B, ent\u00e3o B n\u00e3o pode ter ocorrido antes de A; mas se for maior, pode ser.<\/p>\n<h3>Rel\u00f3gios vetoriais (Vector Clock)<\/h3>\n<p>\nO desenvolvimento l\u00f3gico do rel\u00f3gio de Lamport \u2013 s\u00e3o os Rel\u00f3gios Vetoriais. Eles se diferenciam pelo fato de que cada n\u00f3 presente aqui cont\u00e9m seus pr\u00f3prios rel\u00f3gios separados, que s\u00e3o transmitidos como um vetor.<br \/>\nNeste caso, voc\u00ea v\u00ea que o \u00edndice zero do vetor representa o Feed, e o primeiro \u00edndice do vetor representa os Amigos (cada um desses n\u00f3s). E agora eles v\u00e3o aumentar: o \u00edndice zero do 'Feed' aumenta a cada grava\u00e7\u00e3o \u2013 1, 2, 3:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/d89292686ed8dd41aef06090f16db1c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPor que os rel\u00f3gios vetoriais s\u00e3o melhores? Porque eles permitem entender quais eventos s\u00e3o simult\u00e2neos e quando ocorrem em diferentes n\u00f3s. Isso \u00e9 muito importante para um sistema de sharding, como o 'MongoDB'. Entretanto, n\u00e3o escolhemos isso, embora seja algo incr\u00edvel, que funciona maravilhosamente bem e que provavelmente seria adequado para n\u00f3s\u2026<\/p>\n<p>Se temos 10 mil shards, n\u00e3o conseguimos transferir 10 mil componentes, mesmo comprimindo ou pensando em outras solu\u00e7\u00f5es \u2013 ainda assim, a carga \u00fatil ser\u00e1 v\u00e1rias vezes menor do que o volume total desse vetor. Portanto, com pesar, desistimos dessa abordagem e partimos para outra.<\/p>\n<h3>Spanner TrueTime. Rel\u00f3gios at\u00f4micos<\/h3>\n<p>\nEu disse que falaria sobre o 'Spanner'. \u00c9 uma coisa incr\u00edvel, do s\u00e9culo XXI: rel\u00f3gios at\u00f4micos, sincroniza\u00e7\u00e3o por GPS.<\/p>\n<p>Qual \u00e9 a ideia? O 'Spanner' \u00e9 um sistema do Google, que recentemente se tornou dispon\u00edvel para as pessoas (eles adicionaram SQL a ele). Cada transa\u00e7\u00e3o l\u00e1 tem um certo carimbo de tempo. Como o tempo \u00e9 sincronizado*, cada evento pode ser atribu\u00eddo a determinados tempos \u2013 os rel\u00f3gios at\u00f4micos t\u00eam um tempo de espera, ap\u00f3s o qual um outro tempo 'ocorre' garantidamente.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/707b5998fbb500d201aafffccc666f0e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAssim, apenas gravando no banco de dados e aguardando um certo per\u00edodo, a serializa\u00e7\u00e3o dos eventos \u00e9 automaticamente garantida. Eles t\u00eam o modelo de consist\u00eancia mais forte que poderia ser imaginado \u2013 \u00e9 a Consist\u00eancia Externa.<\/p>\n<p>* Este \u00e9 o problema principal dos rel\u00f3gios de Lamport \u2013 eles nunca est\u00e3o sincronizados em sistemas distribu\u00eddos. Eles podem divergir, mesmo com NTP, ainda assim n\u00e3o funcionam muito bem. O 'Spanner' possui rel\u00f3gios at\u00f4micos e sincroniza\u00e7\u00e3o, parece que na ordem de microssegundos.<\/p>\n<p>Por que n\u00e3o escolhemos? N\u00e3o supomos que nossos usu\u00e1rios tenham rel\u00f3gios at\u00f4micos integrados. Quando eles estiverem presentes, integrados a cada laptop, haver\u00e1 uma super incr\u00edvel sincroniza\u00e7\u00e3o por GPS \u2013 a\u00ed sim\u2026 Mas at\u00e9 l\u00e1, o melhor que podemos ter s\u00e3o as 'Esta\u00e7\u00f5es Base' da 'Amazon' \u2013 para os f\u00e3s\u2026 Portanto, usamos outros rel\u00f3gios.<\/p>\n<h3>Rel\u00f3gios h\u00edbridos (Hybrid Clock)<\/h3>\n<p>\nIsso \u00e9, na verdade, o que faz \"MongoDB\" funcionar ao garantir a consist\u00eancia causal. Em que eles s\u00e3o h\u00edbridos? H\u00edbrido \u00e9 um valor escalar, mas consiste em dois componentes:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/dab03a87d9f6ee2e716f75baff1736bc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>O primeiro \u00e9 a \u00e9poca Unix (quantos segundos se passaram desde o \"in\u00edcio do mundo computacional\").<\/li>\n<li>O segundo \u00e9 um incremento, tamb\u00e9m um inteiro sem sinal de 32 bits.<\/li>\n<\/ul>\n<p>\nIsso \u00e9 tudo. Existe essa abordagem: a parte que responde pelo tempo \u00e9 sempre sincronizada com os rel\u00f3gios; sempre que uma atualiza\u00e7\u00e3o acontece, essa parte se sincroniza com o rel\u00f3gio, e assim o tempo permanece mais ou menos correto, enquanto o incremento permite diferenciar eventos que ocorreram no mesmo momento.<\/p>\n<p>Por que isso \u00e9 importante para \"MongoDB\"? Porque permite realizar backups e restaura\u00e7\u00f5es para um determinado momento no tempo, ou seja, o evento \u00e9 indexado pelo tempo. Isso \u00e9 crucial quando certos eventos s\u00e3o necess\u00e1rios; para o banco de dados, eventos s\u00e3o altera\u00e7\u00f5es no banco que ocorreram em intervalos de tempo espec\u00edficos.<\/p>\n<p>Vou lhe contar o motivo mais importante (por favor, n\u00e3o conte isso a ningu\u00e9m)! Fizemos assim porque \u00e9 assim que os dados ordenados e indexados aparecem no MongoDB OpLog. O OpLog \u00e9 uma estrutura de dados que cont\u00e9m todas as altera\u00e7\u00f5es no banco: elas primeiro v\u00e3o para o OpLog e depois s\u00e3o aplicadas ao Storage, no caso de serem dados replicados ou shard.<\/p>\n<p>Essa foi a raz\u00e3o principal. Existem tamb\u00e9m requisitos pr\u00e1ticos para o desenvolvimento do banco, o que significa que deve ser simples \u2013 pouco c\u00f3digo, o m\u00ednimo poss\u00edvel de coisas quebradas que precisam ser reescritas e testadas. O fato de termos opLogs indexados com rel\u00f3gios h\u00edbridos ajudou muito e permitiu fazer a escolha certa. Isso realmente se mostrou eficaz e funcionou de forma m\u00e1gica no primeiro prot\u00f3tipo. Foi muito legal!<\/p>\n<h3>Sincroniza\u00e7\u00e3o de rel\u00f3gios<\/h3>\n<p>\nExistem v\u00e1rias maneiras de sincroniza\u00e7\u00e3o descritas na literatura cient\u00edfica. Falo de sincroniza\u00e7\u00e3o, quando temos dois shards diferentes. Se houver um conjunto de r\u00e9plicas \u2013 n\u00e3o h\u00e1 necessidade de sincroniza\u00e7\u00e3o: \u00e9 um \u00abmaster \u00fanico\u00bb; temos um OpLog, onde todas as altera\u00e7\u00f5es s\u00e3o registradas \u2013 nesse caso, tudo j\u00e1 est\u00e1 ordenado sequencialmente no pr\u00f3prio \u00abOpLog\u00bb. Mas se temos dois shards diferentes, aqui a sincroniza\u00e7\u00e3o do tempo \u00e9 importante. Aqui, os rel\u00f3gios vetoriais ajudaram mais! Mas n\u00f3s n\u00e3o os temos.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/7d3306747490ac044b7f8130defea0c9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO segundo m\u00e9todo \u00e9 o \u00abHeartbeats\u00bb. Podemos trocar alguns sinais que ocorrem a cada unidade de tempo. Mas os \u00abHeartbeats\u00bb s\u00e3o muito lentos, n\u00e3o conseguimos garantir a lat\u00eancia para nosso cliente.<\/p>\n<p>O tempo verdadeiro \u2013 claro, \u00e9 uma coisa maravilhosa. Mas, novamente, isso \u00e9 provavelmente o futuro\u2026 Embora no \u00abAtlas\u00bb j\u00e1 se possa fazer, j\u00e1 existem sincronizadores de tempo \u00abamazonianos\u00bb r\u00e1pidos. Mas isso n\u00e3o estar\u00e1 dispon\u00edvel para todos.<\/p>\n<p>Gossiping \u00e9 quando todas as mensagens incluem o tempo. \u00c9 mais ou menos isso que usamos. Cada mensagem entre n\u00f3s, driver, roteador de n\u00f3s de dados, absolutamente tudo para \u00abMongoDB\u00bb \u2013 s\u00e3o alguns elementos, componentes do banco de dados, que cont\u00eam rel\u00f3gios que correm. Eles t\u00eam um valor de tempo h\u00edbrido que \u00e9 transmitido. 64 bits? Isso \u00e9 poss\u00edvel.<\/p>\n<h3>Como tudo isso funciona junto?<\/h3>\n<p>\nAqui estou considerando um conjunto de r\u00e9plica para tornar as coisas um pouco mais simples. H\u00e1 um Prim\u00e1rio e um Secund\u00e1rio. O Secund\u00e1rio faz a replica\u00e7\u00e3o e nem sempre est\u00e1 completamente sincronizado com o Prim\u00e1rio.<\/p>\n<p>Uma inser\u00e7\u00e3o ocorre no \u00abPrim\u00e1rio\u00bb com algum valor de tempo. Essa inser\u00e7\u00e3o aumenta o contador interno em 11, se for o m\u00e1ximo. Ou ele ir\u00e1 verificar os valores dos rel\u00f3gios e se sincronizar pelos rel\u00f3gios, se os valores dos rel\u00f3gios forem maiores. Isso permite que o ordenamento seja feito pelo tempo.<\/p>\n<p>Depois que ele faz a grava\u00e7\u00e3o, ocorre um momento importante. Os rel\u00f3gios no \u00abMongoDB\u00bb s\u00f3 s\u00e3o incrementados em caso de grava\u00e7\u00e3o no \u00abOpLog\u00bb. Esse \u00e9 o evento que muda o estado do sistema. Em todos os artigos cl\u00e1ssicos, um evento \u00e9 considerado a chegada de uma mensagem em um n\u00f3: a mensagem chegou \u2013 isso significa que o sistema mudou seu estado.<\/p>\n<p>Isso acontece porque, ao investigar, n\u00e3o \u00e9 poss\u00edvel entender completamente como essa mensagem ser\u00e1 interpretada. Sabemos com certeza que, se n\u00e3o estiver refletida no 'OpLog', n\u00e3o ser\u00e1 interpretada de forma alguma, e a \u00fanica mudan\u00e7a no estado do sistema \u00e9 a grava\u00e7\u00e3o no 'OpLog'. Isso simplifica tudo para n\u00f3s: tanto a modelagem quanto a organiza\u00e7\u00e3o dentro de um \u00fanico conjunto de r\u00e9plicas, al\u00e9m de muitas outras coisas \u00fateis.<\/p>\n<p>Um valor \u00e9 retornado, que j\u00e1 est\u00e1 gravado no 'OpLog' \u2013 sabemos que esse valor j\u00e1 est\u00e1 contido no 'OpLog' e seu tempo \u00e9 12. Agora, digamos que a leitura come\u00e7a a partir de outro n\u00f3 (Secund\u00e1rio), e ele j\u00e1 passa afterClusterTime na pr\u00f3pria mensagem. Ele diz: 'Eu preciso de tudo o que aconteceu pelo menos ap\u00f3s 12 ou no momento do doze' (veja a imagem acima).<\/p>\n<p>Isso \u00e9 o que chamamos de Causal e consistente (CAT). Existe um conceito na teoria que este \u00e9 um certo corte de tempo, que \u00e9 consistente em si mesmo. Neste caso, pode-se dizer que \u00e9 o estado do sistema observado no momento temporal 12.<\/p>\n<p>Neste momento, n\u00e3o h\u00e1 nada aqui, porque isso simula uma situa\u00e7\u00e3o em que o Secund\u00e1rio precisa replicar dados do Prim\u00e1rio. Ele est\u00e1 esperando\u2026 E ent\u00e3o os dados chegaram \u2013 retornam esses valores.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/54d9de3e2696c1e5d19f4da206be090b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00c9 mais ou menos assim que tudo funciona. Quase isso.<\/p>\n<p>O que significa 'quase isso'? Vamos supor que existe uma pessoa que leu e entendeu como tudo funciona. Entendeu que ocorre uma atualiza\u00e7\u00e3o de ClusterTime a cada vez, que atualiza os rel\u00f3gios l\u00f3gicos internos, e ent\u00e3o o pr\u00f3ximo registro aumenta em uma unidade. Essa fun\u00e7\u00e3o ocupa 20 linhas. Suponha que essa pessoa passe o maior n\u00famero inteiro de 64 bits menos um.<\/p>\n<p>Por que 'menos um'? Porque os rel\u00f3gios internos ser\u00e3o inseridos nesse valor (obviamente, este \u00e9 o maior poss\u00edvel e maior que o tempo atual), ent\u00e3o ocorrer\u00e1 uma grava\u00e7\u00e3o no 'OpLog', e os rel\u00f3gios ser\u00e3o incrementados em mais uma unidade \u2013 e j\u00e1 ser\u00e1 o valor m\u00e1ximo (s\u00e3o apenas todos uns, n\u00e3o h\u00e1 mais para onde ir, uns inteiros sem sinal).<\/p>\n<p>\u00c9 claro que, ap\u00f3s isso, o sistema se torna absolutamente inacess\u00edvel para qualquer coisa. S\u00f3 \u00e9 poss\u00edvel descarreg\u00e1-lo, limp\u00e1-lo \u2013 um trabalho manual extenso. Disponibilidade total:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/634b25fe0ef1e0af39181cd59c7b522f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAl\u00e9m disso, se isso se replica em outros lugares, pode derrubar todo o cluster. \u00c9 uma situa\u00e7\u00e3o absolutamente inaceit\u00e1vel, que qualquer pessoa pode criar muito rapidamente e facilmente! Por isso, consideramos esse aspecto como um dos mais importantes. Como preveni-la?<\/p>\n<h3>Nosso caminho \u00e9 assinar clusterTime<\/h3>\n<p>\nAssim, ele \u00e9 transmitido na mensagem (at\u00e9 o texto azul). Mas tamb\u00e9m come\u00e7amos a gerar uma assinatura (texto azul):<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/c16e985f9610e01a61293e0d6dde459b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA assinatura \u00e9 gerada com uma chave que \u00e9 mantida dentro do banco de dados, dentro de um per\u00edmetro seguro; \u00e9 gerada e atualizada (os usu\u00e1rios n\u00e3o v\u00eaem isso). Um hash \u00e9 gerado, e cada mensagem \u00e9 assinada ao ser criada e validada ao ser recebida.<br \/>\nProvavelmente, as pessoas se perguntam: \"Qu\u00e3o lento isso tudo torna?\" Eu disse que deve funcionar rapidamente, especialmente na aus\u00eancia deste recurso.<\/p>\n<p>O que significa usar a consist\u00eancia causal neste caso? Isso significa mostrar o par\u00e2metro afterClusterTime. Sem isso, ele simplesmente transmitir\u00e1 valores independentemente. O Gossiping, a partir da vers\u00e3o 3.6, funciona sempre.<\/p>\n<p>Se deixarmos a gera\u00e7\u00e3o constante de assinaturas, isso desacelerar\u00e1 o sistema mesmo na aus\u00eancia do recurso, o que n\u00e3o est\u00e1 de acordo com nossas abordagens e requerimentos. E o que fizemos?<\/p>\n<h3>Fa\u00e7a isso rapidamente!<\/h3>\n<p>\nUma coisa relativamente simples, mas um truque interessante \u2013 vou compartilhar, talvez algu\u00e9m ache interessante.<br \/>\nTemos um hash que armazena os dados assinados. Todos os dados passam pelo cache. O cache n\u00e3o assina um tempo espec\u00edfico, mas um Range. Quando um determinado valor chega, geramos um Range, mascaramos os \u00faltimos 16 bits, e esse valor n\u00f3s assinamos:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/f4810456f08ba1cc69730ac0079d4206.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAo receber tal assinatura, aceleramos o sistema (condicionalmente) em 65 mil vezes. Funciona maravilhosamente: quando realizamos experimentos, o tempo realmente diminuiu em 10 mil vezes quando temos uma atualiza\u00e7\u00e3o sequencial. \u00c9 claro que quando est\u00e3o desordenados, isso n\u00e3o acontece. Mas na maioria dos casos pr\u00e1ticos, isso funciona. A combina\u00e7\u00e3o da assinatura de Range junto com a assinatura ajudou a resolver o problema de seguran\u00e7a.<\/p>\n<h3>O que aprendemos?<\/h3>\n<p>\nAs li\u00e7\u00f5es que extra\u00edmos disso:<\/p>\n<ul>\n<li>\u00c9 necess\u00e1rio ler materiais, hist\u00f3rias, artigos, porque temos muita coisa interessante. Quando trabalhamos em uma nova funcionalidade (especialmente agora, quando fizemos transa\u00e7\u00f5es etc.), \u00e9 preciso ler e compreender. Isso leva tempo, mas \u00e9 realmente muito \u00fatil, porque nos ajuda a entender onde estamos. Na verdade, n\u00e3o inventamos nada novo \u2013 apenas reunimos os ingredientes.\n<p>Observa-se uma diferen\u00e7a de pensamento quando ocorre uma confer\u00eancia acad\u00eamica (como a \u00abSigmon\u00bb, por exemplo) \u2013 l\u00e1 todos se concentram em novas ideias. Qual \u00e9 a novidade do nosso algoritmo? Aqui n\u00e3o h\u00e1 muita novidade. A inova\u00e7\u00e3o est\u00e1 mais na forma como misturamos diferentes abordagens existentes. Portanto, em primeiro lugar, \u00e9 preciso ler os cl\u00e1ssicos, come\u00e7ando por Lamport.<\/li>\n<li>Em produ\u00e7\u00e3o, as exig\u00eancias s\u00e3o completamente diferentes. Tenho certeza de que muitos de voc\u00eas n\u00e3o lidam com bases de dados \u201cesf\u00e9ricas\u201d em um v\u00e1cuo abstrato, mas com situa\u00e7\u00f5es normais e reais, que apresentam problemas de disponibilidade, lat\u00eancia e resili\u00eancia.<\/li>\n<li>Por \u00faltimo, tivemos que considerar diferentes ideias e combinar v\u00e1rios artigos diversos em uma \u00fanica abordagem. A ideia da assinatura, por exemplo, veio de um artigo que analisava o protocolo Paxos, aplic\u00e1vel a falhas n\u00e3o bizantinas dentro do protocolo de autoriza\u00e7\u00e3o, e para falhas bizantinas \u2013 fora do protocolo de autoriza\u00e7\u00e3o... Enfim, foi exatamente isso que acabamos fazendo.\n<p>N\u00e3o h\u00e1 nada absolutamente novo aqui! Mas assim que misturamos tudo isso\u2026 \u00c9 como dizer que a receita da salada Olivier \u00e9 irrelevante, porque os ovos, maionese e pepinos j\u00e1 foram inventados... \u00c9 mais ou menos a mesma hist\u00f3ria.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/2f9e5cb77079f9a0f7bdf76430c3386e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nConcluo por aqui. Obrigado!<\/p>\n<h3>Perguntas<\/h3>\n<p>\n<b>Pergunta do p\u00fablico (daqui em diante \u2013 P):<\/b> \u2013 Obrigado, Mikhail pela apresenta\u00e7\u00e3o! O tema sobre tempo \u00e9 interessante. Voc\u00ea utiliza Gossiping. Disse que todos t\u00eam seu pr\u00f3prio tempo, todos sabem seu tempo local. Entendi que temos um driver \u2013 pode haver muitos clientes com drivers, tamb\u00e9m muitos planejadores de consulta e shards... A que nosso sistema acaba se reduzindo, se surgir uma discrep\u00e2ncia: algu\u00e9m decide que est\u00e1 um minuto \u00e0 frente, outro \u2013 um minuto atr\u00e1s? Onde ficaremos?<\/p>\n<p><b>MT:<\/b> \u2013 \u00c9 uma \u00f3tima pergunta, na verdade! Eu queria falar sobre shards. Se eu entendi corretamente a pergunta, temos a seguinte situa\u00e7\u00e3o: h\u00e1 o shard 1 e o shard 2, a leitura acontece a partir desses dois shards \u2013 eles t\u00eam diverg\u00eancias, n\u00e3o interagem entre si, porque o tempo que cada um conhece \u00e9 diferente, especialmente o tempo que existe em seus oplogs.<br \/>\nSuponhamos que o shard 1 fez um milh\u00e3o de registros, o shard 2 \u2013 absolutamente nada, e a solicita\u00e7\u00e3o chegou aos dois shards. E o primeiro tem afterClusterTime superior a um milh\u00e3o. Nessa situa\u00e7\u00e3o, como expliquei, o shard 2 nunca responder\u00e1.<\/p>\n<p><b>P:<\/b> \u2013 Eu queria saber como eles se sincronizam e escolhem um \u00fanico tempo l\u00f3gico?<\/p>\n<p><b>MT:<\/b> \u2013 Eles se sincronizam de forma muito simples. O shard, quando recebe afterClusterTime, e n\u00e3o encontra o tempo no 'Oplog' \u2013 inicia o no approved. Ou seja, ele manualmente eleva seu tempo para esse valor. Isso significa que ele n\u00e3o tem eventos correspondentes a essa solicita\u00e7\u00e3o. Ele cria esse evento artificialmente e assim se torna Causal Consistent.<\/p>\n<p><b>P:<\/b> \u2013 E se depois disso ainda chegarem alguns eventos que estavam perdidos na rede?<\/p>\n<p><b>MT:<\/b> \u2013 O shard \u00e9 projetado de forma que eles n\u00e3o chegar\u00e3o, pois \u00e9 um single master. Se ele j\u00e1 registrou, eles n\u00e3o voltar\u00e3o, mas vir\u00e3o depois. N\u00e3o pode acontecer que algo tenha ficado preso em algum lugar, ent\u00e3o ele faz um no write, e esses eventos chegam depois \u2013 e a Causal consistency \u00e9 quebrada. Quando ele faz um no write, todos devem vir depois (ele os aguardar\u00e1).<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/dbbc7c5c653f0c9fa449cceb88ed62ef.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>P:<\/b> \u2013 Eu tenho algumas perguntas sobre filas. A Causal consistency pressup\u00f5e que h\u00e1 uma certa fila de a\u00e7\u00f5es que precisam ser executadas. O que acontece se um pacote se perder? Por exemplo, o 10\u00ba, 11\u00ba\u2026 o 12\u00ba se perdeu, enquanto todos os outros est\u00e3o esperando que ele seja executado. E, de repente, nossa m\u00e1quina parou, e n\u00e3o podemos fazer nada. Existe um comprimento m\u00e1ximo da fila que se acumula antes de ser executada? Que falha fatal ocorre na perda de algum estado? Al\u00e9m disso, se estamos registrando que h\u00e1 algum estado anterior, dever\u00edamos nos basear nele? Mas n\u00e3o conseguimos nos basear nele!<\/p>\n<p><b>MT:<\/b> \u2013 Tamb\u00e9m \u00e9 uma pergunta excelente! O que fazemos? No MongoDB, existe o conceito de grava\u00e7\u00f5es quorum e leitura quorum. Em quais casos uma mensagem pode se perder? Quando o registro n\u00e3o \u00e9 quorum ou quando a leitura n\u00e3o \u00e9 quorum (tamb\u00e9m pode haver algum lixo que sobe).<br \/>\nRealizamos uma ampla verifica\u00e7\u00e3o experimental sobre a Coer\u00eancia Causal, cuja conclus\u00e3o foi que, no caso de grava\u00e7\u00f5es e leituras n\u00e3o-quorum, ocorrem viola\u00e7\u00f5es da Coer\u00eancia Causal. Exatamente o que voc\u00ea mencionou!<\/p>\n<p>Nossa recomenda\u00e7\u00e3o: usar pelo menos leitura quorum ao empregar Coer\u00eancia Causal. Neste caso, nada se perder\u00e1, mesmo se uma grava\u00e7\u00e3o quorum desaparecer... Esta \u00e9 uma situa\u00e7\u00e3o ortogonal: se o usu\u00e1rio n\u00e3o deseja que os dados se percam, deve usar grava\u00e7\u00e3o quorum. A Coer\u00eancia Causal n\u00e3o garante durabilidade. A garantia de durabilidade \u00e9 fornecida pela replica\u00e7\u00e3o e pela maquinaria relacionada \u00e0 replica\u00e7\u00e3o.<\/p>\n<p><b>P:<\/b> \u2013 Quando criamos uma inst\u00e2ncia que realiza sharding (n\u00e3o master, mas slave, respectivamente), ela se baseia no tempo Unix da pr\u00f3pria m\u00e1quina ou no tempo do \"master\"; \u00e9 sincronizado pela primeira vez ou periodicamente?<\/p>\n<p><b>MT:<\/b> \u2013 Agora vou esclarecer. Um shard (ou seja, uma parti\u00e7\u00e3o horizontal) sempre tem um Prim\u00e1rio. E dentro do shard pode haver um \"master\" e podem haver r\u00e9plicas. Mas o shard sempre mant\u00e9m grava\u00e7\u00e3o, porque precisa suportar algum dom\u00ednio (no shard est\u00e1 o Prim\u00e1rio).<\/p>\n<p><b>P:<\/b> \u2013 Ent\u00e3o tudo depende exclusivamente do \"master\"? Sempre \u00e9 usado o tempo do \"master\"?<\/p>\n<p><b>MT:<\/b> \u2013 Sim. Pode-se dizer figurativamente: os rel\u00f3gios ticam quando ocorre uma grava\u00e7\u00e3o no \"master\", no \"OpLog\".<\/p>\n<p><b>P:<\/b> \u2013 Temos um cliente que se conecta e n\u00e3o precisa saber nada sobre o tempo?<\/p>\n<p><b>MT:<\/b> \u2013 Ele n\u00e3o precisa saber nada! Se falarmos sobre como isso funciona no cliente: quando o cliente deseja utilizar a Coer\u00eancia Causal, precisa abrir uma sess\u00e3o. Agora tudo est\u00e1 l\u00e1: transa\u00e7\u00f5es na sess\u00e3o e recupera\u00e7\u00e3o de direitos... A sess\u00e3o \u00e9 uma ordena\u00e7\u00e3o de eventos l\u00f3gicos que ocorrem com o cliente.<\/p>\n<p>Se ele abre essa sess\u00e3o e diz que quer a Coer\u00eancia Causal (se por padr\u00e3o a sess\u00e3o suporta a Coer\u00eancia Causal), tudo funciona automaticamente. O driver registra esse tempo e o aumenta quando recebe uma nova mensagem. Ele se lembra de qual resposta foi retornada anteriormente pelo servidor que forneceu os dados. A pr\u00f3xima solicita\u00e7\u00e3o conter\u00e1 afterCluster (\"tempo maior que este\").<\/p>\n<p>O cliente n\u00e3o precisa saber nada! Isso \u00e9 completamente opaco para ele. Se as pessoas utilizam esses recursos, o que isso permite? Em primeiro lugar, \u00e9 poss\u00edvel ler dados secund\u00e1rios de forma segura: pode-se escrever no Prim\u00e1rio e ler de secund\u00e1rios replicados geograficamente, tendo certeza de que isso funciona. Al\u00e9m disso, as sess\u00f5es gravadas no Prim\u00e1rio podem ser transferidas para o Secund\u00e1rio, ou seja, \u00e9 poss\u00edvel usar v\u00e1rias sess\u00f5es.<\/p>\n<p><b>P:<\/b> \u2013 O conceito de consist\u00eancia eventual est\u00e1 muito relacionado a um novo campo da ci\u00eancia da computa\u00e7\u00e3o \u2013 os tipos de dados CRDT (Tipos de Dados Replicados Sem Conflitos). Voc\u00ea considerou a integra\u00e7\u00e3o desses tipos de dados no banco e o que pode dizer sobre isso?<\/p>\n<p><b>MT:<\/b> \u2013 Boa pergunta! CRDT faz sentido para conflitos durante a grava\u00e7\u00e3o: no MongoDB, temos um mestre \u00fanico.<\/p>\n<p><b>P:<\/b> \u2013 Tenho uma pergunta dos devops. No mundo real, encontramos situa\u00e7\u00f5es t\u00e3o intrigantes, onde uma falha bizantina ocorre, e homens mal-intencionados dentro do per\u00edmetro protegido come\u00e7am a interferir no protocolo, enviando pacotes de maneira engenhosa?<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" src=\"\/wp-content\/uploads\/2020\/02\/99a521d04b416e6978aa68ce7c4a4c46.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>MT:<\/b> \u2013 Homens mal-intencionados dentro do per\u00edmetro s\u00e3o como um cavalo de Troia! Eles podem causar muitos problemas.<\/p>\n<p><b>P:<\/b> \u2013 \u00c9 claro que deixar uma 'fenda' no servidor, por assim dizer, pela qual se pode passar um zool\u00f3gico de elefantes e derrubar todo o cluster para sempre... Isso exigir\u00e1 tempo para restaura\u00e7\u00e3o manual... Isso, para dizer o m\u00ednimo, \u00e9 incorreto. Por outro lado, \u00e9 interessante saber: na vida real, na pr\u00e1tica, voc\u00ea j\u00e1 se deparou com situa\u00e7\u00f5es onde ataques internos semelhantes realmente ocorrem?<\/p>\n<p><b>MT:<\/b> \u2013 Como n\u00e3o me deparei com viola\u00e7\u00f5es de seguran\u00e7a na vida real com frequ\u00eancia, n\u00e3o posso afirmar \u2013 talvez elas realmente ocorram. Mas se falarmos sobre a filosofia de desenvolvimento, acreditamos o seguinte: temos um per\u00edmetro que protege as pessoas que tratam de seguran\u00e7a \u2013 isso \u00e9 como um cadeado, uma parede; e dentro do per\u00edmetro, pode-se fazer o que se quiser. \u00c9 claro que existem usu\u00e1rios que s\u00f3 podem visualizar, enquanto outros t\u00eam permiss\u00e3o para excluir diret\u00f3rios.<\/p>\n<p>Dependendo das permiss\u00f5es, o dano que os usu\u00e1rios podem causar pode ser como um clique do mouse ou como um elefante. \u00c9 evidente que um usu\u00e1rio com permiss\u00f5es totais pode fazer qualquer coisa. J\u00e1 um usu\u00e1rio com permiss\u00f5es limitadas pode causar muito menos dano. Em particular, ele n\u00e3o pode quebrar o sistema.<\/p>\n<p><b>P:<\/b> \u2013 No per\u00edmetro protegido, algu\u00e9m est\u00e1 tentando formar protocolos inesperados para o servidor, colocando-o de joelhos, e se tiver sorte, o cluster inteiro... \u00c9 realmente t\u00e3o 'bom' assim?<\/p>\n<p><b>MT:<\/b> \u2013 Nunca ouvi falar de tais coisas. Que \u00e9 poss\u00edvel derrubar um servidor dessa forma n\u00e3o \u00e9 segredo. Derrubar de dentro, estando no protocolo, sendo um usu\u00e1rio autorizado que pode gravar alguma coisa... Na verdade, isso n\u00e3o \u00e9 poss\u00edvel, porque ainda assim ele ser\u00e1 verificado. Existe a possibilidade de desabilitar essa autentica\u00e7\u00e3o para usu\u00e1rios que n\u00e3o desejam - nesse caso, suas quest\u00f5es; eles, grosseiramente falando, derrubaram as paredes e \u00e9 poss\u00edvel colocar um elefante que vai esmagar... E, na verdade, pode-se se vestir de t\u00e9cnico, aparecer e retirar!<\/p>\n<p><b>P:<\/b> \u2013 Obrigado pela palestra. Sergey (\"Yandex\"). No \"Mongo\", existe uma constante que limita o n\u00famero de membros votantes no Replica Set, e essa constante \u00e9 igual a 7 (sete). Por que isso \u00e9 uma constante? Por que n\u00e3o \u00e9 um par\u00e2metro qualquer?<\/p>\n<p><b>MT:<\/b> \u2013 O Replica Set pode ter at\u00e9 40 n\u00f3s. Sempre haver\u00e1 uma maioria. N\u00e3o sei qual a vers\u00e3o...<\/p>\n<p><b>P:<\/b> \u2013 No Replica Set, pode-se executar membros n\u00e3o votantes, mas votantes - no m\u00e1ximo 7. Como lidar com a interrup\u00e7\u00e3o, se nosso Replica Set est\u00e1 distribu\u00eddo em 3 data centers? Um data center pode facilmente se desligar, e mais uma m\u00e1quina pode falhar.<\/p>\n<p><b>MT:<\/b> \u2013 Isso j\u00e1 est\u00e1 um pouco al\u00e9m da palestra. \u00c9 uma quest\u00e3o geral. Posso explic\u00e1-la depois.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica\" 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=\"Por que no hosting comum a administra\u00e7\u00e3o do PrestaShop \u00e9 lenta, e no seu n\u00e3o \u00e9?\" 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>Um pouco de publicidade \ud83d\ude42<\/h3>\n<p>\nObrigado por permanecer conosco. Voc\u00ea gosta dos nossos artigos? Quer ver mais materiais interessantes? Apoie-nos fazendo um pedido ou recomendando para conhecidos. <noindex><a rel=\"nofollow\" href=\"https:\/\/ua-hosting.company\/cloudvps\/nl\">VPS em nuvem para desenvolvedores a partir de $4.99<\/a><\/noindex>, <b>uma alternativa \u00fanica aos servidores entry-level, que criamos para voc\u00ea:<\/b> <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/ua-hosting\/blog\/347386\/\">Toda a verdade sobre VPS (KVM) E5-2697 v3 (6 N\u00facleos) 10GB DDR4 480GB SSD 1Gbps a partir de $19 ou como dividir um servidor corretamente?<\/a><\/noindex> (dispon\u00edveis op\u00e7\u00f5es com RAID1 e RAID10, at\u00e9 24 n\u00facleos e at\u00e9 40GB DDR4).<\/p>\n<p><b>Dell R730xd por 2 vezes mais barato no datacenter Equinix Tier IV em Amsterd\u00e3?<\/b> Somente conosco <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 100TB a partir de $199<\/a><\/noindex> na Holanda! <b>Dell R420 \u2014 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB \u2014 a partir de $99!<\/b><\/b> Leia sobre <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/ua-hosting\/blog\/329618\/\">Como construir uma infraestrutura de classe corporativa utilizando servidores Dell R730xd E5-2650 v4 com custo de 9000 euros por centavos?<\/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.3 - 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\/pt\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\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\/pt\/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++, Mikhail Tyulenev (MongoDB): Consist\u00eancia causal: da teoria \u00e0 pr\u00e1tica | ProHoster","description":"A pr\u00f3xima confer\u00eancia HighLoad++ ocorrer\u00e1 nos dias 6 e 7 de abril de 2020 em S\u00e3o Petersburgo. Detalhes e ingressos no link.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/56365","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=56365"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/56365\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=56365"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=56365"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=56365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}