ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

三节点 Raft 挂了一台,先别背选举:照着这 5 步查完再回答

三节点 Raft 挂了一台,先别背选举:照着这 5 步查完再回答 面试官问“Leader 挂了怎么办”很多人会立刻开始背心跳超时、Candidate、RequestVote、多数派、新 Leader。这些词没有错但只背这些面试官无法判断你到底有没有真的做过分区或节点故障。更稳的做法不是先解释而是先复现。这篇文章给你一条可以直接照着走的 Windows 操作路径text启动 3 个节点- 写入并读回 key- 查看 Leader 和 commit/applied- 停掉 node-a- 从 node-b、node-c 继续读写- 最后再解释为什么下面所有输出都来自 RaftKV 在 Windows 上的真实验收不是只画一张 Raft 示意图。## 一、先确认你测的是什么不是什么这次测的场景是- 三节点集群- 每个分片有三个副本- 停掉一个节点 node-a- 剩余两个节点仍然在线- 原 key 可以继续读- 新 key 可以继续写。这次不证明- 两台节点同时挂掉还能继续服务- Redis、etcd、TiKV 的生产级替代能力- 跨机房容灾、自动运维或者零请求失败。把边界先说清楚后面的结果才不会被夸大。## 二、第 1 步把三节点启动起来解压 RaftKV 15 分钟试跑包在根目录打开 PowerShellpowershellpowershell -ExecutionPolicy Bypass -File .\scripts\start-trial.ps1脚本会启动三个独立进程textnode-a http://127.0.0.1:19090node-b http://127.0.0.1:19091node-c http://127.0.0.1:19092预期看到textstatus okcluster RaftKV Trial 2026-09-06shards 2RaftKV trial healthy.statusok 说明进程和接口已经起来但不代表选举已经全部完成。再检查一次 Leader 数量powershellInvoke-RestMethod -Uri http://127.0.0.1:19090/api/v1/health |ConvertTo-Json选举完成后应看到textleaders 2shards 2status ok如果 leaders 还是 0等待几秒再查一次。选举没有完成时不要急着判断写入失败。如果 60 秒还没有 healthy先不要继续下一步直接看日志powershellGet-Content .\logs\node-0.err.log -Tail 50Get-Content .\logs\node-1.err.log -Tail 50Get-Content .\logs\node-2.err.log -Tail 50常见原因只有几个端口被占用、三个进程没有全部启动、旧数据和新配置不一致。## 三、第 2 步先写入一个 key再从接口读回来打开另一个 PowerShell先准备地址和密钥powershell$base http://127.0.0.1:19090$admin { X-API-Key admin-trial-20260906 }$read { X-API-Key read-trial-20260906 }写入一个 keypowershell$body {key trial:user:1001value RaftKV-ok} | ConvertTo-JsonInvoke-RestMethod -Method Post -Uri $base/api/v1/put -Headers $admin -ContentType application/json -Body $body读取同一个 keypowershellInvoke-RestMethod -Uri $base/api/v1/get?keytrial%3Auser%3A1001 -Headers $read |ConvertTo-Json本次验收返回json{found: true,key: trial:user:1001,shard: shard-1,value: RaftKV-ok}先写入、再读回不是多余步骤。后面停掉节点以后你会用同一个 key 再读一次。只有这样才能证明“故障前确实有一份已提交数据”。## 四、第 3 步先看清 Leader、commit 和 applied故障前的集群状态powershellInvoke-RestMethod -Uri $base/api/v1/cluster/status -Headers $read |ConvertTo-Json -Depth 8本次验收中三个节点都有两个分片副本。shard-0textnode-b stateleader term5 commit4 applied4node-a statefollower term5 commit4 applied4node-c statefollower term5 commit4 applied4shard-1textnode-a stateleader term3 commit3 applied3node-b statefollower term3 commit3 applied3node-c statefollower term3 commit3 applied3这里先不用背 Raft 论文只要记住三个检查位置- leader这个分片当前由谁负责。- commit日志已经提交到哪里。- applied状态机已经应用到哪里。正常服务时commit 和 applied 不能长期脱节。## 五、第 4 步真的停掉 node-a不要改页面状态先读取启动脚本写下的 PIDpowershell$pids Get-Content .\data\trial\cluster-pids.json | ConvertFrom-Json停掉第一个进程也就是 node-apowershellStop-Process -Id $pids[0] -ForceStart-Sleep -Seconds 12为什么要等因为 Leader 停止以后其余节点需要经过选举超时、投票和日志追赶状态不会在进程退出的那一瞬间就完成切换。检查端口powershellGet-NetTCPConnection -State Listen |Where-Object { $_.LocalPort -in 19090,19091,19092 }此时只应剩text127.0.0.1:19091127.0.0.1:19092## 六、第 5 步从剩余两个节点继续读、继续写先通过 node-b 检查健康状态powershell$baseB http://127.0.0.1:19091Invoke-RestMethod -Uri $baseB/api/v1/health |ConvertTo-Json本次返回json{cluster: RaftKV Trial 2026-09-06,leaders: 2,status: ok,shards: 2,version: raft-kv-1.0.2}这时 node-a 已经停止但两个分片依然都有 Leader。再读取故障前写入的 keypowershellInvoke-RestMethod -Uri $baseB/api/v1/get?keytrial%3Auser%3A1001 -Headers $read |ConvertTo-Json返回仍然是json{found: true,key: trial:user:1001,shard: shard-1,value: RaftKV-ok}接着写入一个新 keypowershell$body2 {key failover:after:node0value still-writable} | ConvertTo-JsonInvoke-RestMethod -Method Post -Uri $baseB/api/v1/put -Headers $admin -ContentType application/json -Body $body2再从 node-c 读取新 keypowershell$baseC http://127.0.0.1:19092Invoke-RestMethod -Uri $baseC/api/v1/get?keyfailover%3Aafter%3Anode0 -Headers $read |ConvertTo-Json返回json{found: true,key: failover:after:node0,shard: shard-0,value: still-writable}到这里验收结果已经足够明确text故障前写入成功停 node-a节点进程真实退出故障后原 key 可读故障后新 key 可写、可从其他节点读回最后再看一次状态powershellInvoke-RestMethod -Uri $baseB/api/v1/cluster/status -Headers $read |ConvertTo-Json -Depth 8本次结果中- shard-1 的新 Leader 变成 node-cterm 提升到 4- node-b 和 node-c 的 commit、applied 都追到 4- 两个分片仍然各有 Leader集群保持可读写。## 七、做到这里再补最少量的原理前面的操作已经完成。现在才需要解释三个问题。### 1. 为什么少一个节点还能工作三节点集群里三个节点中的任意两个可以组成多数派。停掉一个节点以后还有两个节点所以可以继续选举和提交日志。如果三台里停掉两台就只剩一个节点不再有多数派这时不能继续承诺写入。### 2. 为什么原数据还能读已经提交的数据在返回成功前已经复制到多数派。node-a 停止以后剩余节点中仍然保存着已提交日志和对应状态所以可以继续提供原数据。### 3. 为什么可能出现短暂失败“多数派还在”不等于“故障瞬间零失败”。旧 Leader 停止后客户端可能遇到连接失败、选举窗口内的重试或者暂时还要等待本地 applied 追上 commit。所以面试里更准确的表达是 在三节点失去一个节点的场景下多数派仍然存在集群可以完成重新选举并继续推进会提交日志但客户端仍应处理切换期间的短暂失败和重试。## 八、面试时可以直接这样答如果不想背长篇概念按下面这段说 我做过一次三节点 Raft 分片 KV 的故障验证。先写入一个 key再从其他节点读回确认它是已提交数据。然后我真实停掉 node-a等待选举完成再从 node-b 和 node-c 检查健康状态。两个分片仍然都有 Leader原 key 还能读新 key 也还能写。状态里能继续看到 commit 和 applied 推进新 Leader 的 term 也发生了提升。这个测试证明的是教学级三节点故障恢复不替代 Redis、etcd 或 TiKV 的生产能力。这段话里没有堆概念但它包含text测试环境- 操作步骤- 现场证据- 结果判断- 工程边界面试官继续追问时再展开心跳、选举、日志复制和读取条件。## 九、最后记住这 5 个检查点遇到“Leader 挂了怎么办”先按顺序检查1. 三个节点是否都在运行。2. 故障前是否真的写入并读回过一个 key。3. 停节点后端口和进程是否真的发生变化。4. 剩余节点是否还能形成多数派。5. commit、applied 是否继续推进原数据是否能读、新数据是否能写。如果这五项没有证据先不要急着背 Raft。先把故障跑出来再把日志和状态保留下来。系列延伸- 《Raft 旧 Leader 恢复后还能读旧数据吗一个分区测试讲清楚》https://blog.csdn.net/qq_53554649/article/details/164864176- 《Raft 节点重启后怎么恢复别把“进程起来了”当成日志追平》https://blog.csdn.net/qq_53554649/article/details/165001827公开测试记录和复现入口https://github.com/yuan1521913/raft-kv配套视频https://www.bilibili.com/video/BV1VKYE6oEmm/教学级 / 作品集级项目不替代 Redis、etcd 或 TiKV。
返回列表