<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stephanto</title>
    <description>The latest articles on DEV Community by Stephanto (@stephanto).</description>
    <link>https://dev.to/stephanto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3079405%2F8743671d-89fa-48ce-b6ca-cfab8c46dc40.jpg</url>
      <title>DEV Community: Stephanto</title>
      <link>https://dev.to/stephanto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stephanto"/>
    <language>en</language>
    <item>
      <title>JWT ou sessão? Como cada um funciona e quando usar qual</title>
      <dc:creator>Stephanto</dc:creator>
      <pubDate>Tue, 20 Oct 2026 20:24:57 +0000</pubDate>
      <link>https://dev.to/stephanto/jwt-ou-sessao-como-cada-um-funciona-e-quando-usar-qual-4hdc</link>
      <guid>https://dev.to/stephanto/jwt-ou-sessao-como-cada-um-funciona-e-quando-usar-qual-4hdc</guid>
      <description>&lt;p&gt;Começa por aqui: você clica em "Sair". Na sessão, você fica fora na hora. No JWT, o token continua valendo até expirar.&lt;/p&gt;

&lt;p&gt;Parece detalhe, mas essa diferença diz muito sobre como cada um funciona. Estudei sobre o assunto e quero compartilhar com vocês, afinal a melhor forma de aprender é ensinando. No fim do artigo você vai saber como cada um funciona, o preço de cada um e quando usar qual.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0jpekdcjguckzauwplf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0jpekdcjguckzauwplf2.png" alt="O mesmo clique em Sair: na sessão dá 401, fora na hora; no JWT dá 200, ainda dentro até expirar" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É um conteúdo introdutório, a ideia é simplificar. O contexto: numa conversa com o tech lead, veio a pergunta "JWT ou sessão?". Como era uma aplicação web, a escolha foi sessão. Este artigo é pra entender o porquê dessa resposta, e quando ela seria outra.&lt;/p&gt;

&lt;h2&gt;
  
  
  O problema: o HTTP não lembra de você
&lt;/h2&gt;

&lt;p&gt;O HTTP, protocolo da web, é &lt;strong&gt;stateless&lt;/strong&gt;: ele não lembra de nada entre uma requisição e outra. Cada requisição chega "do zero".&lt;/p&gt;

&lt;p&gt;Por exemplo, você loga no e-mail e clica numa mensagem. Pro servidor, esse clique chega sem nenhuma memória do login que você acabou de fazer. Ou seja, depois que você digitou e-mail e senha, alguma coisa precisa viajar em &lt;strong&gt;toda&lt;/strong&gt; requisição seguinte dizendo "sou eu, já fiz login".&lt;/p&gt;

&lt;p&gt;E essa "coisa" é valiosa. A OWASP (a comunidade que mantém os guias de segurança web mais usados) lembra que, depois do login, o identificador da sessão vale temporariamente o mesmo que a credencial mais forte que o usuário usou. Quem rouba esse identificador vira o usuário, e isso se chama &lt;strong&gt;session hijacking&lt;/strong&gt; (sequestro de sessão).&lt;/p&gt;

&lt;p&gt;Existem dois jeitos principais de resolver isso: &lt;strong&gt;Sessão&lt;/strong&gt; e &lt;strong&gt;JWT&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Um aviso antes de começar: é comum ver a comparação "cookie vs JWT", mas isso é comparar maçã com laranja. Cookie é um &lt;strong&gt;lugar&lt;/strong&gt; de guardar coisa no navegador; JWT é um &lt;strong&gt;formato&lt;/strong&gt; de token. As comparações certas são sessão vs JWT (onde fica o estado) e cookie vs localStorage (onde o navegador guarda).&lt;/p&gt;

&lt;h2&gt;
  
  
  Sessão: o servidor guarda, o navegador leva só um número
&lt;/h2&gt;

&lt;p&gt;Na Sessão, o servidor guarda quem está logado num lugar dele: na memória, num banco ou num banco em memória como o Redis. Esse lugar é o &lt;strong&gt;session store&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Pro navegador, ele devolve só um número aleatório, o &lt;strong&gt;session ID&lt;/strong&gt;, dentro de um &lt;strong&gt;cookie&lt;/strong&gt;: um espaço do navegador que vai junto em toda requisição para aquele site, sozinho, sem o JavaScript fazer nada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2t6mw0b47c7m378svzpd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2t6mw0b47c7m378svzpd.png" alt="Ciclo da sessão: login, servidor guarda abc123 = Vinicius, Set-Cookie, e a cada requisição o servidor pergunta ao armazenamento quem é abc123" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na prática, a conversa entre navegador e servidor fica mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /login
(e-mail + senha)

&lt;/span&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Set-Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session_id=abc123; Secure; HttpOnly; SameSite=Lax; Path=/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E a partir daí, em toda requisição:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /emails
Cookie: session_id=abc123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do lado do servidor, cada requisição faz uma consulta ao session store. De forma simplificada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pseudocódigo&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session_id&lt;/span&gt;   &lt;span class="c1"&gt;// "abc123"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sessionStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sessao&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;responder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                          &lt;span class="c1"&gt;// sessão inválida: volta pro login&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usuario&lt;/span&gt;                   &lt;span class="c1"&gt;// "Vinicius"&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;responder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;buscarEmails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A analogia do guarda-volumes
&lt;/h3&gt;

&lt;p&gt;Pensa num guarda-volumes: você entrega a mochila e recebe uma ficha com um número.&lt;/p&gt;

&lt;p&gt;A ficha é o session ID, a mochila são os seus dados e o balcão é o servidor. A ficha sozinha não diz nada, quem sabe o que tem atrás dela é o balcão.&lt;/p&gt;

&lt;h3&gt;
  
  
  O cookie da sessão
&lt;/h3&gt;

