分布式数据库在缩容过程中,数据丢失的根源往往不是操作失误,而是对数据副本迁移、分片重组和一致性协议交互的机制理解不够。很多团队在执行缩容时习惯性地把节点直接下线,结果触发副本不足、Leader切换异常或数据重平衡失败,最终造成部分分片不可用甚至数据文件损坏。要规避这类风险,核心在于把缩容当作一次受控的数据迁移工程,而不是简单的资源回收动作。
先确认缩容场景与数据分布状态
缩容通常分为两种:减少副本数和减少节点数。减少副本数相对简单,但依然要检查当前分片的Leader分布和Follower同步延迟。减少节点数则复杂得多,因为涉及分片重新分配、数据搬迁和元数据更新。在动手之前,必须获取集群的完整拓扑信息,包括每个分片的Leader位置、副本分布、磁盘占用和同步状态。很多数据丢失事故是因为某个节点上同时存在多个分片的Leader,直接下线后这些分片在短时间内没有可用Leader,写入请求被拒绝,客户端重试时又触发不一致写。
执行缩容前,建议先对每个分片执行一次健康检查,确认所有副本的日志进度一致。对于使用Raft或Paxos协议的数据库,可以通过监控指标查看last_log_index和commit_index的差值。如果某个Follower长期落后,缩容时又恰好把这个节点保留下来而移除了其他健康副本,后续一旦Leader故障,这个落后副本被提升为Leader,就会造成已提交数据的丢失。因此,缩容前必须确保所有保留副本的日志差距在可接受范围内,最好先触发一次强制同步或快照传输。
用渐进式迁移替代直接下线
直接下线节点的最大问题是瞬时产生大量副本缺失。正确做法是先把待下线节点上的分片副本迁移到其他节点,等数据完全同步后再从集群中摘除该节点。这个过程需要分步骤执行:先标记节点为“待下线”状态,禁止新的分片调度到该节点;然后对每个分片生成新的副本放置计划,确保新副本完成全量数据同步并加入共识组;接着将旧副本从共识组中移除;最后才关闭节点进程。
以TiDB为例,缩容TiKV节点时可以使用tiup cluster scale-in命令,但直接执行该命令会触发PD调度器自动迁移Region。如果集群数据量大,短时间内大量Region同时搬迁会造成IO风暴,影响在线业务。更稳妥的方式是先通过pd-ctl调整调度参数,比如降低region-schedule-limit和leader-schedule-limit,让迁移速度可控。同时,对待下线节点设置evict-leader-scheduler,主动把Leader迁走,避免下线时Leader集中切换。
对于使用一致性哈希或虚拟节点的数据库,缩容时要特别注意数据重平衡算法。有些系统在节点减少后会触发全量数据重哈希,如果此时网络抖动或进程崩溃,部分数据可能只写了一半。建议在缩容窗口内暂停自动重平衡,手动控制数据迁移批次,每完成一批就校验一次数据一致性。
副本数与一致性级别的匹配
缩容时很多人会顺手把副本数也降下来,比如从三副本降到两副本。这个操作本身没问题,但必须重新评估一致性级别。三副本可以容忍一个节点故障而不丢数据,两副本在单节点故障时如果另一个副本也刚好有坏盘,数据就没了。如果业务对数据丢失零容忍,缩容后副本数降低意味着风险敞口变大,这时候应该考虑是否保留三副本,或者通过跨机架、跨可用区部署来弥补。
另外,有些分布式数据库支持动态调整写一致性级别。缩容期间如果副本数暂时不足,客户端可能自动降级为异步写或单副本写,这种隐式降级非常危险。务必在缩容前检查客户端配置,确保写请求的一致性级别不会被自动降低。对于使用Quorum写机制的数据库,缩容后如果节点数减少,Quorum的计算基数变化,可能导致写入成功但实际副本数不足。例如原来5节点Quorum为3,缩到3节点后Quorum变为2,此时写入只需要2个副本确认,如果其中一个副本所在节点随后故障,数据就可能丢失。因此,缩容后要重新计算Quorum并调整相关参数。
快照备份与回滚预案是最后防线
无论缩容方案设计得多完善,都必须准备一份完整的物理或逻辑备份。备份时间点要尽可能接近缩容操作开始时间,最好在缩容前停止写入或切换到只读模式,然后执行一致性快照。对于支持在线备份的数据库,可以使用其原生备份工具,比如MySQL Group Replication的mysqldump配合事务一致性,或者MongoDB的mongodump配合oplog。备份文件要存放在独立于集群的存储上,并验证可恢复性。
回滚预案同样重要。缩容过程中如果发现数据不一致或性能严重下降,需要能快速恢复原拓扑。这要求缩容操作具备可逆性,比如在移除节点前保留其数据目录和配置,一旦需要回滚,可以重新加入节点并触发数据同步。对于已经执行了数据删除的节点,回滚只能依赖备份,因此备份的完整性和恢复速度直接决定了故障恢复时间。
监控与校验贯穿缩容全程
缩容不是一次性操作,而是一个持续数小时甚至数天的过程。期间必须实时监控数据同步进度、磁盘IO、网络流量和错误日志。重点关注以下指标:待迁移分片的剩余数据量、同步速率、Leader切换次数、客户端重试率和写延迟。如果同步速率突然下降或Leader切换频繁,说明集群可能处于不稳定状态,应立即暂停缩容并排查原因。
数据校验是缩容完成后的必要步骤。可以通过对比缩容前后的数据行数、关键表的主键范围或哈希校验和来确认数据完整性。对于支持在线校验的数据库,可以执行一致性检查命令,比如TiDB的ADMIN CHECK TABLE或MongoDB的db.collection.validate()。如果发现不一致,优先从备份恢复,而不是尝试修复,因为修复过程可能引入新的问题。
特殊场景:跨机房缩容与磁盘故障叠加
跨机房部署的分布式数据库在缩容时面临额外的网络延迟和分区风险。如果缩容节点位于某个机房,而该机房与其他机房之间的网络链路不稳定,数据迁移过程中可能出现脑裂或分区。此时应优先迁移数据到同机房或网络延迟更低的节点,避免跨机房传输大量数据。同时,检查集群的拓扑感知配置,确保分片副本不会集中在同一个故障域。
磁盘故障与缩容叠加是最危险的场景之一。假设某个节点磁盘出现坏道,同时该节点又被列为缩容对象,数据迁移时读取坏道数据会导致迁移失败或数据损坏。正确的处理顺序是:先处理磁盘故障,通过副本修复或替换磁盘恢复节点健康,然后再执行缩容。如果磁盘故障无法修复,应直接从健康副本复制数据到新节点,而不是从故障节点读取。
自动化脚本与人工审核结合
为了减少人为失误,缩容操作应尽量脚本化,但脚本执行前必须经过人工审核。脚本中要包含前置检查、分步执行、失败重试和中断保护逻辑。例如,在迁移分片前检查目标节点剩余磁盘空间是否足够,在移除副本前确认新副本已通过健康检查,在关闭节点前确认该节点上已无任何分片副本。脚本还应支持断点续跑,避免因为某个步骤失败导致整个流程需要从头开始。
一个常见的错误是脚本中直接使用force参数跳过检查。比如在移除节点时使用--force跳过副本数校验,这会在副本不足时仍然下线节点,直接造成数据丢失。所有force操作都应该被禁止,或者在执行前触发二次确认和告警。
缩容后的长期稳定性观察
缩容完成不代表风险结束。节点减少后,集群的容错能力下降,剩余节点的负载会上升。需要持续观察至少一个完整的业务周期,包括高峰和低谷时段。重点关注剩余节点的磁盘使用率、内存占用、CPU负载和网络带宽。如果发现某个节点长期处于高负载状态,说明缩容过度,可能需要重新扩容或优化数据分布。
同时,检查集群的调度策略是否合理。缩容后,分片可能集中在少数节点上,形成数据热点。可以通过调整调度参数或手动迁移部分分片来均衡负载。对于使用自动重平衡的数据库,确认重平衡算法在节点数变化后能正确收敛,不会出现反复迁移或震荡。
分布式数据库缩容运维的核心原则是:把数据安全放在资源回收之前,把受控迁移放在快速下线之前,把校验和回滚放在操作完成之前。只要遵循这些原则,缩容完全可以做到业务无感知、数据零丢失。
