作者介绍:简历上没有一个精通的运维工程师,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。

数据库是一个系统(应用)最重要的资产之一,所以我们的数据库将从以下几个数据库来进行介绍。
MySQL
PostgreSQL
Redis
Etcd(本章节)
Raft协议的核心是日志复制,但日志本身不能无限累积。一方面,海量日志会耗尽节点存储空间;另一方面,节点重启时需回放所有历史日志,时间成本随日志量线性增长。快照(Snapshot)正是解决这一问题的标准方案:将某一时刻的系统状态持久化存储,删除该时刻之前的所有日志,从而完成日志压缩。
etcd的快照机制并非简单拷贝Raft论文,而是围绕独立性、高效性、传输优化三个维度做了大量工程打磨。本文将从快照生成、快照传输、快照恢复、性能权衡四个视角,完整解析etcd的快照技术。
与多数人的直觉相反:etcd快照并非由Leader统一生成后分发,而是每个节点独立创建。这一设计源于Raft作者对强领导人原则的“有意违背”。
生成时机:etcd支持两种触发方式——定量的日志条数(如每10000条日志)或定时的间隔周期。生产环境推荐前者,因为它将日志量控制在稳定水位。
生成内容:快照包含三部分
写时复制优化:生成快照时,etcd会fork子进程或利用操作系统COW(Copy-on-Write)技术,使快照写入与正常日志处理并发执行,避免阻塞客户端请求。
为何不采用Leader统一制式? Raft作者曾尝试此方案,但发现两大弊端:一是Leader向所有Follower发送快照会浪费大量网络带宽;二是Leader需在发送快照的同时并行处理新日志,复杂度急剧上升。最终结论是:每个节点从本地状态创建快照,远比通过网络接收他人快照经济。
虽然节点独立生成快照是常态,但某些场景下Leader必须向Follower发送快照——典型情况是新节点加入集群,或落后节点被Leader的日志压缩操作“甩开”太多,Leader已删除其所需的日志条目。
此时,Raft协议的InstallSnapshot RPC登场。etcd对其实现做了关键优化:
分块传输:快照文件可能达数GB,etcd将其切分为默认4MB的数据块(chunk),通过多个RPC分块发送。每个分块包含偏移量(offset)和完成标记(done),接收端按偏移量写入临时文件。
心跳复用:每个快照分块的发送都会重置接收节点的选举超时定时器——快照分块同时充当了心跳包,避免节点在长时传输中误判Leader失效而发起选举-2。
接收端处理:Follower收到完整快照后,执行以下原子操作——
注意:InstallSnapshot RPC是串行执行的,Leader一次只向一个Follower发送一个快照分块序列,避免并发传输对网络造成冲击。
快照并非独立工作,它与WAL构成互补的恢复体系。
快照记录:当etcd生成快照时,会在WAL中追加一条SnapshotType记录,标记“截至某索引的日志已被快照取代”。这条记录本身极小,却是重启时的关键导航点。
重启恢复流程:
效率质变:若无快照,重启需回放从集群诞生至今的所有日志——数千兆字节的数据;有快照后,仅需回放快照后的增量日志——通常控制在数千条以内。这是etcd秒级重启的核心保障。
快照不是免费的午餐。etcd管理员必须在频率与开销之间做出权衡。
频率过高:频繁的fork和全量状态导出会消耗大量CPU和磁盘I/O带宽,甚至触发内核内存压力。在内存达数GB的节点上,fork操作的时延可达百毫秒级。
频率过低:日志文件无限增长,磁盘空间告急;节点重启时需回放海量日志,恢复时间以分钟计;更严重的是,若落后Follower所需日志已被Leader快照删除,将触发全量快照传输——这是集群网络中代价最高的操作-2。
推荐策略:当日志文件达到固定大小阈值(如1GB)时触发快照。这是空间占用与恢复速度的均衡点。etcd也支持动态调整,需结合监控数据持续优化。
etcd的快照机制,本质是用存储空间换取恢复时间,用独立生成换取网络带宽。它在Raft协议框架下,通过“节点自治、按需传输、写时复制”三大设计,将日志压缩的开销压缩至可接受范围。
对于运维者,理解快照不是“备份”,而是分布式系统的时间切片——它标记了集群的某个一致状态,让节点可以从任意历史时刻重生。这种能力,远比简单的磁盘清理深刻得多。