&lt;p&gt;Como o session ID viaja em cookie, a segurança dele depende dos atributos que vêm junto no &lt;code&gt;Set-Cookie&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HttpOnly&lt;/strong&gt;: o JavaScript da página não consegue ler o cookie. Ajuda contra XSS (quando um atacante consegue rodar JavaScript dele dentro do seu site).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure&lt;/strong&gt;: o cookie só vai por HTTPS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SameSite&lt;/strong&gt;: controla se o cookie vai junto em requisições que vêm de &lt;strong&gt;outro site&lt;/strong&gt;. &lt;code&gt;Strict&lt;/code&gt; nunca vai; &lt;code&gt;Lax&lt;/code&gt; vai também quando o usuário navega pro seu site vindo de outro (clicou num link); &lt;code&gt;None&lt;/code&gt; vai sempre (e exige &lt;code&gt;Secure&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A OWASP também recomenda trocar o session ID por cookie, e não por parâmetro na URL, porque na URL ele vaza em log, histórico e favoritos. O exemplo que ela dá para um cookie de sessão é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: __Host-SessionID=&amp;lt;value&amp;gt;; Secure; HttpOnly; SameSite=Strict; Path=/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  O lado bom: sair é apagar o registro
&lt;/h3&gt;

&lt;p&gt;O logout é simples: o servidor apaga o registro &lt;code&gt;abc123&lt;/code&gt; do session store. Na próxima requisição, a consulta não encontra nada e você já está fora. É o 401 da imagem lá de cima.&lt;/p&gt;

&lt;p&gt;O mesmo vale pra "sair de todos os dispositivos" ou pra tirar a permissão de admin de alguém: como o servidor consulta a sessão a cada requisição, a mudança vale na hora.&lt;/p&gt;

&lt;h3&gt;
  
  
  Porém, nem tudo são flores: CSRF
&lt;/h3&gt;

&lt;p&gt;O cookie ir sozinho em toda requisição é o ponto forte da sessão e também o ponto fraco.&lt;/p&gt;

&lt;p&gt;Como o cookie vai sozinho, outro site pode fazer seu navegador mandar uma ação com ele. Isso é o &lt;strong&gt;CSRF&lt;/strong&gt; (Cross-Site Request Forgery, ou falsificação de requisição entre sites).&lt;/p&gt;

&lt;p&gt;Vamos com o exemplo clássico da PortSwigger pra entender melhor: um site tem um &lt;code&gt;POST /email/change&lt;/code&gt; que troca o e-mail da conta, e identifica o usuário só pelo cookie de sessão. O atacante monta uma página com um formulário escondido apontando pra esse endereço, com o e-mail dele e um script que envia o formulário sozinho. Você, logado, abre essa página, o navegador manda o cookie junto e o seu e-mail é trocado. Depois é só o atacante pedir "esqueci minha senha" pra tomar a conta.&lt;/p&gt;

&lt;p&gt;O CSRF tem defesa conhecida:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SameSite&lt;/strong&gt; no cookie, que segura o cookie em pedidos vindos de outro site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Um token aleatório no formulário&lt;/strong&gt; (o &lt;em&gt;synchronizer token pattern&lt;/em&gt;): o servidor gera um valor imprevisível, coloca no formulário e confere em todo POST. O site do atacante não tem como adivinhar esse valor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A OWASP trata o SameSite como defesa em profundidade e, na maioria dos casos, não como substituto do token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Outro custo: o estado fica no servidor
&lt;/h3&gt;

&lt;p&gt;Toda requisição consulta o lugar onde as sessões ficam. É uma ida a mais na rede a cada clique.&lt;/p&gt;

&lt;p&gt;E com mais de um servidor atrás de um load balancer, a sessão criada no servidor A não existe no servidor B se ela estiver na memória dele. Por isso, quando a aplicação cresce, o comum é usar um store compartilhado, como um Redis dedicado às sessões.&lt;/p&gt;

&lt;p&gt;E aí vem a pergunta: e se o próprio token carregasse quem você é?&lt;/p&gt;

&lt;h2&gt;
  
  
  JWT: os dados vão no próprio token
&lt;/h2&gt;

&lt;p&gt;É isso que o &lt;strong&gt;JWT&lt;/strong&gt; (JSON Web Token, definido na RFC 7519) faz.&lt;/p&gt;

&lt;p&gt;No JWT, o servidor &lt;strong&gt;assina&lt;/strong&gt; o token com uma chave secreta que só ele tem e entrega pro cliente. Em toda requisição, o token vai junto num campo da requisição, o header &lt;code&gt;Authorization&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /emails
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O servidor só confere a assinatura, sem consultar banco nenhum. Isso é o que chamam de autenticação stateless.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvuzf28c4hg638qo99mdm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvuzf28c4hg638qo99mdm.png" alt="Ciclo do JWT: login, servidor assina o token com a chave secreta, e a cada requisição só confere a assinatura, sem consultar banco" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Bearer" quer dizer "portador": qualquer um que tiver o token pode usar, sem provar mais nada. Ou seja, um JWT vazado vale tanto quanto um cookie de sessão vazado.&lt;/p&gt;

&lt;p&gt;E um detalhe interessante: o navegador não anexa o header &lt;code&gt;Authorization&lt;/code&gt; sozinho, quem coloca é o código da aplicação. Por isso, um JWT enviado nesse header não sofre CSRF do jeito que o cookie sofre.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por dentro do token
&lt;/h3&gt;

&lt;p&gt;Por dentro, o token tem 3 partes separadas por ponto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Header&lt;/strong&gt;: como foi assinado (o algoritmo).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload&lt;/strong&gt;: os dados, como o seu id, a sua permissão e quando expira.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signature&lt;/strong&gt;: a assinatura.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9eusrq0g4s43daaosyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9eusrq0g4s43daaosyc.png" alt="JWT: 3 partes separadas por ponto, header, payload e signature, com cada trecho decodificado" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este é o token da imagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3OTI1MzcyMDB9.5D9T1LnD3PpUHNJxm8pq_sny42svPgUxKkkpA8ZSnsQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decodificando as duas primeiras partes, &lt;strong&gt;sem chave nenhuma&lt;/strong&gt;, dá:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Header&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HS256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// como foi assinado&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;     &lt;span class="c1"&gt;// é um JWT&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Payload&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sub&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// quem é você (id 123)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// a permissão, criada pela aplicação&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1792537200&lt;/span&gt;   &lt;span class="c1"&gt;// quando expira, em segundos desde 1970&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare: Header e Payload são só &lt;strong&gt;base64url&lt;/strong&gt;, uma codificação, não criptografia. Qualquer um lê. Dá pra testar no terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3OTI1MzcyMDB9'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;span class="c"&gt;# {"sub":"123","role":"admin","exp":1792537200}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Esse comando só funciona direto aqui porque esse trecho não precisa de padding. Em geral, troque &lt;code&gt;-_&lt;/code&gt; por &lt;code&gt;+/&lt;/code&gt; e complete com &lt;code&gt;=&lt;/code&gt; antes de decodificar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ou seja, a assinatura protege o token contra &lt;strong&gt;alteração&lt;/strong&gt;, não contra &lt;strong&gt;leitura&lt;/strong&gt;. Se alguém trocar &lt;code&gt;"role":"user"&lt;/code&gt; por &lt;code&gt;"role":"admin"&lt;/code&gt;, a assinatura não bate mais e o servidor recusa. Mas nada de colocar segredo no payload.&lt;/p&gt;

&lt;h3&gt;
  
  
  A analogia do crachá
&lt;/h3&gt;

&lt;p&gt;Pensa num crachá com seu nome, cargo e validade, carimbado pela empresa.&lt;/p&gt;

&lt;p&gt;O crachá é o JWT e o carimbo é a assinatura: qualquer porteiro confere e libera, sem ligar pra ninguém. O problema é que o porteiro não tem como saber se você foi demitido ontem.&lt;/p&gt;

&lt;h2&gt;
  
  
  O problema central do JWT: ele vale até expirar
&lt;/h2&gt;

&lt;p&gt;Esse é o ponto principal: o JWT vale até expirar, não importa o quê. O servidor não guarda nada sobre os tokens que emitiu, então não tem o que apagar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicou em "Sair"? O token continua valendo. É o 200 da imagem lá de cima.&lt;/li&gt;
&lt;li&gt;Tirou o admin de alguém? O token antigo segue dizendo &lt;code&gt;"role":"admin"&lt;/code&gt; até vencer.&lt;/li&gt;
&lt;li&gt;Detectou uma invasão? O token do atacante também segue válido.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  As mitigações (e o custo delas)
&lt;/h3&gt;

&lt;p&gt;Dá pra contornar, mas cada saída tem um preço:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token curto + refresh token&lt;/strong&gt;: o token que vai em toda requisição (o &lt;em&gt;access token&lt;/em&gt;) vive pouco. Pra pegar outro, o cliente usa um &lt;strong&gt;refresh token&lt;/strong&gt;, um segundo token que, pela RFC 6749 (OAuth 2.0), serve só pra pedir novos access tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lista de bloqueio (denylist)&lt;/strong&gt;: guardar os tokens revogados e conferir em toda requisição.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mas aí o servidor volta a guardar estado: precisa guardar os refresh tokens, ou consultar a lista de bloqueio a cada requisição. A própria OWASP diz que, se você usa JWT como sessão, vai precisar de um jeito de invalidar, e aí a sessão deixa de ser stateless, o que pode acabar com a vantagem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onde guardar o JWT no navegador?
&lt;/h3&gt;

&lt;p&gt;Aqui aparece um dilema que a sessão não tem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;localStorage&lt;/strong&gt;: o JavaScript lê à vontade. A OWASP recomenda não guardar tokens de autenticação ali, porque um único XSS vaza todos eles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie HttpOnly&lt;/strong&gt;: protege contra XSS, mas aí o navegador manda o cookie sozinho e você volta a ter CSRF. Na prática, vira um cookie de sessão mais pesado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Um risco extra: quem escolhe o algoritmo?
&lt;/h2&gt;

&lt;p&gt;Lembra do header, que diz o algoritmo? Ele vem &lt;strong&gt;do cliente&lt;/strong&gt;, e ainda não foi validado quando o servidor lê ele. Se a biblioteca confia no &lt;code&gt;alg&lt;/code&gt;, é o atacante quem escolhe como a assinatura vai ser verificada.&lt;/p&gt;

&lt;p&gt;Em 2015, o pesquisador Tim McLean achou bibliotecas de JWT aceitando &lt;code&gt;"alg":"none"&lt;/code&gt;, ou seja, um token &lt;strong&gt;sem assinatura&lt;/strong&gt; sendo tratado como se a assinatura tivesse sido verificada. O ataque é trocar o header, mudar o payload pro que quiser e deixar a assinatura vazia:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Header forjado&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Payload forjado&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sub&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No pacote &lt;code&gt;jsonwebtoken&lt;/code&gt; (Node.js), um erro parecido, na validação do tipo de algoritmo (aceitar HS256 quando esperava RS256), virou a falha &lt;strong&gt;CVE-2015-9235&lt;/strong&gt;, com nota &lt;strong&gt;9.8 de 10&lt;/strong&gt; no NVD. As versões 4.2.1 e anteriores eram afetadas, e a correção veio na 4.2.2.&lt;/p&gt;

&lt;p&gt;A defesa: &lt;strong&gt;o servidor fixa o algoritmo&lt;/strong&gt;. A RFC 8725 (boas práticas de JWT) pede que a biblioteca deixe você dizer quais algoritmos aceita, e não use nenhum outro. De forma simplificada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pseudocódigo&lt;/span&gt;

&lt;span class="c1"&gt;// errado: deixa o token escolher o algoritmo&lt;/span&gt;
&lt;span class="nf"&gt;verificar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chave&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// certo: o servidor já sabe qual algoritmo usa&lt;/span&gt;
&lt;span class="nf"&gt;verificar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chave&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;algoritmos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HS256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com sessão esse problema não existe: o servidor só compara um ID aleatório, não tem algoritmo pra escolher errado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando usar cada um?
&lt;/h2&gt;

&lt;p&gt;Não é regra, cada caso é um caso. Mas uma pergunta ajuda: &lt;strong&gt;quem é o cliente?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0o5amcvjtmdz6wkbbolr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0o5amcvjtmdz6wkbbolr.png" alt="Quem é o cliente? Navegador falando com o seu backend: normalmente sessão. App mobile, outro serviço ou SSO: normalmente JWT" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Navegador falando com o seu backend: normalmente sessão.&lt;/strong&gt; O navegador já manda o cookie sozinho, o HttpOnly protege contra XSS, o logout vale na hora e o CSRF tem defesa conhecida. A própria Auth0 indica cookie nesse cenário: quando o frontend só chama uma API num domínio que compartilha cookie com ele, não precisa de token nenhum.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App mobile, outro serviço ou SSO: normalmente JWT.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;App mobile&lt;/strong&gt;: não tem o cookie automático do navegador, então um token curto no &lt;code&gt;Authorization&lt;/code&gt; + refresh token é o caminho comum.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outro serviço&lt;/strong&gt;: um serviço confere a assinatura do token sozinho, sem precisar chamar ninguém.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSO&lt;/strong&gt; (Single Sign-On, logar uma vez e entrar em vários sistemas): no OpenID Connect, o ID Token, que diz quem é o usuário, é um JWT pela própria especificação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E dá até pra usar os dois na mesma aplicação: sessão pro navegador, JWT curto pro app e pros serviços. Foi por isso que, numa aplicação web, a resposta pro tech lead foi sessão.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resumindo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;O HTTP esquece você a cada requisição.&lt;/li&gt;
&lt;li&gt;Sessão: o servidor guarda, o cookie leva só um número.&lt;/li&gt;
&lt;li&gt;JWT: os dados vão no token, assinados e legíveis.&lt;/li&gt;
&lt;li&gt;Sessão sai na hora, JWT vale até expirar.&lt;/li&gt;
&lt;li&gt;Em geral, navegador: sessão. Mobile, serviços e SSO: JWT.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Apresentei apenas algo introdutório, recomendo se aprofundarem! Cada caso é um caso, e não existe vencedor absoluto: cada um é certo pro seu tipo de cliente.&lt;/p&gt;

&lt;p&gt;Pra quem já é experiente: no seu último projeto vocês foram de sessão ou JWT, e por quê? Conta nos comentários.&lt;/p&gt;

&lt;p&gt;Obrigado por ler até aqui!&lt;/p&gt;

&lt;p&gt;Esse artigo nasceu de uma &lt;a href="https://x.com/StephantoDev/status/2112639690071253348" rel="noopener noreferrer"&gt;thread que publiquei no X&lt;/a&gt;. Se preferir a versão curta, com os diagramas, é só dar uma olhada lá.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP: Session Management Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies" rel="noopener noreferrer"&gt;MDN: Using HTTP cookies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://portswigger.net/web-security/csrf" rel="noopener noreferrer"&gt;PortSwigger: CSRF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP: Cross-Site Request Forgery Prevention Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc7519" rel="noopener noreferrer"&gt;RFC 7519: JSON Web Token (JWT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jwt.io/introduction" rel="noopener noreferrer"&gt;jwt.io: Introduction to JSON Web Tokens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP: JSON Web Token Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/" rel="noopener noreferrer"&gt;Stop using JWT for sessions (Sven Slootweg)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6749" rel="noopener noreferrer"&gt;RFC 6749: OAuth 2.0 (refresh token)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation" rel="noopener noreferrer"&gt;Auth0: Refresh Token Rotation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6750" rel="noopener noreferrer"&gt;RFC 6750: Bearer Token Usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/" rel="noopener noreferrer"&gt;Auth0: Critical vulnerabilities in JSON Web Token libraries (Tim McLean)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2015-9235" rel="noopener noreferrer"&gt;NVD: CVE-2015-9235&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/advisories/GHSA-c7hr-j4mj-j2w6" rel="noopener noreferrer"&gt;GitHub Advisory: GHSA-c7hr-j4mj-j2w6 (correção na 4.2.2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc8725" rel="noopener noreferrer"&gt;RFC 8725: JWT Best Current Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/docs/secure/security-guidance/data-security/token-storage" rel="noopener noreferrer"&gt;Auth0: Token Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openid.net/specs/openid-connect-core-1_0.html" rel="noopener noreferrer"&gt;OpenID Connect Core 1.0 (SSO e ID Token)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>jwt</category>
      <category>security</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>O que fazer quando seu banco de dados não aguenta mais? Uma introdução ao Sharding</title>
      <dc:creator>Stephanto</dc:creator>
      <pubDate>Fri, 16 Oct 2026 14:40:02 +0000</pubDate>
      <link>https://dev.to/stephanto/o-que-fazer-quando-seu-banco-de-dados-nao-aguenta-mais-uma-introducao-ao-sharding-33bg</link>
      <guid>https://dev.to/stephanto/o-que-fazer-quando-seu-banco-de-dados-nao-aguenta-mais-uma-introducao-ao-sharding-33bg</guid>
      <description>&lt;p&gt;Empresas como Notion, Slack e Discord passaram por isso e usaram a mesma técnica: o sharding. Estudei sobre o assunto e quero compartilhar com vocês de forma simples, afinal a melhor forma de aprender é ensinando.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fne57rw496hxgc8lxhzwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fne57rw496hxgc8lxhzwx.png" alt="Banco único vs vários bancos" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  O cenário: o banco não aguenta mais
&lt;/h2&gt;

&lt;p&gt;Seu sistema cresceu, o banco ficou lento e as escritas começam a engasgar. O primeiro reflexo é comprar uma máquina maior, com mais CPU, mais memória e disco mais rápido. Isso se chama &lt;strong&gt;escala vertical&lt;/strong&gt;, ou seja, crescer "para cima".&lt;/p&gt;

&lt;p&gt;Porém, nem tudo são flores. A escala vertical tem um teto: em algum momento não existe máquina maior para comprar. Além disso, fica cada vez mais caro, e se essa única máquina cair, cai tudo junto. É o famoso ponto único de falha.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Mas e as réplicas?"
&lt;/h3&gt;

&lt;p&gt;Réplicas são cópias do banco e ajudam muito na &lt;strong&gt;leitura&lt;/strong&gt;, porque espalham as consultas. Porém, toda &lt;strong&gt;escrita&lt;/strong&gt; continua indo para um único banco principal. Se o gargalo é escrita ou volume de dados, réplica não resolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é sharding
&lt;/h2&gt;

&lt;p&gt;Em vez de uma máquina maior, você usa &lt;strong&gt;várias&lt;/strong&gt; máquinas, e cada uma guarda só uma parte dos dados. Cada parte é chamada de &lt;strong&gt;shard&lt;/strong&gt;. Todas têm as mesmas tabelas, mas linhas diferentes. Ou seja, escala &lt;strong&gt;horizontal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por exemplo, um app com 3 milhões de usuários. A shard key (já explico o que é) é o id do usuário: ids de 1 a 1 milhão vão para o shard 1, de 1 a 2 milhões para o shard 2 e de 2 a 3 milhões para o shard 3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4qn5j9puqxp7i32eqbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4qn5j9puqxp7i32eqbv.png" alt="Banco dividido em shards" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É como uma biblioteca que lotou e abriu unidades: autores de A a M na unidade 1, de N a Z na unidade 2. Achar um livro pelo autor é fácil. Mas achar "todos os livros de 2020" obriga a visitar &lt;strong&gt;todas&lt;/strong&gt; as unidades. Guarda essa ideia, porque ela é o coração dos problemas do sharding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharding, particionamento e replicação
&lt;/h2&gt;

&lt;p&gt;Três termos que confundem muito:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Particionamento&lt;/strong&gt;: dividir uma tabela em pedaços, geralmente no mesmo servidor. Por exemplo, o partitioning nativo do PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharding&lt;/strong&gt;: dividir os dados entre servidores diferentes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replicação&lt;/strong&gt;: fazer cópias iguais dos dados em vários servidores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ou seja, sharding ajuda a escalar escrita e volume, e replicação ajuda a escalar leitura e disponibilidade. E eles andam juntos: na prática, cada shard costuma ter as suas próprias réplicas. Um não substitui o outro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como o sistema sabe onde está cada dado?
&lt;/h2&gt;

&lt;p&gt;Se os dados estão espalhados, alguém precisa encaminhar a consulta para o shard certo. Isso pode ficar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No código da aplicação&lt;/strong&gt;, que calcula o shard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Num intermediário&lt;/strong&gt;, como o &lt;a href="https://vitess.io/docs/overview/whatisvitess/" rel="noopener noreferrer"&gt;Vitess&lt;/a&gt;, que nasceu no YouTube e é usado pelo Slack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No próprio banco&lt;/strong&gt;, como o &lt;a href="https://www.mongodb.com/docs/manual/sharding/" rel="noopener noreferrer"&gt;sharding nativo do MongoDB&lt;/a&gt; ou o Citus no Postgres.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No MongoDB, por exemplo, a aplicação fala com o roteador &lt;code&gt;mongos&lt;/code&gt;, que consulta os metadados nos config servers e manda a query para o shard certo.&lt;/p&gt;

&lt;h2&gt;
  
  
  A shard key: a decisão mais importante
&lt;/h2&gt;

&lt;p&gt;A shard key é a coluna que decide em qual shard cada linha vai morar. Uma boa chave tem muitos valores diferentes, distribui os dados por igual e aparece em quase toda consulta. Por exemplo, o id do usuário.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por faixa (range)
&lt;/h3&gt;

&lt;p&gt;Ids de 1 a 1 milhão no shard A, de 1 a 2 milhões no shard B. É ótima para buscar intervalos. Mas se a chave for a data, toda escrita de hoje cai no mesmo shard, que fica sobrecarregado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t2wkk938r68lz4lgvrs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t2wkk938r68lz4lgvrs.png" alt="Sharding por faixa" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Por hash
&lt;/h3&gt;

&lt;p&gt;O sistema passa a chave por uma função matemática (algo como &lt;code&gt;hash(user_id) % N&lt;/code&gt;) que espalha os dados por igual entre os shards. Distribui muito bem. Porém, buscar um intervalo vira perguntar para todos os shards e juntar a resposta.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcur58pe3n5v4yn32mgoi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcur58pe3n5v4yn32mgoi.png" alt="Sharding por hash" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Por região ou por cliente
&lt;/h3&gt;

&lt;p&gt;Também dá para separar por região, deixando os dados perto do usuário, ou por cliente. Por exemplo, o &lt;a href="https://www.notion.com/blog/sharding-postgres-at-notion" rel="noopener noreferrer"&gt;Notion dividiu o banco pelo id do workspace&lt;/a&gt;. Assim, os dados de uma mesma empresa ficam juntos e quase toda consulta vai para um shard só.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dica: shards lógicos
&lt;/h3&gt;

&lt;p&gt;Uma dica que o Notion usou: crie muito mais shards "lógicos" do que máquinas. Eles começaram com 480 shards em 32 bancos. É como uma mudança: você empacota tudo em 480 caixas. Se trocar 32 armários por 64, move caixas inteiras, sem desempacotar livro por livro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Os problemas
&lt;/h2&gt;

&lt;p&gt;Lembra das unidades da biblioteca? Consultas que cruzam shards, como JOINs e relatórios gerais, precisam perguntar para todos e juntar o resultado na aplicação. E transações envolvendo vários shards ficam caras e complicadas.&lt;/p&gt;

&lt;p&gt;Outros problemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ids&lt;/strong&gt;: o auto-incremento de cada shard pode repetir o mesmo número.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shard "quente"&lt;/strong&gt;: um cliente muito ativo concentra a carga. O &lt;a href="https://discord.com/blog/how-discord-stores-trillions-of-messages" rel="noopener noreferrer"&gt;Discord conta isso&lt;/a&gt; no post sobre como guarda trilhões de mensagens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resharding&lt;/strong&gt;: mudar os dados de shard com o sistema no ar é a parte mais arriscada.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Então quando usar?
&lt;/h2&gt;

&lt;p&gt;Só depois de tentar o mais simples: melhorar queries e índices, colocar cache, réplicas de leitura e uma máquina maior. E quando o problema é escrita ou volume que não cabe mais num servidor. Sharding cedo demais é complexidade de graça.&lt;/p&gt;

&lt;p&gt;Ou seja, sharding resolve o limite de um banco só, mas cobra em complexidade para sempre, na aplicação e na operação. E sempre que possível, prefira ferramentas que já fazem isso por você (Vitess, Citus, MongoDB) em vez de reinventar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Apresentei apenas algo introdutório, recomendo se aprofundarem! Se você já é experiente, complementa nos comentários. Obrigado por ler até aqui!&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/sharding/" rel="noopener noreferrer"&gt;MongoDB: Sharding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitess.io/docs/overview/whatisvitess/" rel="noopener noreferrer"&gt;Vitess: What is Vitess&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.engineering/scaling-datastores-at-slack-with-vitess/" rel="noopener noreferrer"&gt;Slack Engineering: Scaling datastores at Slack with Vitess&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.notion.com/blog/sharding-postgres-at-notion" rel="noopener noreferrer"&gt;Notion: Sharding Postgres at Notion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discord.com/blog/how-discord-stores-trillions-of-messages" rel="noopener noreferrer"&gt;Discord: How Discord stores trillions of messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/anfibiacreativa/bases-de-datos-distribuidas-sharding-4a39"&gt;Bases de datos distribuidas: sharding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/jefersoneiji/sharding-vs-partitioning-whats-the-difference-in-software-engineering-24ka"&gt;Sharding vs. Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>systemdesign</category>
      <category>backend</category>
      <category>sharding</category>
    </item>
    <item>
      <title>Cache e CDN são a mesma coisa?</title>
      <dc:creator>Stephanto</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:06:26 +0000</pubDate>
      <link>https://dev.to/stephanto/cache-e-cdn-sao-a-mesma-coisa-533</link>
      <guid>https://dev.to/stephanto/cache-e-cdn-sao-a-mesma-coisa-533</guid>
      <description>&lt;p&gt;Muita gente usa os dois termos como sinônimos, mas não são. Estudei sobre isso e quero compartilhar com vocês, afinal a melhor forma de aprender é ensinando.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é cache
&lt;/h2&gt;

&lt;p&gt;De forma simples, cache é guardar uma cópia de um dado em um lugar mais rápido ou mais perto de quem vai usar, para não precisar buscar de novo na fonte original. Ou seja, você troca espaço (memória ou disco) por velocidade.&lt;/p&gt;

&lt;p&gt;Repare que cache é um &lt;strong&gt;conceito&lt;/strong&gt;, não uma ferramenta. Existe cache na CPU, no navegador, no servidor, no banco de dados. E ele funciona porque a gente acessa sempre os mesmos dados: um post viral, o perfil do usuário logado, o logo do site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hit e miss
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hit&lt;/strong&gt;: o dado estava no cache, e a resposta sai rápido.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Miss&lt;/strong&gt;: não estava, então é preciso buscar na fonte original e, normalmente, salvar no cache para a próxima vez.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Num &lt;a href="https://dev.to/imichaelowolabi/caching-in-node-js-using-redis-o1b"&gt;artigo aqui do dev.to com Node + Redis&lt;/a&gt;, a primeira requisição (miss, que foi buscar numa API externa) levou 615 ms. A mesma requisição depois de cacheada (hit) levou 3 ms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4pbv73hvylgyxfz2l7bw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4pbv73hvylgyxfz2l7bw.png" alt="Cache hit e miss" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  TTL (Time To Live)
&lt;/h3&gt;

&lt;p&gt;TTL é quanto tempo um dado vale antes de expirar. Por exemplo, se guardo o perfil de um usuário por 5 minutos e ele troca a foto, os outros podem continuar vendo a foto antiga por até 5 minutos. TTL curto deixa o dado mais fresco, mas gera mais misses; TTL longo dá mais hits, com mais chance de mostrar dado velho.&lt;/p&gt;

&lt;h2&gt;
  
  
  As camadas de cache
&lt;/h2&gt;

&lt;p&gt;Entre o usuário e o banco de dados existem várias camadas de cache, e cada uma guarda coisas diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navegador&lt;/li&gt;
&lt;li&gt;CDN&lt;/li&gt;
&lt;li&gt;Reverse proxy (NGINX, Varnish)&lt;/li&gt;
&lt;li&gt;Cache de aplicação (Redis, Memcached)&lt;/li&gt;
&lt;li&gt;O próprio banco de dados&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhahl3yl4vdqu4kx5eolz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhahl3yl4vdqu4kx5eolz.png" alt="Camadas de cache" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache-aside
&lt;/h3&gt;

&lt;p&gt;A estratégia mais comum no cache de aplicação é o cache-aside. A aplicação olha primeiro no cache; se der miss, busca no banco, salva no cache e devolve. Num e-commerce, quem abre primeiro o "Tênis X" paga a ida ao banco, e os próximos milhares recebem do Redis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nem tudo são flores
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Há só duas coisas difíceis em Ciência da Computação: invalidação de cache e dar nomes às coisas." (frase atribuída a Phil Karlton)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Invalidação.&lt;/strong&gt; Quando o dado muda na fonte, como fazer o cache esquecer a versão velha?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache stampede.&lt;/strong&gt; Imagine a página inicial de um site de notícias com TTL de 60 segundos. No segundo 61 a chave expira, milhares de requisições dão miss juntas e todas batem no banco. O banco pode cair.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cachear o que não devia.&lt;/strong&gt; O erro mais perigoso é guardar num cache compartilhado (proxy ou CDN) uma página com dado de usuário logado. O usuário A abre "Minha conta", a resposta fica cacheada e o usuário B recebe a página com os dados do A. Para isso existe o &lt;code&gt;Cache-Control: private&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é CDN
&lt;/h2&gt;

&lt;p&gt;CDN (Content Delivery Network) é uma &lt;strong&gt;infraestrutura&lt;/strong&gt;: uma rede de servidores espalhados pelo mundo que guardam cópias do seu conteúdo perto do usuário. Exemplos: Cloudflare, Amazon CloudFront, Akamai e Fastly.&lt;/p&gt;

&lt;p&gt;O problema que ela resolve é físico. O dado viaja por cabos, e distância é latência. Se seu servidor está nos EUA e o usuário está em Manaus, cada imagem, CSS e JS faz essa viagem de ida e volta. Com uma CDN, ele baixa tudo de um servidor no Brasil.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como funciona
&lt;/h3&gt;

&lt;p&gt;O usuário acessa &lt;code&gt;meusite.com/logo.png&lt;/code&gt; e o DNS manda ele para o servidor da CDN mais próximo, o PoP (Point of Presence). Se o PoP tem o arquivo, entrega na hora. Se não tem, busca no seu servidor (a origem), entrega e guarda para os próximos.&lt;/p&gt;

&lt;p&gt;Quem diz o que a CDN pode guardar, e por quanto tempo, são os headers que a origem manda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Cache-Control: public, max-age=31536000, immutable&lt;/code&gt; permite guardar por um ano (bom para arquivos com hash no nome).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Cache-Control: private&lt;/code&gt; proíbe a CDN de guardar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ETag&lt;/code&gt; e &lt;code&gt;Last-Modified&lt;/code&gt; permitem perguntar "mudou?" e receber um &lt;code&gt;304 Not Modified&lt;/code&gt; sem baixar de novo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flqjtse9lvnhqehzp1wir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flqjtse9lvnhqehzp1wir.png" alt="Caminho de uma requisição pela CDN" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um exemplo grande é a Netflix, que tem a própria CDN, a &lt;a href="https://openconnect.netflix.com/en/" rel="noopener noreferrer"&gt;Open Connect&lt;/a&gt;. Ela coloca servidores dentro dos provedores de internet, e o site oficial fala em mais de mil provedores parceiros. Ou seja, a série que você assiste provavelmente vem de dentro do seu provedor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Então, qual a diferença?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cache é o conceito; CDN é uma aplicação dele em escala geográfica.&lt;/li&gt;
&lt;li&gt;O Redis fica perto do &lt;strong&gt;servidor&lt;/strong&gt;; a CDN fica perto do &lt;strong&gt;usuário&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A CDN resolve distância, mas não resolve query lenta no banco.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9xohng8tuywyry3bvxbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9xohng8tuywyry3bvxbv.png" alt="Cache vs CDN" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E eles não são concorrentes: a maioria dos sistemas grandes usa os dois.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cache de aplicação para&lt;/strong&gt; queries pesadas e repetidas, sessões e dados lidos muito e mudados pouco.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use CDN para&lt;/strong&gt; usuários espalhados pelo mundo, imagens, JS, CSS, vídeo e picos de tráfego.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando NÃO usar cache
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dado que precisa estar sempre certo na leitura, como saldo ou estoque na hora do pagamento.&lt;/li&gt;
&lt;li&gt;Dado que muda o tempo todo e quase não se repete.&lt;/li&gt;
&lt;li&gt;No começo do projeto, sem gargalo medido: cache cedo demais esconde problema de query.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Apresentei apenas algo introdutório, recomendo se aprofundarem! Se você já é experiente, complementa nos comentários. Obrigado por ler até aqui!&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching" rel="noopener noreferrer"&gt;MDN: HTTP caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/" rel="noopener noreferrer"&gt;Cloudflare: What is a CDN?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/learning/cdn/what-is-caching/" rel="noopener noreferrer"&gt;Cloudflare: What is caching?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/caching/" rel="noopener noreferrer"&gt;AWS: Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openconnect.netflix.com/en/" rel="noopener noreferrer"&gt;Netflix Open Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/imichaelowolabi/caching-in-node-js-using-redis-o1b"&gt;Caching in Node.js using Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/gabrielanhaia/caching-layers-in-2026-cdn-app-db-query-what-goes-where-4p4m"&gt;Caching layers in 2026: CDN, app, DB query&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cache</category>
      <category>cdn</category>
      <category>webdev</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Pirâmide de Testes: Do Unitário ao E2E - Introdução</title>
      <dc:creator>Stephanto</dc:creator>
      <pubDate>Mon, 02 Jun 2025 21:44:35 +0000</pubDate>
      <link>https://dev.to/stephanto/piramide-de-testes-do-unitario-ao-e2e-introducao-5f0</link>
      <guid>https://dev.to/stephanto/piramide-de-testes-do-unitario-ao-e2e-introducao-5f0</guid>
      <description>&lt;p&gt;Olá, comunidade dev! 👋 Se você busca desenvolver software com mais qualidade e confiança, entender a &lt;strong&gt;Pirâmide de Testes&lt;/strong&gt; é fundamental. Popularizada por Mike Cohn, essa abordagem nos ajuda a organizar e priorizar os diferentes tipos de testes em nossos projetos.&lt;/p&gt;

&lt;p&gt;Neste artigo, vamos mergulhar nas suas camadas – Unitários, Integração e End-to-End (E2E) – e desvendar o &lt;strong&gt;valor&lt;/strong&gt; e o &lt;strong&gt;custo&lt;/strong&gt; de cada uma. Preparados? 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  As Camadas da Pirâmide: Uma Visão Geral
&lt;/h2&gt;

&lt;p&gt;A pirâmide é visualmente dividida em três camadas principais, cada uma com um papel específico e diferentes trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧱 &lt;strong&gt;Testes Unitários:&lt;/strong&gt; A base sólida.&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Testes de Integração:&lt;/strong&gt; A conexão entre as partes.&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;Testes End-to-End (E2E):&lt;/strong&gt; A validação da experiência completa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd3maxXQAEL2Py%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd3maxXQAEL2Py%3Fformat%3Djpg%26name%3D4096x4096" alt="Pirâmide de Testes Clássica" width="3439" height="1743"&gt;&lt;/a&gt;  Vamos explorar cada uma delas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testes End-to-End (E2E): Validando a Experiência do Usuário 🎯
&lt;/h2&gt;

&lt;p&gt;No topo da pirâmide, os testes E2E simulam a jornada completa de um &lt;strong&gt;usuário real&lt;/strong&gt; interagindo com sua aplicação. Pense em um teste de cadastro: o script abriria o site, preencheria os campos, submeteria o formulário e verificaria o resultado, passando pelo frontend, backend, banco de dados e qualquer outro serviço envolvido.&lt;/p&gt;

&lt;h3&gt;
  
  
  Valor do E2E:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Máximo para o Negócio:&lt;/strong&gt; Garante que a funcionalidade crítica está operando como esperado do início ao fim, sob a perspectiva do usuário. ✅&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alta Confiança:&lt;/strong&gt; Um conjunto de testes E2E bem-sucedido transmite grande confiança sobre a saúde geral da aplicação.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custo do E2E:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Altíssimo:&lt;/strong&gt; São os testes mais caros para desenvolver, manter e executar. 💸&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Depuração Complexa:&lt;/strong&gt; Identificar a causa raiz de uma falha pode ser demorado, já que muitos componentes estão envolvidos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ambiente Exigente:&lt;/strong&gt; Requerem um ambiente de testes o mais fiel possível ao de produção, o que pode ser custoso e complexo de configurar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd5aYrWgAEfNK7%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd5aYrWgAEfNK7%3Fformat%3Djpg%26name%3D4096x4096" alt="Diagrama Teste E2E" width="2090" height="1689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testes Unitários: A Fundação Sólida 🧱
&lt;/h2&gt;

&lt;p&gt;Na base da pirâmide, os testes unitários focam na &lt;strong&gt;menor unidade de código&lt;/strong&gt; isolável: uma função, um método ou uma classe pequena. O objetivo é simples: para uma entrada X, esperamos uma saída Y. Testamos diversos cenários, incluindo caminhos felizes e casos de exceção.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd6Q7jWsAA77uu%3Fformat%3Dpng%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd6Q7jWsAA77uu%3Fformat%3Dpng%26name%3D4096x4096" alt="Exemplo de Teste Unitário" width="3309" height="2949"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;### Mocks ao Resgate!&lt;/p&gt;

&lt;p&gt;Um erro comum é achar que testes unitários precisam acessar o banco de dados ou outros serviços externos. Pelo contrário! Para garantir isolamento e rapidez, usamos &lt;strong&gt;mocks&lt;/strong&gt; (objetos simulados) para representar essas dependências.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwycjzm9gpeofwn7sywx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwycjzm9gpeofwn7sywx.jpg" alt="Mocks" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custo dos Unitários:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Baixíssimo:&lt;/strong&gt; São baratos para escrever, executar e manter. ⚡️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback Rápido:&lt;/strong&gt; Executam em milissegundos, fornecendo feedback quase instantâneo aos desenvolvedores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Depuração Fácil:&lt;/strong&gt; Quando um teste unitário falha, o problema geralmente está contido na pequena unidade testada.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Valor dos Unitários:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Menor Valor Isolado (para o Negócio):&lt;/strong&gt; Sozinhos, não garantem que a aplicação inteira funcione. Muitas unidades funcionando perfeitamente em isolamento podem falhar ao serem integradas. 🧩&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base Crucial para a Qualidade:&lt;/strong&gt; Apesar disso, são a fundação! Ajudam a garantir que cada "tijolo" da sua aplicação é confiável.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guia de Design:&lt;/strong&gt; Incentivam um bom design de código (baixo acoplamento, alta coesão) e revelam problemas como falta de abstração ou injeção de dependência inadequada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentação Viva:&lt;/strong&gt; Descrevem como cada unidade de código deve se comportar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grande Quantidade:&lt;/strong&gt; São os testes mais numerosos em uma codebase saudável.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd7GfQXQAANuNJ%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd7GfQXQAANuNJ%3Fformat%3Djpg%26name%3D4096x4096" alt="Custo unitários" width="2090" height="1689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testes de Integração: Conectando os Pontos 🔗
&lt;/h2&gt;

&lt;p&gt;Localizados no meio da pirâmide, os testes de integração verificam se diferentes unidades ou componentes do sistema &lt;strong&gt;se comunicam e colaboram corretamente&lt;/strong&gt;. Se os testes unitários garantem que os tijolos são bons, os de integração garantem que eles se encaixam.&lt;/p&gt;

&lt;p&gt;Aqui, pode ser válido interagir com um banco de dados real (geralmente em uma instância de teste, de menor escala) ou outros serviços externos para validar essa comunicação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd73zUW8AApSkx%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd73zUW8AApSkx%3Fformat%3Djpg%26name%3D4096x4096" alt="Diagrama Teste de Integração" width="4096" height="2590"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Valor da Integração:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Médio:&lt;/strong&gt; Fornecem uma boa visão para os desenvolvedores sobre como diferentes partes da aplicação interagem e como os recursos são utilizados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confiança na Colaboração:&lt;/strong&gt; Aumentam a confiança de que os módulos principais funcionam bem juntos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indicador de Saúde:&lt;/strong&gt; Embora não representem a experiência final do usuário, dão um bom panorama do estado da aplicação.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custo da Integração:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Médio:&lt;/strong&gt; São mais caros e lentos que os testes unitários, pois envolvem múltiplos componentes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Depuração Moderada:&lt;/strong&gt; Identificar falhas pode ser mais complexo que nos testes unitários, mas geralmente mais simples que nos E2E.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursos:&lt;/strong&gt; Podem exigir mais recursos de setup (ex: um banco de dados de teste) do que os unitários.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd8Za3XcAA-I4i%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGsd8Za3XcAA-I4i%3Fformat%3Djpg%26name%3D4096x4096" alt="Custo Teste de Integração" width="2090" height="1689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Por Que o Formato de Pirâmide? 🔺
&lt;/h2&gt;

&lt;p&gt;O formato visual da pirâmide não é um acaso. Ele ilustra a &lt;strong&gt;proporção ideal&lt;/strong&gt; de cada tipo de teste em um sistema saudável e com manutenção sustentável:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base Larga (Muitos Testes Unitários):&lt;/strong&gt; São rápidos, baratos e isolam falhas eficientemente. Constituem a maior parte da sua suíte de testes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meio (Menos Testes de Integração):&lt;/strong&gt; Verificam as interações chave sem o custo dos E2E.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topo Estreito (Poucos Testes E2E):&lt;/strong&gt; Cobrem os fluxos críticos do usuário, mas são usados com moderação devido ao seu alto custo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seguir essa proporção ajuda a obter &lt;strong&gt;feedback rápido&lt;/strong&gt; (a maioria dos testes são rápidos), &lt;strong&gt;custos de manutenção controlados&lt;/strong&gt; e uma &lt;strong&gt;cobertura de risco eficaz&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pontos de Atenção e Nuances 📝
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contexto é Rei:&lt;/strong&gt; Os exemplos e proporções são um guia, não uma regra absoluta. Adapte a estratégia ao seu produto e contexto. Um teste E2E para uma API é diferente de um para uma aplicação web full-stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integração no Frontend:&lt;/strong&gt; Testes de integração não são exclusivos do backend! No frontend, eles podem verificar a interação entre componentes da UI, por exemplo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estratégia Balanceada:&lt;/strong&gt; O objetivo final é ter uma estratégia de testes balanceada, que maximize a confiança e minimize os custos e o tempo de feedback. ⚖️&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Concluindo...
&lt;/h2&gt;

&lt;p&gt;A Pirâmide de Testes é um modelo poderoso para guiar sua estratégia de testes, ajudando a construir aplicações mais robustas, confiáveis e fáceis de manter. Lembre-se que testes são um investimento na qualidade e sustentabilidade do seu software!&lt;/p&gt;

&lt;p&gt;E você, como aplica a Pirâmide de Testes nos seus projetos? Quais são seus maiores desafios ou aprendizados? Compartilhe nos comentários abaixo! 👇&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Entendendo a Replicação de Banco de Dados: Uma Chave para Sistemas Robustos</title>
      <dc:creator>Stephanto</dc:creator>
      <pubDate>Wed, 21 May 2025 19:50:04 +0000</pubDate>
      <link>https://dev.to/stephanto/entendendo-a-replicacao-de-banco-de-dados-uma-chave-para-sistemas-robustos-5eem</link>
      <guid>https://dev.to/stephanto/entendendo-a-replicacao-de-banco-de-dados-uma-chave-para-sistemas-robustos-5eem</guid>
      <description>&lt;p&gt;Olá a todos! Estou aqui novamente para compartilhar mais do que aprendi esta semana, especificamente sobre o tema da replicação de dados. Este artigo fornecerá uma explicação resumida do que é e quais são os seus tipos. Vamos lá!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQFgd2N1JkEhBA%2Farticle-cover_image-shrink_600_2000%2Farticle-cover_image-shrink_600_2000%2F0%2F1677831225612%3Fe%3D2147483647%26v%3Dbeta%26t%3DWbZrCjZbw2Zq2UPMzEb18-Zca9BRHhooN6iCmC9ANmQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQFgd2N1JkEhBA%2Farticle-cover_image-shrink_600_2000%2Farticle-cover_image-shrink_600_2000%2F0%2F1677831225612%3Fe%3D2147483647%26v%3Dbeta%26t%3DWbZrCjZbw2Zq2UPMzEb18-Zca9BRHhooN6iCmC9ANmQ" alt="Replication" width="720" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Por Que a Replicação de Dados é Importante?
&lt;/h3&gt;

&lt;p&gt;Para entender a importância da replicação de dados, considere este cenário: Imagine que este é um servidor hospedado na minha casa. Se eu acidentalmente derramar café em cima do servidor/DB, o que acontece? Já era.&lt;/p&gt;

&lt;p&gt;Temos aqui um "Single point of failure".&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI--EzWYAAizPM%3Fformat%3Djpg%26name%3Dlarge" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI--EzWYAAizPM%3Fformat%3Djpg%26name%3Dlarge" alt="SPF" width="1398" height="811"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro ponto é que usuários de países diferentes têm tempos de resposta diferentes. Dependendo da localização, demora um tempo considerável para obter resposta da aplicação, o que pode prejudicar a experiência do usuário.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_GAhWgAA4rOX%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_GAhWgAA4rOX%3Fformat%3Djpg%26name%3D4096x4096" alt="Diferentes usuarios" width="3083" height="1623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então, a replicação pode servir para, caso algum servidor deixe de funcionar, aumentar a disponibilidade e diminuir a latência para diferentes localidades. Adicionamos mais DBs para poder garantir essas melhorias.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_MKDXcAE1MQC%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_MKDXcAE1MQC%3Fformat%3Djpg%26name%3D4096x4096" alt="Servidores" width="4096" height="2682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Porém, não sei se vocês notaram, mas surge um novo problema: Temos 3 bancos de dados em 3 lugares diferentes. Como garantir e manter a sincronização entre os 3 bancos de dados?&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_bCjXgAAuHsO%3Fformat%3Djpg%26name%3Dlarge" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_bCjXgAAuHsO%3Fformat%3Djpg%26name%3Dlarge" alt="Databases" width="1506" height="1530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Abordagens para Consistência de Dados
&lt;/h3&gt;

&lt;p&gt;Ao lidar com múltiplos bancos de dados, garantir a consistência dos dados é crucial. Existem duas abordagens principais:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Replicação Síncrona
&lt;/h4&gt;

&lt;p&gt;A primeira abordagem é a Síncrona. Ela garante o dado mais recente (tendo uma consistência forte) através de fazer com que o usuário aguarde, se necessário, todo o processo de replicação para obter a resposta dele. O problema dessa abordagem é que ela gera uma certa lentidão.&lt;br&gt;
![Sincrona]&lt;a href="https://pbs.twimg.com/media/GpI_d8sWsAAYR5J?format=jpg&amp;amp;name=4096x4096" rel="noopener noreferrer"&gt;https://pbs.twimg.com/media/GpI_d8sWsAAYR5J?format=jpg&amp;amp;name=4096x4096&lt;/a&gt;)&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Replicação Assíncrona
&lt;/h4&gt;

&lt;p&gt;A outra abordagem é a Assíncrona. Com ela, o usuário não precisa esperar todo o processo de replicação (pois ele é feito em background), o que torna o acesso ao dado mais rápido. Seu problema é que não garante que a consistência seja 100%, e sim a chamada "consistência eventual".&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_kpoWYAAoGhs%3Fformat%3Djpg%26name%3D4096x4096" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_kpoWYAAoGhs%3Fformat%3Djpg%26name%3D4096x4096" alt="Assincrona" width="2585" height="2921"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Métodos de Replicação
&lt;/h3&gt;

&lt;p&gt;Agora que vocês sabem as abordagens, vamos para os métodos de replicação. Vou apresentar 3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-leader replication&lt;/li&gt;
&lt;li&gt;Multi-leader replication&lt;/li&gt;
&lt;li&gt;Leaderless replication&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  1. Single-Leader Replication
&lt;/h4&gt;

&lt;p&gt;No Single-leader replication, apenas um banco recebe os writes e replica para os outros que apenas recebem reads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prós&lt;/strong&gt;: É bom pois não tem conflitos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contras&lt;/strong&gt;: Porém, tem um Throughput baixo e possui Single point of failure pois só um escreve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caso de Uso&lt;/strong&gt;: É comum de ser usado em aplicações financeiras.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_tTgWMAAJdUR%3Fformat%3Djpg%26name%3D4096x4096" alt="SLR" width="4096" height="2375"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Multi-Leader Replication
&lt;/h4&gt;

&lt;p&gt;Já o Multi-leader replication, a replicação de dados ocorre entre os DBs, ou seja, todos são líderes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prós&lt;/strong&gt;: Possui um alto throughput para escritas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contras&lt;/strong&gt;: O que pode gerar conflitos nas escritas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caso de Uso&lt;/strong&gt;: É usado para grandes áreas geográficas.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_vy9XgAA3KWe%3Fformat%3Djpg%26name%3D4096x4096" alt="MLR" width="4096" height="2561"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Leaderless Replication
&lt;/h4&gt;

&lt;p&gt;Por fim, o Leaderless replication funciona na forma de "Quorum" para lidas e escritas. Para simplificar, veja a imagem abaixo: Temos 4 nós, se um user quiser ler/escrever, será lido um pouco a mais da metade do número de nós para assim ter a resposta.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prós&lt;/strong&gt;: Isso é feito para garantir a consistência, o que gera uma alta disponibilidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contras&lt;/strong&gt;: Porém, acaba causando conflitos de escrita e gera latência na leitura.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caso de Uso&lt;/strong&gt;: É usado em sistemas que priorizam alta disponibilidade e tolerância a falhas, como sistemas de mensagens.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGpI_2uLW8AAvNeu%3Fformat%3Djpg%26name%3D4096x4096" alt="Leaderless" width="3249" height="3429"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;Bom, é isso. Espero que minha explicação tenha sido clara. Caso queiram, eu posso aprofundar mais em consistência e como lidar com conflitos de escrita. Fiquem livres para adicionar o que acharem relevante!&lt;/p&gt;

&lt;p&gt;Obrigado por lerem até aqui!&lt;/p&gt;

&lt;p&gt;Recomendo se aprofundarem em cada um deles, dei apenas uma visão geral e superficial para compreensão geral. Alguns materiais para leitura que dão uma complementada legal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/what-is-replication-in-distributed-system/" rel="noopener noreferrer"&gt;What is Replication in Distributed System?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.bytebytego.com/p/how-to-choose-a-replication-strategy" rel="noopener noreferrer"&gt;How to Choose a Replication Strategy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>devops</category>
    </item>
    <item>
      <title>COMO ESCALAR UM SISTEMA PARA 1 MILHÃO DE USUÁRIOS?</title>
      <dc:creator>Stephanto</dc:creator>
      <pubDate>Wed, 23 Apr 2025 15:05:18 +0000</pubDate>
      <link>https://dev.to/stephanto/como-escalar-um-sistema-para-1-milhao-de-usuarios-4a4m</link>
      <guid>https://dev.to/stephanto/como-escalar-um-sistema-para-1-milhao-de-usuarios-4a4m</guid>
      <description>&lt;p&gt;Escalar um sistema para suportar milhões de usuários é um desafio significativo. A complexidade aumenta com o aumento da carga de dados e usuários, demandando uma arquitetura robusta. Neste artigo, exploraremos como escalar um sistema para lidar com 1 milhão de usuários, utilizando boas práticas e abordagens como balanceamento de carga, caches, e sharding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkohp1g342m9zku22i20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkohp1g342m9zku22i20.png" alt="Image description" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O fluxo comum de um usuário ao acessar um site é: Acessar o o site pela URL, o DNS traduzir o endereço, a requisição chegar no servidor e devolver o conteúdo para o usuário&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxb76qt5pu73d70wu5xb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxb76qt5pu73d70wu5xb.png" alt="Image description" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se começarmos a ter usuários acessando nosso site e quisermos guardar seus registros e/ou ter um backend que queremos armazenar dados, temos que ter um database que vai salvar e resgatar esses dados&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrnpgd8hy1gzbd2jvyxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrnpgd8hy1gzbd2jvyxt.png" alt="Image description" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Porém, como temos apenas 1 servidor, a medida que o número de usuários aumenta, pode gerar delay e timeout para alguns usuários, para isso adicionamos o loadbalancer que vai cuidar de encaminhar os usuários para os diferente servidores para não sobrecarregar&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0zvl05k1kjnbryfnfnq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0zvl05k1kjnbryfnfnq.png" alt="Image description" width="800" height="784"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora, como teremos mais de um banco de dados (por conta do aumento de servidores), precisamos garantir a consistência dos dados. Podemos utilizar o método de Master/Slave, que somente 1 database recebe as escritas, replica para os outros e eles apenas leem os registros&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquizy34gchqw3sbtmg5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquizy34gchqw3sbtmg5i.png" alt="Image description" width="800" height="972"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos dar uma olhada em como ficou nosso sistema até agora então, está bom mas ainda podemos melhorar bastante a performance&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jphu1h0b6clnhjr2pgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jphu1h0b6clnhjr2pgw.png" alt="Image description" width="800" height="1009"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos adicionar um cache para dados frequentemente acessados. Assim, melhora a velocidade e poupa acessos ao banco de dados pela memória cache ser mais rápida&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwxwxchwbtdowx9sdtkk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwxwxchwbtdowx9sdtkk.png" alt="Image description" width="800" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos também adicionar um CDN. Um CDN é um servidor estrategicamente localizado em um lugar que seja mais perto do cliente, funciona semelhante a um cache&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusbuyfqpdwz0bs74yx82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusbuyfqpdwz0bs74yx82.png" alt="Image description" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com essas adições nosso sistema esta desta forma até agora:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawc9lgdns9y0nswor2h9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawc9lgdns9y0nswor2h9.png" alt="Image description" width="800" height="915"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, mas como escalamos ainda mais? Podemos mover uma parte do sistema para stateless, por exemplo, tirar o estado do usuário do servidor e adicionar em um NoSQL. No exemplo abaixo é como seria o acesso do usuário sem stateless, sua sessão e foto de perfil ficam apenas em 1 server&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmefp9o5okaqa1l0j5ofs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmefp9o5okaqa1l0j5ofs.png" alt="Image description" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Já com stateless, adicionamos um shared storage para adicionar a sessão e a foto de perfil do usuário, para manter uma boa experiência de usuário (se o loadbalancer jogar ele pra outro servidor, ele não ser deslogado ou coisa do tipo)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpjnd8kmbpep99ihkmjh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpjnd8kmbpep99ihkmjh.png" alt="Image description" width="800" height="920"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com essa adição, nosso sistema está ficando cada vez mais bonito e escalável&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlnczwnsjqll9500vue4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlnczwnsjqll9500vue4.png" alt="Image description" width="800" height="743"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ta bom, mas e se seu sistema quer internacionalizar? Para isso, vamos ter outro datacenter em outro país, e com isso, adicionamos um outro loadbalancer mas com algoritmo de georoute nele&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomzb3ftkygr7vaymvuzl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomzb3ftkygr7vaymvuzl.png" alt="Image description" width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uma boa prática (algumas vezes) é desacoplar alguma função frequente que ser servidor faz para aumentar o desempenho e diminuir o overload em um macro-serviço. Exemplo, podemos fazer um sistema separado para processamento de imagens no nosso servidor usando sistema de filas. Com esse sistema de filas, caso algum servidor caia, não é perdido a requisição, além de, como dito anteriormente, diminuir o overload&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttj5lmxj6a8ime9ju4pe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttj5lmxj6a8ime9ju4pe.png" alt="Image description" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com isso, nosso sistema fica dessa forma:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawmimvw1izozpssnuert.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawmimvw1izozpssnuert.png" alt="Image description" width="800" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por fim, o que podemos fazer é diminuir a sobrecarga do banco de dados. As bases de dados estão apenas com redundância até agora, com os mesmos tipos de dados em todos eles. Com isso, podemos usar um método chamado sharding.&lt;br&gt;
Sharding é, de forma simplifcada, usar um algoritmo para dividir a alocação de um registro em bases de dados diferentes. O exemplo abaixo vai elucidar melhor.&lt;br&gt;
Vou pegar o id do usuário e fazer módulo 4, o resultado vai fazer com que ele seja salvo em um DB especifico&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxat4vlbwy0cxb7ss5m98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxat4vlbwy0cxb7ss5m98.png" alt="Image description" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essa é uma visão de como ficaria cada um dos bancos de dados após o sharding:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmd310z9n5kt88ahd43ry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmd310z9n5kt88ahd43ry.png" alt="Image description" width="800" height="814"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora juntando tudo isso que temos, voltamos para a imagem inicial do artigo. Vocês tem um sistema escalável para bem mais que 1 milhão de usuários!&lt;/p&gt;

&lt;p&gt;Espero que tenham compreendido de forma simples o funcionamento disso. Novamente, aconselho aprofundar no assunto!&lt;/p&gt;

&lt;p&gt;Obrigado por ler até aqui!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6enb6vgw98ddq5b4tsay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6enb6vgw98ddq5b4tsay.png" alt="Image description" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
