{"id":26788,"date":"2020-02-11T17:34:00","date_gmt":"2020-02-11T17:34:00","guid":{"rendered":"https:\/\/building.nu.com\/a-digital-pine-forest-the-evergreen-cache\/"},"modified":"2024-03-20T17:40:07","modified_gmt":"2024-03-20T17:40:07","slug":"uma-floresta-digital-o-cache-perene","status":"publish","type":"post","link":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/","title":{"rendered":"Uma floresta digital: o cache perene"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/building.nu.com\/how-we-designed-our-bank-account-nuconta-part-i\/\">A conta digital do Nubank<\/a>&nbsp;\u00e9 criada usando a mesma stack fant\u00e1stica que suporta os nossos outros produtos: Clojure, Datomic e Kafka, todos instalados na nuvem da AWS. Na equipe que cria a conta do Nubank, tamb\u00e9m somos grandes f\u00e3s do event sourcing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Event sourcing \u00e9 uma express\u00e3o sofisticada que significa uma ideia simples: em vez de armazenar o estado atual do sistema em um banco de dados, armazenamos cada passo da hist\u00f3ria at\u00e9 agora. Mais tarde, se necess\u00e1rio, podemos sempre examinar o armazenamento para responder a qualquer pergunta ou at\u00e9 acessar a lista inteira para obter uma vis\u00e3o &#8220;stateful&#8221; atualizada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Isso soluciona muitos problemas que surgem com os sistemas distribu\u00eddos. N\u00f3s usamos muitos microsservi\u00e7os no Nubank, e mant\u00ea-los consistentes entre si \u00e9 um problema complexo. Descobrimos que o event sourcing nos permite dividir as coisas de uma forma que mant\u00e9m essa complexidade em um n\u00edvel confort\u00e1vel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Esta \u00e9 uma hist\u00f3ria sobre o momento em que a nossa abordagem de eventos come\u00e7ou a gerar situa\u00e7\u00f5es de mem\u00f3ria insuficiente, e como solucionamos isso sem abrir m\u00e3o da consist\u00eancia.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Contar dinheiro<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Uma das principais caracter\u00edsticas de uma conta banc\u00e1ria \u00e9 manter a contagem atualizada de quanto dinheiro voc\u00ea tem nela. Obviamente, tamb\u00e9m queremos permitir que voc\u00ea deposite mais dinheiro e possa sac\u00e1-lo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depositar e sacar dinheiro do Nubank envolve algumas integra\u00e7\u00f5es complexas, que s\u00e3o muito interessantes, mas eu gostaria de falar sobre a parte de &#8220;manter a contagem atualizada&#8221;. Nesse caso, a contagem \u00e9 o saldo da conta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma implementa\u00e7\u00e3o ing\u00eanua de um servi\u00e7o de saldo seria assim:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>O modelo de banco de dados consiste em uma entidade <em>conta<\/em><\/li>\n\n\n\n<li>Essa entidade tem um atributo <em>saldo<\/em><\/li>\n\n\n\n<li>Adicionar dinheiro significa atualizar o atributo <em>saldo<\/em> para aument\u00e1-lo<\/li>\n\n\n\n<li>Remover dinheiro significa atualizar o atributo <em>saldo<\/em> para reduzi-lo<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Parece simples, n\u00e3o \u00e9?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mas como voc\u00ea faria um extrato com isso? Como depurar se alguma coisa der errado? Como garantir que voc\u00ea nunca adicione ou remova um valor duas vezes?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eu n\u00e3o vou entrar em detalhes, mas uma abordagem com event sourcing soluciona todos esses problemas (e alguns outros tamb\u00e9m). Ent\u00e3o, eis uma forma de criar um servi\u00e7o de saldo com event sourcing:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>O modelo de banco de dados tem uma entidade <em>conta<\/em>.<\/li>\n\n\n\n<li>Ele tamb\u00e9m tem uma entidade <em>dep\u00f3sito<\/em> e uma entidade <em>saque<\/em>, ambas pertencentes a uma <em>conta<\/em>. Cada uma dessas entidades tem dois atributos: <em>valor<\/em> e <em>data.<\/em><\/li>\n\n\n\n<li>Adicionar dinheiro significa criar um novo <em>dep\u00f3sito.<\/em><\/li>\n\n\n\n<li>Remover dinheiro significa criar um novo <em>saque.<\/em><\/li>\n\n\n\n<li>O saldo da conta em uma data qualquer \u00e9 a soma de todos os <em>dep\u00f3sitos<\/em> feitos at\u00e9 aquela data, menos a soma de todos os <em>saques<\/em> feitos at\u00e9 aquela data.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Essa \u00e9 uma defini\u00e7\u00e3o simplificada, mas suficientemente pr\u00f3xima. \u00c9 assim que eu geralmente explico o nosso sistema nas palestras. Quando abrimos as perguntas, sempre surge uma:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8220;Voc\u00ea l\u00ea a lista inteira toda vez que algu\u00e9m pede o saldo? Isso n\u00e3o \u00e9 demorado demais?&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A minha resposta costumava ser, <em>&#8220;est\u00e1 funcionando bem at\u00e9 agora, obrigado por perguntar&#8221;<\/em>, mas isso j\u00e1 foi h\u00e1 alguns meses.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"640\" src=\"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/The-evergreen-cache-Square.jpg?resize=640%2C640&#038;ssl=1\" alt=\"Cache\" class=\"wp-image-81\" srcset=\"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/The-evergreen-cache-Square.jpg?w=640&amp;ssl=1 640w, https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/The-evergreen-cache-Square.jpg?resize=300%2C300&amp;ssl=1 300w, https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/The-evergreen-cache-Square.jpg?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/The-evergreen-cache-Square.jpg?resize=400%2C400&amp;ssl=1 400w, https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/The-evergreen-cache-Square.jpg?resize=200%2C200&amp;ssl=1 200w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><figcaption class=\"wp-element-caption\">O cache perene. \ud83c\udf32&nbsp;<br><a href=\"https:\/\/bit.ly\/jobs-at-nu\">Confira nossas oportunidades de trabalho&nbsp;<\/a><br><\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Sem mem\u00f3ria<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Conforme descobrimos, a velocidade n\u00e3o era um problema, mas os requisitos de mem\u00f3ria se tornaram um problema. Para entender o motivo, precisamos falar um pouco sobre o Datomic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O Datomic n\u00e3o \u00e9 um banco de dados SQL tradicional, mas ele provavelmente tamb\u00e9m n\u00e3o \u00e9 o que voc\u00ea pensa quando l\u00ea o jarg\u00e3o &#8220;NoSQL&#8221;. Ele oferece transa\u00e7\u00f5es ACID totalmente consistentes e tem v\u00e1rios <a href=\"https:\/\/www.youtube.com\/watch?v=7lm3K8zVOdY\">superpoderes<\/a> j\u00e1 na configura\u00e7\u00e3o padr\u00e3o. Temos trilhas de auditoria simples, e nunca perdemos quaisquer dados. Ele \u00e9 muito impressionante, mesmo depois de trabalhar com ele por alguns anos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por mais que sejam interessantes, as complexidades do modelo de dados do Datomic n\u00e3o s\u00e3o muito importantes para este problema. O que \u00e9 relevante \u00e9 uma decis\u00e3o de arquitetura espec\u00edfica: O Datomic separa as tarefas de gravar, armazenar e consultar dados. Em um servidor SQL tradicional, uma \u00fanica m\u00e1quina realiza as tr\u00eas tarefas. Com o Datomic, n\u00f3s podemos ter (e geralmente temos) tr\u00eas m\u00e1quinas ou clusters diferentes, um para cada tarefa.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Armazenar dados parece ser uma parte essencial de um banco de dados. De certa forma, \u00e9 mesmo, mas o Datomic n\u00e3o soluciona esse problema diretamente. Em vez disso, ele nos permite descarregar isso para um servi\u00e7o separado, como o DynamoDB.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A tarefa de gravar dados fica por conta de um processo espec\u00edfico, chamado de &#8220;transactor&#8221; (negociador). Todas as grava\u00e7\u00f5es passam por esse funil e s\u00e3o serializadas, processadas e validadas. Se tudo correr bem, a nossa transa\u00e7\u00e3o \u00e9 aceita e o resultado \u00e9 persistido na nossa camada de armazenamento.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Como todos os dados est\u00e3o na camada de armazenamento, eles podem ser acessados de qualquer lugar. Isso significa que podemos ter tantos processos de consulta quanto quisermos, todos pesquisando, filtrando e retornando os dados de interesse de forma independente. Estes processos somente leitura s\u00e3o chamados de <em>peers<\/em> (pares).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No Nubank, os nossos pares s\u00e3o as pr\u00f3prias inst\u00e2ncias dos nossos microsservi\u00e7os. O mesmo cont\u00eainer, a mesma JVM que executa nosso c\u00f3digo de aplica\u00e7\u00e3o, tamb\u00e9m est\u00e1 executando consultas, carregando coisas do DynamoDB para um enorme cache na mem\u00f3ria, carregando dados preemptivamente antes mesmo de pedirmos isso. Isso significa que as consultas podem ser <em>extremamente r\u00e1pidas<\/em>, porque a maioria dos dados de que voc\u00ea vai precisar est\u00e3o na mem\u00f3ria, ent\u00e3o nenhuma viagem pela rede \u00e9 necess\u00e1ria.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">E isso tamb\u00e9m pode consumir <em>muita<\/em> mem\u00f3ria. N\u00f3s j\u00e1 vimos o nosso servi\u00e7o de saldos alocando v\u00e1rios gigabytes em alguns segundos.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ent\u00e3o, come\u00e7amos a ver travamentos. M\u00e1quinas ficando sem mem\u00f3ria, pausando por v\u00e1rios minutos para fazer a coleta de lixo. Primeiro, nossa rea\u00e7\u00e3o foi aumentar a mem\u00f3ria dispon\u00edvel para essas inst\u00e2ncias. A princ\u00edpio, isso deu certo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quando chegamos a inst\u00e2ncias com 100 GB que estavam por um fio, percebemos que n\u00e3o dava mais para manter essa abordagem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Portanto, reunimos uma for\u00e7a-tarefa. Criadores de perfis foram a arma escolhida, e muitos testes de carregamento foram realizados. Cortamos megabytes, otimizamos as consultas. Houve paz por algum tempo. Infelizmente, isso n\u00e3o durou.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">O problema real estava em dois fatos b\u00e1sicos sobre o nosso sistema:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Nossa abordagem com event sourcing nos exigia o carregamento de <em>muitos<\/em> dados do armazenamento para o cache dos pares na mem\u00f3ria, onde poder\u00edamos fazer as consultas necess\u00e1rias.&nbsp;<\/li>\n\n\n\n<li>Qualquer inst\u00e2ncia do nosso servi\u00e7o poderia ser chamada para atender a qualquer solicita\u00e7\u00e3o. Isso significa que se um cliente fez quatro solicita\u00e7\u00f5es de seu saldo durante a navega\u00e7\u00e3o pelo aplicativo (o que \u00e9 normal), ele podia for\u00e7ar quatro inst\u00e2ncias diferentes a carregar os mesmos dados.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Nenhuma inst\u00e2ncia poderia ser grande o suficiente para manter todo o banco de dados no cache de mem\u00f3ria, mas ainda assim, todas as inst\u00e2ncias <em>tinham<\/em> que conter os dados necess\u00e1rios para todos os clientes a cada momento. Todas as inst\u00e2ncias estavam gastando muito tempo e mem\u00f3ria refazendo trabalho que alguma outra m\u00e1quina j\u00e1 havia feito. O tempo todo. Para todo mundo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se pud\u00e9ssemos fazer essas m\u00e1quinas compartilharem uma parte do trabalho, ou melhor ainda, n\u00e3o deixar que refizessem o trabalho desnecess\u00e1rio, ent\u00e3o haveria alguma esperan\u00e7a. Isso significava adicionar uma camada de cache. Mas o que \u00e9 que costumam dizer sobre o cache mesmo?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Uma das coisas dif\u00edceis<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Devo admitir, eu tenho um pouco de medo dos caches. Eu sei que eles existem e sei que \u00e9 poss\u00edvel faz\u00ea-los funcionar. Eu tamb\u00e9m sei que \u00e9 poss\u00edvel criar um programa seguro com m\u00faltiplas threads em assembly, mas prefiro n\u00e3o fazer isso, se puder evitar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eu j\u00e1 vi implementa\u00e7\u00f5es de cache em que v\u00e1rias pessoas examinavam e revisavam o c\u00f3digo, concluindo que ele estava correto, e <em>ainda assim<\/em> n\u00f3s encontr\u00e1vamos estados inv\u00e1lidos na produ\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma piada famosa sobre caching \u00e9 <a href=\"https:\/\/martinfowler.com\/bliki\/TwoHardThings.html\">atribu\u00edda a Phil Karlton<\/a>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8220;S\u00f3 existem duas coisas dif\u00edceis em Ci\u00eancia da Computa\u00e7\u00e3o: invalida\u00e7\u00e3o de cache e nomear coisas.&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">E essa piada est\u00e1 mesmo correta: a parte dif\u00edcil n\u00e3o \u00e9 criar o cache; a parte dif\u00edcil \u00e9 a <em>invalida\u00e7\u00e3o<\/em> do cache. E se n\u00f3s pud\u00e9ssemos criar um cache que nunca precisasse ser invalidado?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00f3s, programadores em Clojure, nos gabamos sobre as nossas estruturas de dados prontas e imut\u00e1veis. Nunca perdemos qualquer coisa at\u00e9 n\u00e3o precisarmos mais dela, e nesse momento, podemos apenas&#8230; abandonar a refer\u00eancia, esquec\u00ea-la, confiar no coletor de lixo e n\u00e3o olhar para tr\u00e1s.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ser\u00e1 que poder\u00edamos criar um cache que funcionasse desse jeito? Seria poss\u00edvel contornar a parte dif\u00edcil, em vez de resolv\u00ea-la?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Armazenamento imut\u00e1vel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pense nisto: um cache em que qualquer refer\u00eancia que voc\u00ea teve aponta para <em>nada<\/em> (um cache vazio) ou para algo imut\u00e1vel e, portanto, v\u00e1lido em algum momento do tempo. Quando o mundo muda, n\u00f3s mudamos a refer\u00eancia, n\u00e3o aquele valor. A nova refer\u00eancia tamb\u00e9m deve apontar para <em>nada<\/em> ou para um novo valor imut\u00e1vel e v\u00e1lido.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c9 dif\u00edcil rastrear de onde v\u00eam as ideias, mas olhando para tr\u00e1s, acho que duas fontes tiveram mais influ\u00eancia.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.info.ucl.ac.be\/~pvr\/book.html\">Conceitos, t\u00e9cnicas e modelos de programa\u00e7\u00e3o de computador<\/a> \u00e9 um livro incr\u00edvel, escrito por Peter Van Roy e Seif Haridi. Um dos primeiros construtos que voc\u00ea aprende nesse livro \u00e9 a <a href=\"https:\/\/mozart.github.io\/mozart-v1\/doc-1.4.0\/tutorial\/node3.html#chapter.basics\"><em>vari\u00e1vel l\u00f3gica<\/em><\/a>. As vari\u00e1veis l\u00f3gicas s\u00f3 podem ser atribu\u00eddas uma vez \u2013 elas s\u00e3o <em>desvinculadas<\/em> ou vinculadas a um valor espec\u00edfico para o resto do tempo (at\u00e9 o programa terminar). As vari\u00e1veis l\u00f3gicas me lembram de <a href=\"https:\/\/en.wikipedia.org\/wiki\/Futures_and_promises\">futuros e promessas<\/a> e fun\u00e7\u00f5es memorizadas.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Esse livro tamb\u00e9m mostra como usar vari\u00e1veis l\u00f3gicas para criar belos sistemas concorrentes com comportamento totalmente determin\u00edstico. Ocorre que se as suas vari\u00e1veis se tornarem imut\u00e1veis ap\u00f3s o v\u00ednculo <em>e<\/em> o processo que as vincula for determin\u00edstico, a concorr\u00eancia \u00e9 bem segura!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A outra grande inspira\u00e7\u00e3o foi o pr\u00f3prio Datomic. O Datomic armazena dados (em qualquer camada de armazenamento que queiramos usar) na forma de uma grande \u00e1rvore de n\u00f3s imut\u00e1veis. Cada n\u00f3 imut\u00e1vel \u00e9 identificado por uma UUID. Sempre que precisa fazer uma altera\u00e7\u00e3o na \u00e1rvore, ele pode simplesmente criar novas vers\u00f5es dos n\u00f3s que precisam ser modificados, at\u00e9 a raiz da \u00e1rvore, e, finalmente, fazer uma troca at\u00f4mica para a parte do armazenamento que cont\u00e9m a refer\u00eancia para a raiz <em>atual<\/em> da \u00e1rvore.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Agora, imagine que um par do Datomic precisa executar uma consulta. Ela inicia na raiz da \u00e1rvore, faz uma certa l\u00f3gica de indexa\u00e7\u00e3o e decide que os dados necess\u00e1rios est\u00e3o no n\u00f3 com a UUID <strong>EAE4D22F-CE79\u201347C4-AE5A-759A46B4D166<\/strong>. Agora, suponha que esse n\u00f3 j\u00e1 esteja carregado no cache de mem\u00f3ria. Como ele pode saber se o n\u00f3 ainda \u00e9 v\u00e1lido?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c9 claro que \u00e9 v\u00e1lido! Ele \u00e9 um valor imut\u00e1vel! Desde que iniciemos pela refer\u00eancia correta, certamente chegaremos a valores v\u00e1lidos. <em>O Datomic, nos bastidores, tem o tipo de cache que est\u00e1vamos procurando!<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Outra documenta\u00e7\u00e3o sugestiva do Datomic \u00e9 <a href=\"https:\/\/docs.datomic.com\/on-prem\/acid.html#implica%C3%A7%C3%B5es\">esta<\/a>:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8220;O Datomic sempre v\u00ea um indicador de registro correto, que foi colocado via um put condicional. Se algum dos n\u00f3s da \u00e1rvore ainda n\u00e3o estiver vis\u00edvel sob o indicador, o Datomic fica consistente, mas parcialmente indispon\u00edvel, e ficar\u00e1 totalmente dispon\u00edvel quando isso eventualmente acontecer.&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Isso se parece com uma vari\u00e1vel l\u00f3gica desvinculada, que ser\u00e1 vinculada assincronamente por alguma outra thread. Desde que aquela outra thread fa\u00e7a seu trabalho de forma correta e determin\u00edstica, estaremos seguros!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ent\u00e3o, eis o que precisamos:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Um <em>armazenamento imut\u00e1vel<\/em> que mapeie refer\u00eancias para algum valor (ou nada)<\/li>\n\n\n\n<li>Uma forma de derivar o valor atual do estado do banco de dados e envi\u00e1-lo para o armazenamento<\/li>\n\n\n\n<li>Uma forma de obter uma <em>refer\u00eancia<\/em> v\u00e1lida para o valor mais recente<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Qualquer armazenamento de chave-valor funcionar\u00e1 bem como armazenamento imut\u00e1vel. N\u00f3s decidimos usar o DynamoDB, pois j\u00e1 estamos acostumados com ele no Nubank.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00f3s j\u00e1 sab\u00edamos como computar os resultados que quer\u00edamos do banco de dados: estamos fazendo isso sempre que algu\u00e9m faz uma solicita\u00e7\u00e3o HTTP. Ent\u00e3o, uma estrat\u00e9gia simples que podemos usar \u00e9 um cache com leitura: procurar os dados no cache, e se n\u00e3o estiverem l\u00e1, comput\u00e1-los do zero, e ent\u00e3o grav\u00e1-los no cache e retornar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Agora s\u00f3 falta aquela refer\u00eancia m\u00e1gica que poderemos usar como chave para o nosso armazenamento imut\u00e1vel. Como podemos obt\u00ea-la?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">N\u00fameros de vers\u00e3o<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">O Datomic foi um bom modelo at\u00e9 agora, vamos ver se conseguimos roubar mais algumas ideias dele. Qual \u00e9 a <em>refer\u00eancia v\u00e1lida<\/em> do armazenamento do Datomic?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A resposta est\u00e1 naquele local espec\u00edfico de armazenamento que s\u00f3 \u00e9 <a href=\"https:\/\/docs.datomic.com\/on-prem\/acid.html#implica%C3%A7%C3%B5es\">atualizado usando solicita\u00e7\u00f5es put condicionais fortemente consistentes<\/a>: a chave para o n\u00f3 raiz da \u00e1rvore. Essa UUID aponta para a <em>vers\u00e3o<\/em> mais recente dos dados. Se voc\u00ea seguir a refer\u00eancia, tudo o que voc\u00ea vai encontrar estar\u00e1 atualizado. Qualquer outra coisa que voc\u00ea pode encontrar na camada de armazenamento \u00e9 lixo antigo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Essa ideia de identificadores de vers\u00e3o aparece em muitos lugares como uma forma de identificar coisas exclusivamente: reposit\u00f3rios do git, gerenciadores de pacote, blockchains. Eles podem ser hashes criptogr\u00e1ficos ou nomes atribu\u00eddos por alguma autoridade central. Isso n\u00e3o importa, desde que eles nomeiem valores imut\u00e1veis.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O Datomic tem um tipo de n\u00famero de vers\u00e3o que pode ser usado pelo c\u00f3digo de aplica\u00e7\u00e3o. Ele \u00e9 chamado de <a href=\"https:\/\/docs.datomic.com\/on-prem\/glossary.html#basis-t\">basis-t<\/a>, uma refer\u00eancia a um momento no tempo no banco de dados. \u00c9 poss\u00edvel compartilhar uma basis-t entre seus pares para garantir que estejam visualizando a mesma vers\u00e3o dos dados. A basis-t pode ser usada para visualizar o passado (ou seja, consultar o banco de dados como ele era naquele momento) ou para esperar pelo futuro (ou seja, bloquear uma thread at\u00e9 o par local ter recebido todos os dados at\u00e9 aquele momento no tempo).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">E se usarmos esse n\u00famero de basis-t como nossa refer\u00eancia?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bem, cada transa\u00e7\u00e3o faz o rel\u00f3gio do Datomic avan\u00e7ar, cada transa\u00e7\u00e3o aumenta esse n\u00famero de vers\u00e3o. Ent\u00e3o, o seguinte aconteceria:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>N\u00f3s consultamos o Datomic e descobrimos que a basis-t atual \u00e9 13. Usaremos isso como parte da nossa chave de cache at\u00e9 que a basis-t atual mude.<\/li>\n\n\n\n<li>Recebemos uma solicita\u00e7\u00e3o do saldo da conta n\u00famero 2042.<\/li>\n\n\n\n<li>Nossa chave de cache ter\u00e1 o formato &#8220;n\u00famero da conta\/basis-t&#8221;, ent\u00e3o, neste caso, ser\u00e1 &#8220;2042\/13&#8221;.<\/li>\n\n\n\n<li>Consultamos esse valor no armazenamento e n\u00e3o encontramos &#8211; cache vazio.<\/li>\n\n\n\n<li>Consultamos o banco de dados e computamos o resultado.<\/li>\n\n\n\n<li>Salvamos o resultado no armazenamento, na chave &#8220;2042\/13&#8221;, e retornamos.<\/li>\n\n\n\n<li>A seguir, recebemos um dep\u00f3sito para uma conta diferente, n\u00e3o relacionada. N\u00f3s o salvamos no banco de dados. Essa transa\u00e7\u00e3o aumenta o basis-t para 14.<\/li>\n\n\n\n<li>Se recebermos uma nova solicita\u00e7\u00e3o para obter o saldo da conta 2042, usaremos uma chave de cache diferente: &#8220;2042\/14&#8221;. Cache vazio novamente!<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ent\u00e3o, se usarmos a basis-t como parte da nossa chave de cache, perderemos os nossos caches com muita frequ\u00eancia, sem um bom motivo para isso. Todas essas consultas que estamos fazendo examinam os dados de uma conta de cada vez. Perder o cache da conta A por causa de um dep\u00f3sito na conta B \u00e9 tolice.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Podemos fazer melhor?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Contador no n\u00edvel da conta<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Sim!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">S\u00f3 o que precisamos fazer \u00e9 adicionar um atributo \u00e0 nossa entidade <em>conta<\/em> no Datomic. Esse atributo come\u00e7a em zero. Cada vez que fazemos <em>qualquer coisa relacionada a essa conta<\/em>, aumentamos esse atributo em 1 na mesma transa\u00e7\u00e3o. Isso nos d\u00e1 um n\u00famero de vers\u00e3o para os dados da conta, que podemos&nbsp; usar como chave de cache.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Como esse atributo acaba <em>contando<\/em> cada <em>evento<\/em> que acontece em uma conta, n\u00f3s demos a ele um nome muito original: <em>contador de eventos<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A estrutura geral do nosso cache com leitura \u00e9 assim:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Recebemos uma solicita\u00e7\u00e3o do saldo da conta 2042.<\/li>\n\n\n\n<li>Consultamos o Datomic para obter o valor atual do contador de eventos da conta 2042.<\/li>\n\n\n\n<li>O Datomic nos diz que o contador de eventos est\u00e1 em 17 no momento. Nossa chave de cache ser\u00e1 &#8220;2042\/17&#8221;<\/li>\n\n\n\n<li>Procuramos por &#8220;2042\/17&#8221; no armazenamento imut\u00e1vel, mas n\u00e3o encontramos nada. Cache vazio.<\/li>\n\n\n\n<li>Consultamos o Datomic sobre os dados de que precisamos e computamos o saldo.<\/li>\n\n\n\n<li>Salvamos o saldo no armazenamento imut\u00e1vel, na chave &#8220;2042\/17&#8221;, e retornamos.<\/li>\n\n\n\n<li>Horas depois, recebemos uma nova solicita\u00e7\u00e3o do saldo da conta 2042.<\/li>\n\n\n\n<li>O contador de eventos atual ainda est\u00e1 em 17, ent\u00e3o a chave de cache ainda \u00e9 &#8220;2042\/17&#8221;.<\/li>\n\n\n\n<li>Cache encontrado!<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Se recebermos um novo dep\u00f3sito ou saque da conta 2042, aumentaremos o contador de eventos, e isso levar\u00e1 a um cache vazio na pr\u00f3xima solicita\u00e7\u00e3o. Isso \u00e9 inevit\u00e1vel, pois o saldo atual de fato mudou! A parte importante \u00e9 que isso n\u00e3o acontecer\u00e1 por motivos desnecess\u00e1rios, como acontecia quando tentamos usar a basis-t.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">O cache e o banco de dados<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00f3s geralmente pensamos no cache como algo que fica <em>na frente do<\/em> servi\u00e7o atual, protegendo-o contra as solicita\u00e7\u00f5es. \u00c9 isso que os CDNs fazem, por exemplo. Esse tipo de cache nos permite continuar servindo conte\u00fado mesmo se o servi\u00e7o real estiver completamente inativo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por\u00e9m, isso s\u00f3 funciona bem para conte\u00fado <em>est\u00e1tico<\/em>. Se precisarmos de dinamismo, intera\u00e7\u00e3o e a\u00e7\u00f5es que v\u00e3o al\u00e9m de qualquer estado que podemos manter no lado do cliente, teremos que executar c\u00f3digo de aplica\u00e7\u00e3o no lado do servidor de qualquer maneira.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se esse for o tipo de aplica\u00e7\u00e3o que estamos executando, e se a consist\u00eancia for um requisito importante, faz sentido obter alguma coopera\u00e7\u00e3o do servidor e seu banco de dados, mesmo quando estivermos tentando servir a partir do cache.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Observe a diferen\u00e7a: em um CDN, consultamos o cache primeiro, e ent\u00e3o vamos para o servidor de fato, se o cache n\u00e3o tiver a resposta. No esquema que descrevemos acima, <em>a primeira coisa que fazemos \u00e9 consultar o banco de dados para obter o contador de eventos<\/em>. S\u00f3 ent\u00e3o podemos procurar um cache, e depois disso, reverter para o banco de dados e coletar o resto dos dados.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Podemos armazenar em cache praticamente qualquer parte de dados, mas o banco de dados ainda fornece aquela base s\u00f3lida que mant\u00e9m tudo consistente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Faz sentido para o nosso caso de uso, porque a &#8220;disponibilidade a qualquer custo&#8221; n\u00e3o ajuda os nossos clientes. Do que adianta ver um saldo obsoleto de sua conta banc\u00e1ria, se eles n\u00e3o poder\u00e3o fazer nada com isso, j\u00e1 que os servidores est\u00e3o inativos?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Em vez de substituir o servi\u00e7o, nosso primeiro objetivo com o cache era permitir que ele funcionasse usando menos recursos. E conseguimos isso: cada inst\u00e2ncia do nosso servi\u00e7o exigia 90 GB de RAM, mas agora precisa de apenas 55 GB. E ainda melhor: agora somos capazes de escalar o servi\u00e7o horizontalmente se a carga aumentar, porque o trabalho \u00e9 efetivamente distribu\u00eddo entre inst\u00e2ncias. A lat\u00eancia tamb\u00e9m diminuiu para a maioria das solicita\u00e7\u00f5es, o que \u00e9 legal, embora n\u00e3o tenha sido o objetivo principal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Com essa abordagem, conseguimos reduzir drasticamente a quantidade de trabalho repetido que faz\u00edamos nos nossos servidores. Isso tamb\u00e9m nos permitiu suportar uma carga maior com m\u00e1quinas menores, tudo sem abrir m\u00e3o da consist\u00eancia.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Agora, s\u00f3 temos que encontrar uma forma de evitar dar nomes \u00e0s coisas!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">(<em>Mais artigos de <\/em><a href=\"https:\/\/medium.com\/%40gusbicalho\"><em>Gustavo Bicalho<\/em><\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">(Foto por <a href=\"https:\/\/unsplash.com\/%40samscrim?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Samuel Scrimshaw<\/a> em <a href=\"https:\/\/unsplash.com\/s\/photos\/evergreen-forest?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Unsplash<\/a>)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;Guarde cada passo da hist\u00f3ria!&#8221; Como criamos um cache que nunca fica obsoleto no Nubank<\/p>\n","protected":false},"author":178110057,"featured_media":23206,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_eb_attr":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_wpcom_ai_launchpad_first_post":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[2586],"tags":[3074,3075,2582],"class_list":["post-26788","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-engineering-pt-br","tag-cache-pt-br","tag-data-model-pt-br","tag-datomic-pt-br"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Uma floresta digital: o cache perene - Building Nubank<\/title>\n<meta name=\"description\" content=\"&quot;Guarde cada passo da hist\u00f3ria!&quot; Como criamos um cache que nunca fica obsoleto no Nubank\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Uma floresta digital: o cache perene - Building Nubank\" \/>\n<meta property=\"og:description\" content=\"&quot;Guarde cada passo da hist\u00f3ria!&quot; Como criamos um cache que nunca fica obsoleto no Nubank\" \/>\n<meta property=\"og:url\" content=\"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/\" \/>\n<meta property=\"og:site_name\" content=\"Building Nubank\" \/>\n<meta property=\"article:published_time\" content=\"2020-02-11T17:34:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-03-20T17:40:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1440\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Gustavo Bicalho - Software Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Gustavo Bicalho - Software Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. tempo de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/\"},\"author\":{\"name\":\"Gustavo Bicalho - Software Engineer\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/#\\\/schema\\\/person\\\/8fef4b83e99a68039a00c8b6069b71fd\"},\"headline\":\"Uma floresta digital: o cache perene\",\"datePublished\":\"2020-02-11T17:34:00+00:00\",\"dateModified\":\"2024-03-20T17:40:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/\"},\"wordCount\":3387,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/building.nu.com\\\/wp-content\\\/uploads\\\/2020\\\/04\\\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1\",\"keywords\":[\"Cache\",\"data model\",\"Datomic\"],\"articleSection\":[\"Software Engineering\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/\",\"url\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/\",\"name\":\"Uma floresta digital: o cache perene - Building Nubank\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/building.nu.com\\\/wp-content\\\/uploads\\\/2020\\\/04\\\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1\",\"datePublished\":\"2020-02-11T17:34:00+00:00\",\"dateModified\":\"2024-03-20T17:40:07+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/#\\\/schema\\\/person\\\/8fef4b83e99a68039a00c8b6069b71fd\"},\"description\":\"\\\"Guarde cada passo da hist\u00f3ria!\\\" Como criamos um cache que nunca fica obsoleto no Nubank\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/building.nu.com\\\/wp-content\\\/uploads\\\/2020\\\/04\\\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/building.nu.com\\\/wp-content\\\/uploads\\\/2020\\\/04\\\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1\",\"width\":1440,\"height\":600},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/uma-floresta-digital-o-cache-perene\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Uma floresta digital: o cache perene\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/#website\",\"url\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/\",\"name\":\"Building Nubank\",\"description\":\"We make the extraordinary happen\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/#\\\/schema\\\/person\\\/8fef4b83e99a68039a00c8b6069b71fd\",\"name\":\"Gustavo Bicalho - Software Engineer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/0d238d4f6c898ccf82f93e47eb51fcd9581bb48982753e49040d9fed5d0834ae?s=96&d=identicon&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/0d238d4f6c898ccf82f93e47eb51fcd9581bb48982753e49040d9fed5d0834ae?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/0d238d4f6c898ccf82f93e47eb51fcd9581bb48982753e49040d9fed5d0834ae?s=96&d=identicon&r=g\",\"caption\":\"Gustavo Bicalho - Software Engineer\"},\"description\":\"Gustavo is a software engineer at Nubank, where he builds microservices and whatever else is needed to get the product running. He believes the tech industry can be a tool to positively impact the world if we can focus on solving the right problems. He likes programming, drawing weird diagrams on whiteboards, reading science fiction, and learning about how the mind works.\",\"url\":\"https:\\\/\\\/building.nu.com\\\/pt-br\\\/author\\\/bicalho\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Uma floresta digital: o cache perene - Building Nubank","description":"\"Guarde cada passo da hist\u00f3ria!\" Como criamos um cache que nunca fica obsoleto no Nubank","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/","og_locale":"pt_BR","og_type":"article","og_title":"Uma floresta digital: o cache perene - Building Nubank","og_description":"\"Guarde cada passo da hist\u00f3ria!\" Como criamos um cache que nunca fica obsoleto no Nubank","og_url":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/","og_site_name":"Building Nubank","article_published_time":"2020-02-11T17:34:00+00:00","article_modified_time":"2024-03-20T17:40:07+00:00","og_image":[{"width":1440,"height":600,"url":"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1","type":"image\/jpeg"}],"author":"Gustavo Bicalho - Software Engineer","twitter_card":"summary_large_image","twitter_misc":{"Escrito por":"Gustavo Bicalho - Software Engineer","Est. tempo de leitura":"18 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#article","isPartOf":{"@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/"},"author":{"name":"Gustavo Bicalho - Software Engineer","@id":"https:\/\/building.nu.com\/pt-br\/#\/schema\/person\/8fef4b83e99a68039a00c8b6069b71fd"},"headline":"Uma floresta digital: o cache perene","datePublished":"2020-02-11T17:34:00+00:00","dateModified":"2024-03-20T17:40:07+00:00","mainEntityOfPage":{"@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/"},"wordCount":3387,"commentCount":0,"image":{"@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1","keywords":["Cache","data model","Datomic"],"articleSection":["Software Engineering"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/","url":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/","name":"Uma floresta digital: o cache perene - Building Nubank","isPartOf":{"@id":"https:\/\/building.nu.com\/pt-br\/#website"},"primaryImageOfPage":{"@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#primaryimage"},"image":{"@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1","datePublished":"2020-02-11T17:34:00+00:00","dateModified":"2024-03-20T17:40:07+00:00","author":{"@id":"https:\/\/building.nu.com\/pt-br\/#\/schema\/person\/8fef4b83e99a68039a00c8b6069b71fd"},"description":"\"Guarde cada passo da hist\u00f3ria!\" Como criamos um cache que nunca fica obsoleto no Nubank","breadcrumb":{"@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#primaryimage","url":"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1","contentUrl":"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1","width":1440,"height":600},{"@type":"BreadcrumbList","@id":"https:\/\/building.nu.com\/pt-br\/uma-floresta-digital-o-cache-perene\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/building.nu.com\/pt-br\/"},{"@type":"ListItem","position":2,"name":"Uma floresta digital: o cache perene"}]},{"@type":"WebSite","@id":"https:\/\/building.nu.com\/pt-br\/#website","url":"https:\/\/building.nu.com\/pt-br\/","name":"Building Nubank","description":"We make the extraordinary happen","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/building.nu.com\/pt-br\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-BR"},{"@type":"Person","@id":"https:\/\/building.nu.com\/pt-br\/#\/schema\/person\/8fef4b83e99a68039a00c8b6069b71fd","name":"Gustavo Bicalho - Software Engineer","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/secure.gravatar.com\/avatar\/0d238d4f6c898ccf82f93e47eb51fcd9581bb48982753e49040d9fed5d0834ae?s=96&d=identicon&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/0d238d4f6c898ccf82f93e47eb51fcd9581bb48982753e49040d9fed5d0834ae?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0d238d4f6c898ccf82f93e47eb51fcd9581bb48982753e49040d9fed5d0834ae?s=96&d=identicon&r=g","caption":"Gustavo Bicalho - Software Engineer"},"description":"Gustavo is a software engineer at Nubank, where he builds microservices and whatever else is needed to get the product running. He believes the tech industry can be a tool to positively impact the world if we can focus on solving the right problems. He likes programming, drawing weird diagrams on whiteboards, reading science fiction, and learning about how the mind works.","url":"https:\/\/building.nu.com\/pt-br\/author\/bicalho\/"}]}},"jetpack_likes_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pbKBB5-6Y4","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/building.nu.com\/wp-content\/uploads\/2020\/04\/the-evergreen-cache-Header-1.jpg?fit=1440%2C600&ssl=1","_links":{"self":[{"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/posts\/26788","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/users\/178110057"}],"replies":[{"embeddable":true,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/comments?post=26788"}],"version-history":[{"count":4,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/posts\/26788\/revisions"}],"predecessor-version":[{"id":28738,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/posts\/26788\/revisions\/28738"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/media\/23206"}],"wp:attachment":[{"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/media?parent=26788"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/categories?post=26788"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/building.nu.com\/pt-br\/wp-json\/wp\/v2\/tags?post=26788"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}