{"id":1719,"date":"2026-09-23T12:42:25","date_gmt":"2026-09-23T15:42:25","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/?p=1719"},"modified":"2026-09-23T12:42:25","modified_gmt":"2026-09-23T15:42:25","slug":"valkey-em-cluster-primarios-replicas-failover","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/es\/2026\/09\/valkey-em-cluster-primarios-replicas-failover\/","title":{"rendered":"Valkey en cl\u00faster: 3 principales, 3 r\u00e9plicas y failover probado"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/09\/valkey-cluster-failover-v1.webp\" alt=\"Mascote LinuxPro encaixa um cubo de luz (hash slot) num servidor de um cluster Valkey de tr\u00eas racks, com o logo do Valkey na parede e o cachorro caramelo deitado ao lado\" width=\"1486\" height=\"856\" \/><\/p>\n<p>Um Valkey sozinho aguenta muita coisa, mas quando cai leva junto o cache, as sess\u00f5es e as filas da aplica\u00e7\u00e3o. O modo cluster resolve os dois problemas de uma vez: divide os dados entre v\u00e1rios prim\u00e1rios e deixa uma r\u00e9plica pronta para assumir cada peda\u00e7o quando um servidor morre. Neste guia montamos um cluster com 3 prim\u00e1rios e 3 r\u00e9plicas, derrubamos um prim\u00e1rio de prop\u00f3sito e medimos quanto tempo as escritas ficaram paradas. Tamb\u00e9m adicionamos e removemos n\u00f3s, ligamos persist\u00eancia, ACL e TLS, configuramos o servi\u00e7o com systemd e ligamos o Valkey Admin no cluster. Tudo foi executado de verdade num laborat\u00f3rio em Docker com o Valkey 9.1.2, e as sa\u00eddas mostradas abaixo sa\u00edram desse teste.<\/p>\n<h2>O que \u00e9 o Valkey<\/h2>\n<p>Em mar\u00e7o de 2024 a Redis Inc. trocou a licen\u00e7a do Redis, que era BSD, por licen\u00e7as <em>source available<\/em>. No dia 28 daquele m\u00eas a <a href=\"https:\/\/www.linuxfoundation.org\/press\/linux-foundation-launches-open-source-valkey-community\">Linux Foundation anunciou o Valkey<\/a>, um fork criado por mantenedores e colaboradores antigos do projeto a partir do Redis 7.2.4. O Valkey continua com a <a href=\"https:\/\/github.com\/valkey-io\/valkey\/blob\/unstable\/COPYING\">licen\u00e7a BSD de 3 cl\u00e1usulas<\/a> e tem governan\u00e7a aberta. AWS, Google Cloud, Oracle, Ericsson e Snap apoiaram o projeto desde o an\u00fancio. O protocolo continua o mesmo, ent\u00e3o clientes e ferramentas feitos para o Redis em geral funcionam sem altera\u00e7\u00e3o.<\/p>\n<p>Vers\u00f5es em 23\/09\/2026, conferidas nas <a href=\"https:\/\/github.com\/valkey-io\/valkey\/releases\/tag\/9.1.2\">releases do GitHub<\/a> e na <a href=\"https:\/\/valkey.io\/download\/\">p\u00e1gina de download<\/a>:<\/p>\n<ul>\n<li><strong>9.1.2<\/strong> (31\/08\/2026): est\u00e1vel atual. \u00c9 uma release de seguran\u00e7a que corrige dois use-after-free (um deles no estado do interpretador Lua, explor\u00e1vel sem autentica\u00e7\u00e3o) e dezenas de bugs, v\u00e1rios deles de cluster e de migra\u00e7\u00e3o de slots. Atualize.<\/li>\n<li><strong>9.0.6<\/strong> e <strong>8.1.10<\/strong> (01\/09\/2026): \u00faltimas corre\u00e7\u00f5es das s\u00e9ries anteriores que ainda recebem suporte.<\/li>\n<li><strong>9.2.0-rc1<\/strong> (16\/09\/2026): release candidate. N\u00e3o use em produ\u00e7\u00e3o.<\/li>\n<\/ul>\n<p>Novidades das duas \u00faltimas vers\u00f5es maiores que mudam a opera\u00e7\u00e3o de um cluster, segundo os an\u00fancios oficiais do <a href=\"https:\/\/valkey.io\/blog\/introducing-valkey-9\/\">Valkey 9.0<\/a> e do <a href=\"https:\/\/valkey.io\/blog\/valkey-9-1-delivers-improvements-in-security-performance-and-more\/\">Valkey 9.1<\/a>:<\/p>\n<ul>\n<li><strong>Atomic Slot Migration (9.0):<\/strong> o resharding passa a mover o slot inteiro, e n\u00e3o mais chave por chave. O n\u00f3 de origem mant\u00e9m todos os dados at\u00e9 o fim da migra\u00e7\u00e3o, o que evita os redirecionamentos intermedi\u00e1rios e o travamento com chaves muito grandes. O comando \u00e9 <code>CLUSTER MIGRATESLOTS<\/code>, que usamos mais abaixo.<\/li>\n<li><strong>Bancos numerados no modo cluster (9.0):<\/strong> <code>SELECT 1<\/code> passou a funcionar em cluster. No Redis e nas vers\u00f5es anteriores do Valkey, o cluster s\u00f3 aceitava o db 0.<\/li>\n<li><strong>Expira\u00e7\u00e3o por campo de hash (9.0):<\/strong> comandos como <code>HEXPIRE<\/code>, <code>HSETEX<\/code> e <code>HGETEX<\/code>.<\/li>\n<li><strong>Clusters grandes (9.0):<\/strong> o projeto informa escala de at\u00e9 2.000 n\u00f3s e mais de 1 bilh\u00e3o de requisi\u00e7\u00f5es por segundo.<\/li>\n<li><strong>ACL por banco de dados (9.1):<\/strong> <code>ACL SETUSER app ... db=0,1<\/code> restringe um usu\u00e1rio a alguns bancos.<\/li>\n<li><strong>Lua como m\u00f3dulo (9.1):<\/strong> o Lua saiu do n\u00facleo e pode ser desligado quando n\u00e3o \u00e9 usado.<\/li>\n<li><strong>TLS (9.1):<\/strong> recarga autom\u00e1tica dos certificados, data de expira\u00e7\u00e3o no <code>INFO<\/code> e autentica\u00e7\u00e3o por SAN URI.<\/li>\n<li><strong>Log em JSON (9.1):<\/strong> <code>log-format json<\/code> no <code>valkey.conf<\/code>.<\/li>\n<li><strong>Mem\u00f3ria e desempenho (9.1):<\/strong> strings pequenas usam at\u00e9 20% menos mem\u00f3ria, h\u00e1 um novo modelo de I\/O threads e os comandos novos <code>HGETDEL<\/code> e <code>MSETEX<\/code>.<\/li>\n<\/ul>\n<h2>Como o cluster funciona<\/h2>\n<p>O Valkey Cluster divide o espa\u00e7o de chaves em <strong>16384 hash slots<\/strong>. O slot de uma chave \u00e9 <code>CRC16(chave) mod 16384<\/code>, e cada prim\u00e1rio \u00e9 dono de uma faixa de slots. Com 3 prim\u00e1rios, a divis\u00e3o padr\u00e3o fica assim: 0\u20135460, 5461\u201310922 e 10923\u201316383. Cada prim\u00e1rio tem uma ou mais <strong>r\u00e9plicas<\/strong>, que recebem os dados por replica\u00e7\u00e3o ass\u00edncrona e ficam prontas para assumir.<\/p>\n<ul>\n<li><strong>Barramento do cluster (cluster bus):<\/strong> al\u00e9m da porta dos clientes, cada n\u00f3 abre uma segunda porta TCP, que por padr\u00e3o \u00e9 a porta do cliente mais 10000 (16379). Por ela os n\u00f3s trocam <em>gossip<\/em> bin\u00e1rio, ou seja, PING\/PONG com o estado de cada n\u00f3, o mapa de slots e os votos de failover.<\/li>\n<li><strong>Detec\u00e7\u00e3o de falha:<\/strong> se um n\u00f3 fica sem responder por mais de <code>cluster-node-timeout<\/code>, quem percebe o marca como <code>PFAIL<\/code> (falha prov\u00e1vel). Quando a maioria dos prim\u00e1rios relata o mesmo, ele vira <code>FAIL<\/code> e essa informa\u00e7\u00e3o se espalha pelo cluster.<\/li>\n<li><strong>Failover autom\u00e1tico:<\/strong> a r\u00e9plica do prim\u00e1rio em <code>FAIL<\/code> pede votos aos outros prim\u00e1rios. Com a maioria dos votos, ela se promove, incrementa o <em>config epoch<\/em> e passa a servir os slots do prim\u00e1rio que caiu.<\/li>\n<li><strong>MOVED:<\/strong> quando o cliente pede uma chave a um n\u00f3 que n\u00e3o \u00e9 dono do slot, recebe <code>MOVED &lt;slot&gt; &lt;ip:porta&gt;<\/code>. Um cliente <em>cluster-aware<\/em> atualiza o mapa de slots e vai direto ao n\u00f3 certo.<\/li>\n<li><strong>ASK:<\/strong> aparece enquanto um slot est\u00e1 migrando e a chave j\u00e1 foi para o destino. O redirecionamento vale s\u00f3 para aquela requisi\u00e7\u00e3o, e o cliente n\u00e3o atualiza o mapa.<\/li>\n<li><strong>Hash tags:<\/strong> quando a chave tem <code>{...}<\/code>, s\u00f3 o trecho entre chaves entra no c\u00e1lculo do slot. <code>{pedido:42}:itens<\/code> e <code>{pedido:42}:total<\/code> caem no mesmo slot e podem ser usadas juntas em <code>MSET<\/code>, transa\u00e7\u00f5es e scripts.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/09\/valkey-cluster-topologia.webp\" alt=\"Topologia de um cluster Valkey com tr\u00eas shards, cada um com um prim\u00e1rio e uma r\u00e9plica, ligados pelo barramento do cluster na porta 16379\" width=\"1200\" height=\"800\" loading=\"lazy\" \/><\/p>\n<h2>Cluster ou Sentinel?<\/h2>\n<p>As duas op\u00e7\u00f5es entregam alta disponibilidade, mas resolvem problemas diferentes:<\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Sentinel<\/th>\n<th>Cluster<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Dados<\/td>\n<td>Um \u00fanico prim\u00e1rio com o dataset inteiro<\/td>\n<td>Dataset dividido entre v\u00e1rios prim\u00e1rios (sharding)<\/td>\n<\/tr>\n<tr>\n<td>Escala de escrita<\/td>\n<td>A de um servidor<\/td>\n<td>Cresce com o n\u00famero de prim\u00e1rios<\/td>\n<\/tr>\n<tr>\n<td>Failover<\/td>\n<td>Processos <code>valkey-sentinel<\/code> separados votam e promovem a r\u00e9plica<\/td>\n<td>Os pr\u00f3prios n\u00f3s votam pelo barramento<\/td>\n<\/tr>\n<tr>\n<td>Cliente<\/td>\n<td>Pergunta ao Sentinel quem \u00e9 o prim\u00e1rio<\/td>\n<td>Precisa entender <code>MOVED<\/code>\/<code>ASK<\/code> (modo cluster)<\/td>\n<\/tr>\n<tr>\n<td>Comandos multi-chave<\/td>\n<td>Livres<\/td>\n<td>S\u00f3 com chaves no mesmo slot (hash tags)<\/td>\n<\/tr>\n<tr>\n<td>Bancos numerados<\/td>\n<td>Sim<\/td>\n<td>Sim a partir do Valkey 9.0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Se o dataset cabe num servidor e a aplica\u00e7\u00e3o depende de muitos comandos multi-chave, o <a href=\"https:\/\/valkey.io\/topics\/sentinel\/\">Sentinel<\/a> \u00e9 mais simples. Se voc\u00ea precisa de mais mem\u00f3ria ou de mais vaz\u00e3o de escrita do que uma m\u00e1quina entrega, o caminho \u00e9 o cluster.<\/p>\n<h2>Requisitos e portas<\/h2>\n<ul>\n<li><strong>M\u00ednimo de 3 prim\u00e1rios.<\/strong> A <a href=\"https:\/\/valkey.io\/topics\/cluster-tutorial\/\">documenta\u00e7\u00e3o<\/a> recomenda 6 n\u00f3s (3 prim\u00e1rios e 3 r\u00e9plicas), e cada prim\u00e1rio deve ficar numa m\u00e1quina diferente da sua r\u00e9plica.<\/li>\n<li><strong>TCP 6379<\/strong> (clientes e replica\u00e7\u00e3o) e <strong>TCP 16379<\/strong> (barramento) abertos entre todos os n\u00f3s. Os clientes precisam alcan\u00e7ar a 6379 de <em>todos<\/em> os n\u00f3s, e n\u00e3o s\u00f3 de um.<\/li>\n<li><strong>Sem NAT nem remapeamento de portas.<\/strong> O cluster anuncia o pr\u00f3prio IP e a pr\u00f3pria porta, e o Docker com <code>-p 7000:6379<\/code> quebra os redirecionamentos. No laborat\u00f3rio abaixo usamos uma rede bridge com IP fixo por cont\u00eainer e sem publicar portas. Em Kubernetes, use <code>cluster-announce-ip<\/code>\/<code>cluster-announce-hostname<\/code> ou o <a href=\"https:\/\/valkey.io\/blog\/valkey-helm-chart\/\">Helm chart oficial<\/a>.<\/li>\n<li><strong>O barramento n\u00e3o autentica mensagens.<\/strong> Pela documenta\u00e7\u00e3o, a porta 16379 aceita o que chegar. Proteja-a com firewall liberando s\u00f3 os IPs dos n\u00f3s, ou com mTLS (<code>tls-cluster yes<\/code>).<\/li>\n<\/ul>\n<h2>Laborat\u00f3rio com Docker: 6 n\u00f3s em 5 minutos<\/h2>\n<p>O laborat\u00f3rio usa a imagem oficial <code>valkey\/valkey:9.1.2<\/code> numa rede bridge dedicada, e cada n\u00f3 recebe um IP fixo. Se precisar de uma revis\u00e3o sobre cont\u00eaineres, veja <a href=\"\/2026\/09\/a-historia-do-docker\/\">a hist\u00f3ria do Docker<\/a>. Comece pelo arquivo de configura\u00e7\u00e3o que os seis n\u00f3s v\u00e3o compartilhar:<\/p>\n<pre><code class=\"language-bash\">mkdir -p ~\/valkey-lab &amp;&amp; cd ~\/valkey-lab\ncat &gt; valkey.conf &lt;&lt;'EOF'\nport 6379\nbind 0.0.0.0\nprotected-mode no\ncluster-enabled yes\ncluster-config-file nodes.conf\ncluster-node-timeout 5000\nappendonly yes\nappendfsync everysec\nsave 900 1 300 10\ndir \/data\nEOF\n\ndocker network create --subnet 10.77.77.0\/24 valkey-net\n\nfor i in 1 2 3 4 5 6; do\n  docker run -d --name valkey-$i --hostname valkey-$i \\\n    --network valkey-net --ip 10.77.77.1$i \\\n    -v \"$PWD\/valkey.conf:\/usr\/local\/etc\/valkey\/valkey.conf:ro\" \\\n    valkey\/valkey:9.1.2 valkey-server \/usr\/local\/etc\/valkey\/valkey.conf\ndone\n\n# cont\u00eainer \"cliente\" na mesma rede, para rodar valkey-cli e testes\ndocker run -d --name valkey-client --network valkey-net --ip 10.77.77.30 \\\n  valkey\/valkey:9.1.2 sleep infinity<\/code><\/pre>\n<p>O <code>protected-mode no<\/code> sem senha serve s\u00f3 para o laborat\u00f3rio isolado. A se\u00e7\u00e3o de seguran\u00e7a mostra o que muda em produ\u00e7\u00e3o. Antes de criar o cluster, um n\u00f3 rec\u00e9m-iniciado recusa escritas:<\/p>\n<pre><code class=\"language-bash\">$ docker exec valkey-1 valkey-cli set foo bar\nCLUSTERDOWN Hash slot not served<\/code><\/pre>\n<p>Crie o cluster com uma r\u00e9plica por prim\u00e1rio:<\/p>\n<pre><code class=\"language-bash\">docker exec valkey-client valkey-cli --cluster create \\\n  10.77.77.11:6379 10.77.77.12:6379 10.77.77.13:6379 \\\n  10.77.77.14:6379 10.77.77.15:6379 10.77.77.16:6379 \\\n  --cluster-replicas 1 --cluster-yes<\/code><\/pre>\n<pre><code class=\"language-text\">&gt;&gt;&gt; Performing hash slots allocation on 6 node(s)...\nPrimary[0] -&gt; Slots 0 - 5460\nPrimary[1] -&gt; Slots 5461 - 10922\nPrimary[2] -&gt; Slots 10923 - 16383\nAdding replica 10.77.77.15:6379 to 10.77.77.11:6379\nAdding replica 10.77.77.16:6379 to 10.77.77.12:6379\nAdding replica 10.77.77.14:6379 to 10.77.77.13:6379\n...\n[OK] All nodes agree about slots configuration.\n&gt;&gt;&gt; Check for open slots...\n&gt;&gt;&gt; Check slots coverage...\n[OK] All 16384 slots covered.<\/code><\/pre>\n<h3>CLUSTER INFO e CLUSTER NODES<\/h3>\n<pre><code class=\"language-bash\">$ docker exec valkey-client valkey-cli -h 10.77.77.11 cluster info | head -12\ncluster_state:ok\ncluster_slots_assigned:16384\ncluster_slots_ok:16384\ncluster_slots_pfail:0\ncluster_slots_fail:0\ncluster_nodes_pfail:0\ncluster_nodes_fail:0\ncluster_voting_nodes_pfail:0\ncluster_voting_nodes_fail:0\ncluster_known_nodes:6\ncluster_size:3\ncluster_current_epoch:6\n\n$ docker exec valkey-client valkey-cli -h 10.77.77.11 cluster nodes\n63fa7320... 10.77.77.12:6379@16379 master - 0 1790176949000 2 connected 5461-10922\n6e304101... 10.77.77.14:6379@16379 slave 5eaf881d... 0 1790176949520 3 connected\n4bc5ee75... 10.77.77.15:6379@16379 slave accd0471... 0 1790176949000 1 connected\naccd0471... 10.77.77.11:6379@16379 myself,master - 0 0 1 connected 0-5460\n57d5706c... 10.77.77.16:6379@16379 slave 63fa7320... 0 1790176948000 2 connected\n5eaf881d... 10.77.77.13:6379@16379 master - 0 1790176948818 3 connected 10923-16383<\/code><\/pre>\n<p>Em cada linha de <code>CLUSTER NODES<\/code> aparecem o ID do n\u00f3, <code>ip:porta@porta-do-barramento<\/code>, o papel, o prim\u00e1rio que ele replica (no caso das r\u00e9plicas), o <em>config epoch<\/em> e as faixas de slots. Os IDs foram encurtados aqui. O <code>valkey-cli --cluster check 10.77.77.11:6379<\/code> mostra a mesma informa\u00e7\u00e3o num formato mais f\u00e1cil de ler e avisa sobre slots abertos ou descobertos.<\/p>\n<h2>Testando: MOVED, -c, CROSSSLOT e hash tags<\/h2>\n<pre><code class=\"language-bash\">$ C=\"docker exec valkey-client valkey-cli\"\n\n$ $C -h 10.77.77.11 set usuario:1000 nilton\nMOVED 7319 10.77.77.12:6379\n\n$ $C -h 10.77.77.11 cluster keyslot usuario:1000\n(integer) 7319\n\n$ $C -c -h 10.77.77.11 set usuario:1000 nilton     # -c segue o redirecionamento\nOK\n$ $C -c -h 10.77.77.11 get usuario:1000\n\"nilton\"\n\n$ $C -c -h 10.77.77.11 mset a 1 b 2\nCROSSSLOT Keys in request don't hash to the same slot\n\n$ $C -h 10.77.77.11 cluster keyslot '{pedido:42}:itens'\n(integer) 2873\n$ $C -h 10.77.77.11 cluster keyslot '{pedido:42}:total'\n(integer) 2873\n$ $C -c -h 10.77.77.11 mset '{pedido:42}:itens' 3 '{pedido:42}:total' 99.90\nOK<\/code><\/pre>\n<p>O <code>-c<\/code> n\u00e3o resolve o <code>CROSSSLOT<\/code>, porque o comando precisa rodar inteiro num \u00fanico n\u00f3. Para carregar dados de teste, o <code>valkey-benchmark<\/code> tem modo cluster:<\/p>\n<pre><code class=\"language-bash\">docker exec valkey-client valkey-benchmark -h 10.77.77.11 --cluster \\\n  -t set,get -n 100000 -r 100000 -q\n\nfor i in 1 2 3; do docker exec valkey-$i valkey-cli dbsize; done\n# 34705 \/ 32366 \/ 32931 chaves: distribui\u00e7\u00e3o equilibrada entre os shards<\/code><\/pre>\n<h2>Failover na pr\u00e1tica: derrubando um prim\u00e1rio<\/h2>\n<p>Para medir o failover, um script no cont\u00eainer cliente grava a chave <code>conta:1<\/code> a cada 100 ms. A chave fica no slot 3844, que pertence ao prim\u00e1rio <code>10.77.77.11<\/code>. O script usa <code>valkey-cli -c<\/code> com timeout de 0,5 s por tentativa e anota quando a primeira escrita falha e quando as escritas voltam:<\/p>\n<pre><code class=\"language-bash\">cat &gt; failover.sh &lt;&lt;'EOF'\n#!\/bin\/bash\n# Grava conta:1 (slot 3844) a cada 100 ms e mede quanto tempo as escritas falham.\nms() { date +%s%3N; }\nfalhou=0; n=0\nwhile :; do\n  n=$((n+1))\n  r=$(timeout 0.5 valkey-cli -c -h 10.77.77.12 set conta:1 \"$n\" 2&gt;&amp;1)\n  if [ \"$r\" != \"OK\" ]; then\n    [ \"$falhou\" = 0 ] &amp;&amp; falhou=$(ms) &amp;&amp; echo \"$(date +%T.%3N) primeira falha: ${r:-timeout}\"\n  elif [ \"$falhou\" != 0 ]; then\n    echo \"$(date +%T.%3N) escrita voltou; indisponivel por $(( $(ms) - falhou )) ms\"; exit 0\n  fi\n  sleep 0.1\ndone\nEOF\nchmod +x failover.sh\ndocker cp failover.sh valkey-client:\/failover.sh\ndocker exec -d valkey-client bash -c '\/failover.sh &gt; \/failover.log 2&gt;&amp;1'\nsleep 2; date -u +%T.%3N; docker kill valkey-1     # derruba o prim\u00e1rio sem aviso\nsleep 15; docker exec valkey-client cat \/failover.log<\/code><\/pre>\n<p>Resultado com <code>cluster-node-timeout 5000<\/code>. O <code>docker kill<\/code> foi \u00e0s 15:23:07.013 (UTC):<\/p>\n<pre><code class=\"language-text\">15:23:07.589 primeira falha: timeout\n15:23:13.216 escrita voltou; indisponivel por 5628 ms<\/code><\/pre>\n<p>O log da r\u00e9plica <code>valkey-5<\/code> mostra a sequ\u00eancia:<\/p>\n<pre><code class=\"language-text\">15:23:13.076 * FAIL message received from 63fa7320... (10.77.77.12:6379) about accd0471... (10.77.77.11:6379)\n15:23:13.076 # Cluster state changed: fail\n15:23:13.076 * This is the best ranked replica and can initiate the election immediately.\n15:23:13.076 * Starting a failover election for epoch 7, node config epoch is 1\n15:23:13.079 * Failover election won: I'm the new primary.\n15:23:13.079 * configEpoch set to 7 after successful failover<\/code><\/pre>\n<p>Entre a morte do prim\u00e1rio e a volta das escritas passaram <strong>cerca de 6,2 s<\/strong>. Quase todo esse tempo foi o <code>cluster-node-timeout<\/code> (5 s) somado \u00e0 propaga\u00e7\u00e3o do <code>FAIL<\/code> pelo gossip. A elei\u00e7\u00e3o levou 3 ms. Repetimos o teste com o timeout em 2000 ms (<code>CONFIG SET cluster-node-timeout 2000<\/code> em todos os n\u00f3s), derrubando o novo prim\u00e1rio. O <code>FAIL<\/code> saiu 2,99 s depois do kill e as escritas voltaram em <strong>cerca de 3,1 s<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/09\/valkey-cluster-failover-medido.webp\" alt=\"Linha do tempo do failover medido no laborat\u00f3rio com cluster-node-timeout de 5000 e 2000 ms\" width=\"1200\" height=\"640\" loading=\"lazy\" \/><\/p>\n<p>Um timeout menor n\u00e3o \u00e9 de gra\u00e7a. Uma pausa longa de rede ou de disco, como um fork grande para o RDB, pode disparar um failover desnecess\u00e1rio. Entre 2 e 5 segundos \u00e9 uma faixa razo\u00e1vel em rede local, mas me\u00e7a no seu ambiente. Depois do failover, o prim\u00e1rio antigo volta como r\u00e9plica do n\u00f3 promovido:<\/p>\n<pre><code class=\"language-bash\">$ docker start valkey-1\n$ docker exec valkey-client valkey-cli -h 10.77.77.12 cluster nodes | grep -E '1[15]:'\naccd0471... 10.77.77.11:6379@16379 slave 4bc5ee75... 0 1790177013144 7 connected\n4bc5ee75... 10.77.77.15:6379@16379 master - 0 1790177012000 7 connected 0-5460<\/code><\/pre>\n<p>Para devolver o papel de prim\u00e1rio, sem perder escritas, rode <code>CLUSTER FAILOVER<\/code> <strong>na r\u00e9plica<\/strong>. O failover manual espera a r\u00e9plica alcan\u00e7ar o offset do prim\u00e1rio antes de trocar os pap\u00e9is. \u00c9 o procedimento certo para atualizar a vers\u00e3o n\u00f3 a n\u00f3:<\/p>\n<pre><code class=\"language-bash\">docker exec valkey-client valkey-cli -h 10.77.77.11 cluster failover\ndocker exec valkey-client valkey-cli -h 10.77.77.11 role | head -1   # master<\/code><\/pre>\n<h2>Adicionando n\u00f3s, rebalance e remo\u00e7\u00e3o<\/h2>\n<p>Suba dois n\u00f3s novos com a mesma configura\u00e7\u00e3o (<code>valkey-7<\/code> em 10.77.77.17 e <code>valkey-8<\/code> em 10.77.77.18). Um entra como prim\u00e1rio vazio e o outro como r\u00e9plica dele:<\/p>\n<pre><code class=\"language-bash\">C=\"docker exec valkey-client valkey-cli\"\n$C --cluster add-node 10.77.77.17:6379 10.77.77.11:6379\n$C --cluster add-node 10.77.77.18:6379 10.77.77.11:6379 --cluster-replica\n# sem --cluster-primaries-id, a r\u00e9plica \u00e9 associada ao prim\u00e1rio com menos r\u00e9plicas (o novo)<\/code><\/pre>\n<p>O prim\u00e1rio novo entra sem slots. O <code>rebalance<\/code> distribui os slots por igual, e <code>--cluster-use-empty-primaries<\/code> \u00e9 o que faz ele considerar os prim\u00e1rios vazios:<\/p>\n<pre><code class=\"language-bash\">$ time $C --cluster rebalance 10.77.77.11:6379 --cluster-use-empty-primaries\n&gt;&gt;&gt; Rebalancing across 4 nodes. Total weight = 4.00\nMoving 1366 slots from 10.77.77.12:6379 to 10.77.77.17:6379\nMoving 1365 slots from 10.77.77.13:6379 to 10.77.77.17:6379\nMoving 1365 slots from 10.77.77.11:6379 to 10.77.77.17:6379\nreal  0m6,472s\n\n$ $C --cluster info 10.77.77.11:6379\n10.77.77.11:6379 (accd0471...) -&gt; 26018 keys | 4096 slots | 1 replicas.\n10.77.77.17:6379 (7149edd5...) -&gt; 24991 keys | 4096 slots | 1 replicas.\n10.77.77.13:6379 (5eaf881d...) -&gt; 24782 keys | 4096 slots | 1 replicas.\n10.77.77.12:6379 (63fa7320...) -&gt; 24212 keys | 4096 slots | 1 replicas.\n[OK] 100003 keys in 4 primaries.<\/code><\/pre>\n<p>Para mover uma faixa espec\u00edfica existe o <code>--cluster reshard<\/code> (<code>--cluster-from<\/code>, <code>--cluster-to<\/code>, <code>--cluster-slots<\/code>). No Valkey 9 tamb\u00e9m d\u00e1 para usar a <a href=\"https:\/\/valkey.io\/blog\/atomic-slot-migration\/\">migra\u00e7\u00e3o at\u00f4mica<\/a> direto, e foi assim que esvaziamos o n\u00f3 17 antes de remov\u00ea-lo. O comando \u00e9 enviado ao n\u00f3 de <strong>origem<\/strong>, com uma faixa por destino:<\/p>\n<pre><code class=\"language-bash\">$ $C -h 10.77.77.17 cluster migrateslots \\\n    slotsrange 0 1364 node accd0471d25a3d53a1a66c41971d01adacdbbe70 \\\n    slotsrange 5461 6826 node 63fa7320b3a4524df08a5925ab94962b08b5c5e0 \\\n    slotsrange 10923 12287 node 5eaf881d4c3e5720ccf7cc369540e57ed00decfe\nOK\n$ $C -h 10.77.77.17 cluster getslotmigrations   # state: success em cada job<\/code><\/pre>\n<p>Detalhe observado no teste: depois de perder todos os slots, o n\u00f3 17 se reconfigurou sozinho como r\u00e9plica de outro prim\u00e1rio. \u00c9 a migra\u00e7\u00e3o de r\u00e9plicas (<code>cluster-allow-replica-migration<\/code>, ligada por padr\u00e3o). Com o n\u00f3 vazio, remova primeiro a r\u00e9plica e depois o antigo prim\u00e1rio:<\/p>\n<pre><code class=\"language-bash\">$C --cluster del-node 10.77.77.11:6379 &lt;id-do-valkey-8&gt;\n$C --cluster del-node 10.77.77.11:6379 &lt;id-do-valkey-7&gt;\n$C --cluster check 10.77.77.11:6379\n# [OK] 100003 keys in 3 primaries.  [OK] All 16384 slots covered.<\/code><\/pre>\n<p>Nenhuma chave se perdeu no vaiv\u00e9m: 100003 antes e 100003 depois. Para o <code>--cluster call<\/code>, que roda o mesmo comando em todos os n\u00f3s, veja a pegadinha da se\u00e7\u00e3o de troubleshooting.<\/p>\n<h2>Persist\u00eancia: RDB e AOF<\/h2>\n<p>No cluster, cada n\u00f3 persiste s\u00f3 os pr\u00f3prios slots. As op\u00e7\u00f5es s\u00e3o as mesmas do Valkey standalone (<a href=\"https:\/\/valkey.io\/topics\/persistence\/\">documenta\u00e7\u00e3o<\/a>):<\/p>\n<ul>\n<li><strong>RDB<\/strong> (<code>save 900 1 300 10<\/code>): snapshot peri\u00f3dico, compacto, bom para backup. Pode perder as escritas feitas desde o \u00faltimo snapshot.<\/li>\n<li><strong>AOF<\/strong> (<code>appendonly yes<\/code>, <code>appendfsync everysec<\/code>): registra cada escrita e perde no m\u00e1ximo cerca de 1 s. Desde o Redis 7 o AOF \u00e9 multiparte: um <code>base.rdb<\/code>, um <code>incr.aof<\/code> e um manifesto.<\/li>\n<\/ul>\n<pre><code class=\"language-bash\">$ docker exec valkey-1 ls \/data \/data\/appendonlydir\n\/data:\nappendonlydir  nodes.conf\n\/data\/appendonlydir:\nappendonly.aof.2.base.rdb  appendonly.aof.2.incr.aof  appendonly.aof.manifest\n\n$ docker restart valkey-1 valkey-2 valkey-3 valkey-4 valkey-5 valkey-6\n$ docker exec valkey-client valkey-cli --cluster info 10.77.77.11:6379 | tail -2\n[OK] 100003 keys in 3 primaries.<\/code><\/pre>\n<p>O <code>nodes.conf<\/code> n\u00e3o \u00e9 backup de dados. \u00c9 o estado do cluster (IDs, epochs, slots), escrito pelo pr\u00f3prio Valkey, e n\u00e3o deve ser editado \u00e0 m\u00e3o. Guarde junto do backup, mas n\u00e3o o copie para outro n\u00f3. Em cache puro d\u00e1 para desligar os dois (<code>save \"\"<\/code> e <code>appendonly no<\/code>). Nesse caso a r\u00e9plica \u00e9 a \u00fanica c\u00f3pia, e um n\u00f3 que reinicia volta vazio e sincroniza tudo de novo.<\/p>\n<h2>Seguran\u00e7a: protected-mode, senha, ACL e TLS<\/h2>\n<h3>protected-mode<\/h3>\n<p>Se o usu\u00e1rio <code>default<\/code> n\u00e3o tem senha e o <code>protected-mode<\/code> est\u00e1 ligado (padr\u00e3o), o Valkey s\u00f3 aceita conex\u00f5es pelo loopback. Um cliente remoto recebe:<\/p>\n<pre><code class=\"language-text\">DENIED Running in protected mode because protected mode is enabled and no password is set for the default user. In this mode connections are only accepted from the loopback interface. ...<\/code><\/pre>\n<p>A sa\u00edda n\u00e3o \u00e9 desligar a prote\u00e7\u00e3o. \u00c9 definir senha, ou usu\u00e1rios ACL, e manter o <code>bind<\/code> nos IPs internos.<\/p>\n<h3>Senha do cluster e autentica\u00e7\u00e3o entre r\u00e9plica e prim\u00e1rio<\/h3>\n<p>No cluster, as r\u00e9plicas tamb\u00e9m se autenticam no prim\u00e1rio, e por isso <code>requirepass<\/code> precisa andar junto com <code>primaryauth<\/code> (o antigo <code>masterauth<\/code>). No laborat\u00f3rio aplicamos as duas com <code>CONFIG SET<\/code> e reiniciamos uma r\u00e9plica. Como o arquivo montado era somente leitura, a configura\u00e7\u00e3o n\u00e3o persistiu, e a r\u00e9plica voltou sem <code>primaryauth<\/code>:<\/p>\n<pre><code class=\"language-text\">master_link_status:down\n# Unexpected reply to PSYNC from primary: -NOAUTH Authentication required.\n# PRIMARY aborted replication with an error: NOAUTH Authentication required.<\/code><\/pre>\n<p>Coloque as duas diretivas no <code>valkey.conf<\/code> de <strong>todos<\/strong> os n\u00f3s, e n\u00e3o s\u00f3 via <code>CONFIG SET<\/code>. Com senha, as ferramentas de cluster recebem <code>-a<\/code> (ou <code>--user<\/code>\/<code>--pass<\/code>):<\/p>\n<pre><code class=\"language-bash\">valkey-cli -a 'SenhaForte' --no-auth-warning --cluster check 10.77.77.11:6379<\/code><\/pre>\n<h3>ACL por aplica\u00e7\u00e3o<\/h3>\n<p>As ACLs n\u00e3o s\u00e3o replicadas pelo barramento. Crie o usu\u00e1rio em cada n\u00f3, ou mantenha um <code>aclfile<\/code> igual em todos:<\/p>\n<pre><code class=\"language-bash\">for i in 11 12 13 14 15 16; do\n  valkey-cli -a 'SenhaForte' --no-auth-warning -h 10.77.77.$i \\\n    ACL SETUSER app on '&gt;S3nhaApp!' '~app:*' '+@read' '+@write' '-@dangerous'\ndone\n\n$ valkey-cli -c -h 10.77.77.11 --user app --pass 'S3nhaApp!' --no-auth-warning set app:config 1\nOK\n$ valkey-cli -c -h 10.77.77.11 --user app --pass 'S3nhaApp!' --no-auth-warning set outro:x 1\nNOPERM No permissions to access a key\n$ valkey-cli -c -h 10.77.77.11 --user app --pass 'S3nhaApp!' --no-auth-warning flushall\nNOPERM User app has no permissions to run the 'flushall' command<\/code><\/pre>\n<h3>TLS em clientes, replica\u00e7\u00e3o e barramento<\/h3>\n<p>A imagem oficial e o bin\u00e1rio oficial j\u00e1 v\u00eam com TLS. Testamos um cluster separado de 3 n\u00f3s s\u00f3 com TLS, usando uma CA pr\u00f3pria e um certificado com os IPs no SAN:<\/p>\n<pre><code class=\"language-bash\">openssl genrsa -out ca.key 4096\nopenssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj \"\/CN=Valkey CA\" -out ca.crt\nopenssl genrsa -out valkey.key 2048\nopenssl req -new -key valkey.key -subj \"\/CN=valkey-cluster\" -out valkey.csr\nprintf \"subjectAltName=IP:10.77.77.21,IP:10.77.77.22,IP:10.77.77.23\\nextendedKeyUsage=serverAuth,clientAuth\\n\" &gt; ext.cnf\nopenssl x509 -req -in valkey.csr -CA ca.crt -CAkey ca.key -CAcreateserial \\\n  -days 825 -sha256 -extfile ext.cnf -out valkey.crt<\/code><\/pre>\n<pre><code class=\"language-bash\"># valkey.conf (trecho TLS)\nport 0                  # desliga a porta sem TLS\ntls-port 6379\ntls-cert-file \/tls\/valkey.crt\ntls-key-file \/tls\/valkey.key\ntls-ca-cert-file \/tls\/ca.crt\ntls-cluster yes         # barramento do cluster com TLS\ntls-replication yes     # replica\u00e7\u00e3o com TLS\ntls-auth-clients yes    # exige certificado do cliente (mTLS)<\/code><\/pre>\n<pre><code class=\"language-bash\">T=\"--tls --cacert \/tls\/ca.crt --cert \/tls\/valkey.crt --key \/tls\/valkey.key\"\nvalkey-cli $T --cluster create 10.77.77.21:6379 10.77.77.22:6379 10.77.77.23:6379 --cluster-yes\nvalkey-cli $T -c -h 10.77.77.21 set tls:ok sim     # OK\nvalkey-cli $T -c -h 10.77.77.22 get tls:ok         # \"sim\"\n\nvalkey-cli -h 10.77.77.21 ping                          # Error: Connection reset by peer\nvalkey-cli --tls --cacert \/tls\/ca.crt -h 10.77.77.21 ping   # Error: Server closed the connection<\/code><\/pre>\n<p>A primeira falha \u00e9 um cliente sem TLS falando com a porta TLS. A segunda \u00e9 um cliente com TLS mas sem certificado pr\u00f3prio, recusado pelo <code>tls-auth-clients yes<\/code>. Em produ\u00e7\u00e3o, gere um certificado por n\u00f3. Para mais contexto sobre certificados, veja <a href=\"\/2026\/09\/ssl-tls-postfix-dovecot\/\">SSL\/TLS no Postfix e no Dovecot<\/a>.<\/p>\n<h2>Em servidores reais: bin\u00e1rio oficial e systemd<\/h2>\n<p>Op\u00e7\u00f5es de instala\u00e7\u00e3o no Ubuntu e no Debian em setembro de 2026:<\/p>\n<ul>\n<li><strong>Bin\u00e1rio oficial<\/strong> em <a href=\"https:\/\/valkey.io\/download\/\">valkey.io\/download<\/a>: tarballs para Ubuntu 22.04 (jammy) e 24.04 (noble), em x86_64 e arm64, com a vers\u00e3o mais recente (9.1.2). \u00c9 o que usamos abaixo.<\/li>\n<li><strong>Pacote da distribui\u00e7\u00e3o:<\/strong> o Ubuntu 26.04 LTS traz o 9.0.4 (<code>apt install valkey-server valkey-tools<\/code>, testado), o Debian 13 traz o 8.1.1 e o Ubuntu 24.04 ainda est\u00e1 no 7.2.x. Os pacotes j\u00e1 incluem as units <code>valkey-server.service<\/code> e <code>valkey-server@.service<\/code>.<\/li>\n<\/ul>\n<p>Nos seis servidores (aqui 10.0.0.11 a 10.0.0.16), ajuste o kernel como a <a href=\"https:\/\/valkey.io\/topics\/admin\/\">documenta\u00e7\u00e3o de administra\u00e7\u00e3o<\/a> recomenda:<\/p>\n<pre><code class=\"language-bash\">echo 'vm.overcommit_memory = 1' | sudo tee \/etc\/sysctl.d\/90-valkey.conf\nsudo sysctl --system\necho never | sudo tee \/sys\/kernel\/mm\/transparent_hugepage\/enabled   # persista via unit ou GRUB<\/code><\/pre>\n<p>Instale o bin\u00e1rio conferindo o SHA-256 e crie usu\u00e1rio, diret\u00f3rios e configura\u00e7\u00e3o:<\/p>\n<pre><code class=\"language-bash\">VER=9.1.2\ncd \/tmp\ncurl -fsSLO https:\/\/download.valkey.io\/releases\/valkey-${VER}-noble-x86_64.tar.gz\ncurl -fsSLO https:\/\/download.valkey.io\/releases\/valkey-${VER}-noble-x86_64.tar.gz.sha256\nsha256sum -c valkey-${VER}-noble-x86_64.tar.gz.sha256      # ...tar.gz: OK\ntar xzf valkey-${VER}-noble-x86_64.tar.gz\nsudo install -m 755 valkey-${VER}-noble-x86_64\/bin\/* \/usr\/local\/bin\/\n\nsudo useradd --system --home-dir \/var\/lib\/valkey --shell \/usr\/sbin\/nologin valkey\nsudo install -d -o valkey -g valkey -m 750 \/var\/lib\/valkey \/var\/log\/valkey\nsudo install -d -o root -g valkey -m 750 \/etc\/valkey<\/code><\/pre>\n<pre><code class=\"language-bash\"># \/etc\/valkey\/valkey.conf  (troque o IP do bind em cada servidor)\nbind 10.0.0.11 127.0.0.1\nport 6379\nprotected-mode yes\ndaemonize no\nsupervised systemd\ndir \/var\/lib\/valkey\nlogfile \/var\/log\/valkey\/valkey.log\ncluster-enabled yes\ncluster-config-file nodes-6379.conf\ncluster-node-timeout 5000\nappendonly yes\nappendfsync everysec\nsave 3600 1 300 100\nrequirepass Troque-Esta-Senha\nprimaryauth Troque-Esta-Senha\nmaxmemory 2gb\nmaxmemory-policy noeviction<\/code><\/pre>\n<pre><code class=\"language-bash\">sudo chown root:valkey \/etc\/valkey\/valkey.conf\nsudo chmod 640 \/etc\/valkey\/valkey.conf<\/code><\/pre>\n<p>Em cluster, <code>maxmemory-policy noeviction<\/code> faz o n\u00f3 recusar escritas quando a mem\u00f3ria acaba, em vez de apagar dados. Para uso s\u00f3 como cache, troque por <code>allkeys-lru<\/code>. A unit do systemd usa <code>Type=notify<\/code>, porque o bin\u00e1rio oficial \u00e9 compilado com suporte a systemd e avisa quando est\u00e1 pronto. Para os comandos de dia a dia do systemd, veja <a href=\"\/2026\/09\/dominando-o-systemd-comandos-essenciais\/\">Dominando o systemd<\/a>.<\/p>\n<pre><code class=\"language-ini\"># \/etc\/systemd\/system\/valkey.service\n[Unit]\nDescription=Valkey (cluster node)\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=notify\nUser=valkey\nGroup=valkey\nExecStart=\/usr\/local\/bin\/valkey-server \/etc\/valkey\/valkey.conf\nRestart=on-failure\nLimitNOFILE=65535\nTimeoutStartSec=60\nTimeoutStopSec=60\nNoNewPrivileges=yes\nProtectSystem=full\nProtectHome=yes\nPrivateTmp=yes\nReadWritePaths=\/var\/lib\/valkey \/var\/log\/valkey \/etc\/valkey\n\n[Install]\nWantedBy=multi-user.target<\/code><\/pre>\n<pre><code class=\"language-bash\">sudo systemctl daemon-reload\nsudo systemctl enable --now valkey\nsystemctl status valkey     # Active: active (running) ... Status: \"Ready to accept connections\"<\/code><\/pre>\n<p>N\u00e3o \u00e9 preciso <code>ExecStop<\/code>. O systemd manda SIGTERM, e o Valkey faz o fsync do AOF, grava o RDB final e salva o <code>nodes.conf<\/code> antes de sair. No teste, o log registrou <em>&#8220;Saving the final RDB snapshot before exiting&#8221;<\/em> e <em>&#8220;Valkey is now ready to exit&#8221;<\/em>. O <code>\/etc\/valkey<\/code> entra em <code>ReadWritePaths<\/code> para o caso de voc\u00ea usar <code>CONFIG REWRITE<\/code>. Libere as portas s\u00f3 para a rede dos n\u00f3s e dos clientes:<\/p>\n<pre><code class=\"language-bash\">sudo ufw allow from 10.0.0.0\/24 to any port 6379,16379 proto tcp<\/code><\/pre>\n<p>Por fim, de qualquer um dos servidores:<\/p>\n<pre><code class=\"language-bash\">valkey-cli -a 'Troque-Esta-Senha' --no-auth-warning --cluster create \\\n  10.0.0.11:6379 10.0.0.12:6379 10.0.0.13:6379 \\\n  10.0.0.14:6379 10.0.0.15:6379 10.0.0.16:6379 --cluster-replicas 1<\/code><\/pre>\n<p>Replicar isso em seis m\u00e1quinas \u00e9 trabalho para automa\u00e7\u00e3o. O guia de <a href=\"\/2026\/09\/automatizando-servidores-linux-com-ansible\/\">Ansible<\/a> cobre o b\u00e1sico para transformar os passos acima num playbook.<\/p>\n<h2>Valkey Admin: o cluster numa tela<\/h2>\n<p>O <a href=\"https:\/\/valkey-admin.valkey.io\/\">Valkey Admin<\/a> \u00e9 a ferramenta oficial de observa\u00e7\u00e3o e gerenciamento do projeto, com licen\u00e7a Apache 2.0. A vers\u00e3o 1.0 saiu em maio de 2026 e a atual \u00e9 a <a href=\"https:\/\/github.com\/valkey-io\/valkey-admin\/releases\/tag\/v1.1.1\">1.1.1<\/a> (14\/08\/2026). Ele roda como aplicativo desktop para Linux (.deb e AppImage) e macOS, ou como aplica\u00e7\u00e3o web em Docker\/Kubernetes. Entre os recursos est\u00e3o dashboard de mem\u00f3ria, CPU, clientes e hit ratio, navegador de chaves, envio de comandos com autocompletar, mapa de topologia do cluster, hot keys, big keys (novidade da 1.1) e o <code>COMMANDLOG<\/code> agregado de todos os n\u00f3s.<\/p>\n<p>No laborat\u00f3rio rodamos a vers\u00e3o web na mesma rede do cluster, publicada s\u00f3 no localhost:<\/p>\n<pre><code class=\"language-bash\">docker run -d --name valkey-admin --network valkey-net --ip 10.77.77.60 \\\n  -p 127.0.0.1:18080:8080 \\\n  -e DEPLOYMENT_MODE=Web \\\n  -e VALKEY_HOST=10.77.77.11 -e VALKEY_PORT=6379 \\\n  -e VALKEY_AUTH_TYPE=password -e VALKEY_USERNAME=default \\\n  -e 'VALKEY_PASSWORD=SenhaForte' \\\n  valkey\/valkey-admin:1.1.1\n\ndocker logs valkey-admin\n# Server running at http:\/\/localhost:8080\n# Starting metrics server for:  10-77-77-11-6379\n# Starting metrics server for:  10-77-77-12-6379\n# Starting metrics server for:  10-77-77-13-6379\n# Cluster nodes and metrics servers are in sync<\/code><\/pre>\n<p>As vari\u00e1veis <code>VALKEY_*<\/code> iniciam a coleta de m\u00e9tricas (um coletor por prim\u00e1rio), mas a interface come\u00e7a vazia. Abra <code>http:\/\/127.0.0.1:18080<\/code>, clique em <strong>+ Add Connection<\/strong> e escolha <strong>Discovery<\/strong> para cluster. Preencha host, porta, usu\u00e1rio e senha. Aten\u00e7\u00e3o: no nosso teste, a op\u00e7\u00e3o <strong>Use TLS<\/strong> veio marcada por padr\u00e3o no modo Discovery, e a conex\u00e3o ficou parada em <em>Connecting&#8230;<\/em> at\u00e9 desmarcarmos a op\u00e7\u00e3o, j\u00e1 que o cluster do laborat\u00f3rio n\u00e3o usa TLS. Conectado, o <em>Cluster Topology<\/em> mostrou os 6 n\u00f3s com os pares prim\u00e1rio\/r\u00e9plica corretos:<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/09\/valkey-admin-cluster-topologia.webp\" alt=\"Tela Cluster Topology do Valkey Admin mostrando 3 prim\u00e1rios e 3 r\u00e9plicas do laborat\u00f3rio\" width=\"1200\" height=\"470\" loading=\"lazy\" \/><\/p>\n<p>Leia as <a href=\"https:\/\/valkey-admin.valkey.io\/reference\/limitations\/\">limita\u00e7\u00f5es<\/a> antes de p\u00f4r em produ\u00e7\u00e3o:<\/p>\n<ul>\n<li><strong>N\u00e3o tem login pr\u00f3prio nem RBAC.<\/strong> Quem acessa a interface roda qualquer comando que a ACL do usu\u00e1rio configurado permitir. Coloque-o atr\u00e1s de um proxy com autentica\u00e7\u00e3o (nginx, oauth2-proxy) e conecte com um usu\u00e1rio ACL restrito.<\/li>\n<li><strong>N\u00e3o suporta mTLS.<\/strong> S\u00f3 TLS com senha. O cluster TLS com <code>tls-auth-clients yes<\/code> que montamos acima n\u00e3o \u00e9 compat\u00edvel.<\/li>\n<li>As m\u00e9tricas v\u00eam s\u00f3 dos prim\u00e1rios, e o navegador de chaves amostra cerca de 1.000 chaves (a busca usa <code>SCAN MATCH<\/code>).<\/li>\n<\/ul>\n<h2>Monitoramento<\/h2>\n<p>O Valkey Admin \u00e9 bom para investigar problemas, mas alerta \u00e9 trabalho do Prometheus. O blog do Valkey tem um <a href=\"https:\/\/valkey.io\/blog\/valkey-prometheus-exporters\/\">guia de exporters<\/a> que usa o <a href=\"https:\/\/github.com\/oliver006\/redis_exporter\">redis_exporter<\/a>, compat\u00edvel com o Valkey. Os alertas m\u00ednimos s\u00e3o <code>cluster_state<\/code> diferente de <code>ok<\/code>, <code>master_link_status:down<\/code> nas r\u00e9plicas, mem\u00f3ria perto do <code>maxmemory<\/code> e shard sem r\u00e9plica. Se o Prometheus ainda n\u00e3o est\u00e1 no ar, comece por <a href=\"\/2026\/09\/monitorando-servidores-linux-com-prometheus\/\">Monitorando Servidores Linux com Prometheus<\/a>. Para um check externo simples de TCP na 6379 de cada n\u00f3, o <a href=\"\/2026\/09\/go-uptime-monitoramento-self-hosted-derivado-do-gatus\/\">Go Uptime<\/a> resolve.<\/p>\n<h2>Troubleshooting: erros que apareceram no laborat\u00f3rio<\/h2>\n<ul>\n<li><strong><code>CLUSTERDOWN Hash slot not served<\/code><\/strong>: o n\u00f3 est\u00e1 em modo cluster, mas nenhum n\u00f3 \u00e9 dono do slot. Acontece antes do <code>--cluster create<\/code> ou quando slots ficaram sem dono. Rode <code>valkey-cli --cluster check<\/code> e, se for o caso, <code>--cluster fix<\/code>.<\/li>\n<li><strong><code>CLUSTERDOWN The cluster is down<\/code><\/strong>: apareceu por um instante logo depois do <code>--cluster create<\/code> no cluster TLS, enquanto os n\u00f3s convergiam. Dois segundos depois estava <code>ok<\/code>. Tamb\u00e9m aparece quando um shard perde o prim\u00e1rio <em>e<\/em> a r\u00e9plica. Derrubamos os n\u00f3s 3 e 4 juntos, e <code>cluster_slots_ok<\/code> caiu para 10923. Com <code>cluster-require-full-coverage no<\/code>, os shards saud\u00e1veis continuam atendendo e s\u00f3 as chaves do shard morto falham.<\/li>\n<li><strong><code>MOVED 7319 10.77.77.12:6379<\/code><\/strong>: cliente sem modo cluster. Use <code>valkey-cli -c<\/code> ou uma biblioteca com suporte a cluster. Se o redirecionamento aponta para um IP inalcan\u00e7\u00e1vel, o problema \u00e9 NAT ou <code>cluster-announce-ip<\/code> errado.<\/li>\n<li><strong><code>ASK 3844 10.77.77.12:6379<\/code><\/strong>: reproduzido marcando o slot como <code>MIGRATING<\/code>\/<code>IMPORTING<\/code> \u00e0 m\u00e3o, no meio de uma migra\u00e7\u00e3o chave a chave. O cliente com <code>-c<\/code> segue sozinho. Se um slot ficar preso nesse estado, o <code>--cluster check<\/code> acusa <em>open slots<\/em>, e o <code>CLUSTER SETSLOT &lt;slot&gt; STABLE<\/code> ou o <code>--cluster fix<\/code> resolvem.<\/li>\n<li><strong><code>CROSSSLOT Keys in request don't hash to the same slot<\/code><\/strong>: comando multi-chave com chaves em slots diferentes. Use hash tags (<code>{pedido:42}:...<\/code>).<\/li>\n<li><strong><code>master_link_status:down<\/code> com <code>NOAUTH<\/code> no log da r\u00e9plica<\/strong>: falta <code>primaryauth<\/code> no n\u00f3.<\/li>\n<li><strong><code>DENIED Running in protected mode<\/code><\/strong>: conex\u00e3o remota sem senha no usu\u00e1rio default.<\/li>\n<li><strong><code>Unrecognized option or bad number of args for: '-@dangerous'<\/code><\/strong>: o <code>valkey-cli --cluster call<\/code> interpreta argumentos que come\u00e7am com <code>-<\/code> como op\u00e7\u00f5es da pr\u00f3pria ferramenta. Crie ACLs com um la\u00e7o por n\u00f3, como mostrado acima.<\/li>\n<li><strong>O <code>AUTH failed<\/code> n\u00e3o interrompe o <code>valkey-cli<\/code>.<\/strong> Esse foi o susto do laborat\u00f3rio. Rodamos comandos com <code>--user app<\/code> antes de o usu\u00e1rio existir. O <code>valkey-cli<\/code> mostrou <code>AUTH failed: WRONGPASS<\/code> e <strong>continuou executando os comandos como usu\u00e1rio <code>default<\/code><\/strong>, que naquele momento n\u00e3o tinha senha. Um <code>FLUSHALL<\/code> de teste passou e apagou o shard 1 inteiro (<code>cmdstat_flushall:calls=1<\/code> no <code>INFO commandstats<\/code>). Mais um motivo para nunca deixar o usu\u00e1rio <code>default<\/code> sem senha.<\/li>\n<\/ul>\n<h2>Limpando o laborat\u00f3rio<\/h2>\n<pre><code class=\"language-bash\">docker rm -f valkey-{1..8} valkey-client valkey-admin 2&gt;\/dev\/null\ndocker network rm valkey-net<\/code><\/pre>\n<h2>Conclus\u00e3o<\/h2>\n<p>O Valkey herdou o cluster do Redis e vem melhorando exatamente a parte que mais dava trabalho: o resharding virou at\u00f4mico, o cluster aceita bancos numerados e a vers\u00e3o 9.1 trouxe ACL por banco e TLS com rota\u00e7\u00e3o de certificados. No teste, o failover levou cerca de 6 s com o <code>cluster-node-timeout<\/code> padr\u00e3o do tutorial e cerca de 3 s com 2000 ms, sem interven\u00e7\u00e3o. Esse n\u00famero \u00e9 o que voc\u00ea deve levar \u00e0 conversa com o time da aplica\u00e7\u00e3o, junto com a exig\u00eancia de um cliente que entenda cluster. Se o seu problema \u00e9 alta disponibilidade de banco relacional, veja o <a href=\"\/2026\/09\/mariadb-galera-cluster-mariabackup-ubuntu\/\">cluster MariaDB Galera com mariabackup<\/a>. Se o cluster vai rodar em Kubernetes bare metal, o <a href=\"\/2026\/09\/metallb-loadbalancer-kubernetes-bare-metal-layer2-bgp\/\">MetalLB<\/a> resolve a exposi\u00e7\u00e3o dos servi\u00e7os.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cl\u00faster Valkey 9.1.2 con 3 principales y 3 r\u00e9plicas: slots de hash, MOVED\/ASK, failover medido derribando un primario, reshard con migraci\u00f3n at\u00f3mica, persistencia, ACL, TLS, systemd y Valkey Admin.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[46,21,2,111,120],"tags":[502,500,329,156,503,496,123,497,504],"class_list":["post-1719","post","type-post","status-publish","format-standard","hentry","category-devops","category-infra","category-linux","category-opensource","category-servidores","tag-alta-disponibilidade","tag-cache","tag-cluster","tag-docker","tag-failover","tag-redis","tag-systemd","tag-valkey","tag-valkey-admin"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/1719","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/comments?post=1719"}],"version-history":[{"count":1,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/1719\/revisions"}],"predecessor-version":[{"id":1721,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/posts\/1719\/revisions\/1721"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/media?parent=1719"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/categories?post=1719"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/es\/wp-json\/wp\/v2\/tags?post=1719"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}