☰
WuKongIM 启动恢复的规模门禁与认证检查点:300 万用户下的 2/4 GiB 内存硬限实测
2026/10/16 2:43:18 网站建设 项目流程
  • 即时通讯
  • 后端

【免费下载链接】WuKongIM

More than just IM 不只是即时通讯(IM)

项目地址:https://gitcode.com/gh_mirrors/wu/WuKongIM
点击查看免费下载

导读

本文围绕 WuKongIM 启动恢复(startup recovery)的最终落地计划展开:在 Linux 真实硬内存上限(2 GiB / 4 GiB cgroup)下,对 300 万用户/设备数据执行基线(baseline)与候选(candidate)版本的完整重启对比实验,并实现"认证检查点(certified checkpoint)"快速重启路径——用可验证的持久化 FSM 证据跳过全量快照重写,同时保留严格的回退与崩溃一致性保证。读完本文,你将掌握该规模门禁的实验设计、环境变量与复现命令、三重独立正确性证明的底层原理,以及源码级实现与全部实测证据的落点。

背景与目标:从"有界恢复"到"认证快速重启"

WuKongIM 的启动恢复问题源于真实生产事故:在某个未记录确切构建与日志的现场,三百万用户数据在启动时出现疑似无限等待。仓库内以提交64f73d99b3b0cb8960d40825f76053f5a0000dbd为基线,用合成数据做了干净重开复现:加载 226 MiB 快照、采样 Go 堆峰值 1,379 MiB、累计分配 2,950 MiB、向元数据 WAL 重写约 229 MiB——这确认了"放大效应"(amplification),而第一阶段的有界流式恢复(bounded streaming recovery)通过分块、鉴权、流式安装把内存峰值压低了约 90%,但它仍然要重写整份快照。

因此最终计划(即本文主体,见 docs/superpowers/plans/2026-09-27-startup-recovery-followup.md)确立了三个必须全部完成的后续步骤:

  1. 在 Linux 硬 2/4 GiB 内存上限下对比真实 300 万用户/设备重启;
  2. 依据该证据决定是否具备合入资格;
  3. 实现持久化 FSM 检查点快速路径,并验证回退与崩溃一致性。

一个关键约束贯穿始终:较小的 smoke 测试或仅存储探针不满足规模门禁,证据不全时实现不得合入。

规模实验(Scale Gate)设计

实验入口与种子生成

规模实验是 opt-in 的 Linux 场景,入口位于 test/e2e/cluster/startup_recovery/scale_linux_test.go。种子通过公开的/bench/v1/users/tokens适配器导入,该入口与/user/token调用同一个集群用户用例(见 scale_linux_test.go)。

种子生成的完整要求:

  • 3,000,000 个确定性 UID,每 UID 一个设备(默认数量可用WK_E2E_STARTUP_SCALE_USERS覆盖);
  • 256 个 hash slot、1 个物理 Slot;
  • 通过 Manager 请求一次真实压缩(compaction),生成快照;
  • 再写入一个快照之后的追加凭据(suffix credential,UID 为scale-after-snapshot);
  • 正常停止产品,并且只在每一批导入都被确认(acknowledged)之后才发布 fixture 收据fixture.json(见 scale_linux_test.go)。

fixture.json是"公共输入收据",不是解码后的存储镜像;种子一旦发布即不可覆盖(refuse to overwrite a published fixture)。

内存硬限制与运行方式

每个用例的关键在于"硬上限"的真实性:

  • 停止后的种子保持不可变,其不透明目录树被复制到每个用例的全新 Docker 卷中,并以相同路径挂载;
  • 实际产品二进制与小型黑盒测试驱动一起运行在 cgroup 内:--memory=2g --memory-swap=2g或对应的4g标志,外加--cpus=4;
  • 测试会校验memory.max与memory.swap.max;cgroup 内存包含驱动与页缓存,而/procRSS 仅指产品进程本身;
  • 不用GOMEMLIMIT替代硬上限。

度量与证据边界

实验需记录的指标包括:进程启动到 ready 的时间、采样 RSS/HWM、CPU ticks、进程读/写计数器、cgroup OOM 计数器与 GC trace;ready 之后再采集有界的 heap/CPU pprof 与指标,并明确标注其范围。特别强调:启动期 CPU 归因使用独立的诊断 overlay(见下文),ready 之后的 profile 不能当作启动归因;Docker Desktop 的页缓存条件也不得描述为物理冷盘测量。

验证要求

  1. 全量库存核对:通过 Manager 分页验证每一个导入 UID 恰好出现一次,包含其设备数量与非空 token 数量,使用 375 KiB 的 bitset(见 verifyScaleInventory,verifyScaleInventory拒绝重复行与光标不前进的页面);
  2. 采样认证:通过真实 WKProto 认证 256 个确定性样本外加提交后的追加凭据(共 257 次);
  3. 恢复期 SIGKILL/重试用例:在观察到安装进行中时停止全部线程、拒绝已完成的安装,再 SIGKILL 并完整重试,保留阶段与计时证据后才算门禁完成。

复现命令

种子与重启的可执行入口(来自计划原文):

# Inside a Linux container with the artifact and /lab volumes mounted: WK_E2E_BINARY=/artifacts/wukongim-baseline \ WK_E2E_STARTUP_SCALE_SEED=/lab/fixture \ /artifacts/scale.test -test.run '^TestStartupRecoveryScaleSeed$' -test.v -test.timeout=100m WK_E2E_BINARY=/artifacts/wukongim-bounded \ WK_E2E_STARTUP_SCALE_FIXTURE=/lab/fixture \ WK_E2E_STARTUP_SCALE_REPORT=/artifacts/case/report.json \ /artifacts/scale-next.test -test.run '^TestStartupRecoveryScaleRestart$' -test.v -test.timeout=40m

配套测试通过环境变量选择行为:WK_E2E_STARTUP_SCALE_INTERRUPT=1触发中断模式,WK_E2E_STARTUP_EXPECT_STAGE断言选定的恢复路径(如checkpoint_reuse时禁止出现snapshot_install),WK_E2E_STARTUP_CPU_PROFILE仅用于诊断插桩二进制(见 scale_linux_test.go)。完整 E2E 场景的使用约束记录在 test/e2e/cluster/startup_recovery/AGENTS.md。

执行收据与二进制精确哈希位于/tmp/wk-startup-followup;种子卷/容器为wk-startup-20260927-seed。有界矩阵驱动会等待该种子容器成功退出,再创建各自命名的 baseline 与 bounded 2/4 GiB 用例,且只触碰任务自有的 Docker 资源。

认证检查点的正确性设计:三重独立证明

快速重启的核心是checkpoint(持久化检查点证书)。要证明"复用已有 FSM 是安全的",计划要求三个独立证明同时成立:

1. 物理元数据连续性(sequence seal)

  • 最终的序列封条(sequence seal)与元数据变更写入同一个物理 Pebble batch,其值标识下一个可见序列号;
  • 在独占准入(exclusive admission)下打开时,通过钉住的快照读取该边界;
  • 不了解协议的旧写者如果修改引擎序列却不刷新封条,复用会被拒绝——这覆盖旧程序与离线导入器(它们会保留 applied index 不变);
  • 无效的启动封条会在重新封条前持久化清除所有旧证书,包括本进程未打开的休眠 Slot(dormant Slot);
  • 未分类(unclassified)写入删除全部检查点记录;混合组提交中任何请求的 veto 都生效;歧义提交(ambiguous commit)要求重开;
  • 进程本地 epoch在失效提交时推进,并在物理提交锁下校验;携带旧内存链的后续业务写入无法复活其证书;
  • 所有权校验过的 FSM 请求按证书检查 epoch,只删除自己的过期证明;被栅栏保护的启动安装与无快照 FSM 写入只删除自身证明,不使不相交 Slot 失效;
  • 迁移维护、重叠迁移状态与所有权不匹配保留保守的全局失效;压缩在读取业务快照之前捕获 epoch,且该 epoch 在跨 open 时永不复用。

该层在源码中的落地是 pkg/db/internal/engine/recovery_seal.go:ConfigureRecoverySeal在独占启动准入下运行一次,通过 Pebble 快照指标读取可见序列边界;commitSealed在提交时写入WKSEAL01封条、按 epoch 清理过期证书,并保留批次的公开表示(batch.Repr())以校验引擎实际分配的序列号(见 recovery_seal.go)。这一修复正是针对大规模测试中"Pebble 将大批次接管为 flushable 后清空调用方批次表示、Batch.SeqNum()误报"的坑。

2. 原子 FSM 证据

  • 一份带版本、CRC 保护的记录,把不透明的 Raft 证明绑定到元数据数据库的随机化身(incarnation)、物理 Slot 与 applied watermark,并与其业务变更原子地写入同一批次;
  • 挂起的快照安装标记、畸形记录或 watermark 不匹配都会拒绝复用;
  • 运行时快照、导入及其它未分类元数据批次会自动使证书失效。

对应实现见 pkg/slot/multiraft/checkpoint_proof.go 中的CheckpointState/RecoveryCheckpoint与 pkg/slot/multiraft/checkpoint_recovery.go 的CheckpointStateMachine接口(RecoveryState+PersistRecoveryCheckpoint)。

3. 精确 Raft 历史

  • 绑定集群/节点/Slot 身份、当前所有权、快照 index/term/内容摘要、配置边界与成员,并对每一介入条目(包括 noop 与配置条目)维护SHA-256 链;
  • 链必须验证到检查点,且保留的条目必须连续到持久化 commit;
  • 成员关系用现有 Raft 配置机制重建;
  • index 与 term 相同但命令字节不同必须拒绝复用——仅比较两个 applied index 不是有效的快速路径证明。

verifyCheckpointProof正是这条链的校验者:它要求条目从AppliedIndex+1连续推进、逐条更新日志摘要、用confchange.Restore恢复配置跟踪器,并在任一不连续或越界时返回 false(见 checkpoint_proof.go)。

检查点选择与回退

  • 只有显式启动栅栏(startup-fenced)的打开才允许复用验证过的检查点:它把 Raft 的 applied 与成员边界设到认证状态,并重放已提交的追加后缀;
  • 缺失、过期或不支持的证据走既有已验证快照路径;缺失已提交日志数据则失败关闭(fail closed);
  • 压缩只有在匹配的 Raft 快照持久化之后才发布替换的检查点锚点;两次发布之间崩溃则回退;
  • 运行时快照替换与维护保持既有准入与原子恢复行为。

选择逻辑在 pkg/slot/multiraft/checkpoint_recovery.go 的selectRecoveryCheckpoint:按checkpoint_reuse/checkpoint_fallback上报进度,reason区分missing_certificate、incompatible_certificate、live_open;无快照的兼容性恢复不会为未知存量数据签发证书。

进度可观测性:slot.recovery.progress

无论走哪条路径,恢复过程都通过 INFO 事件slot.recovery.progress可观测。事件字段包括nodeID、slotID、snapshotIndex、stage、bytes、totalBytes、entries、totalEntries、elapsed,以及存在分母时的percent;阶段边界立即打印,同阶段进度最多每五秒一次,没有每 Slot 的 ticker,日志不含 UID、token 或记录内容。阶段包括open、snapshot_verify、log_load、snapshot_restore、snapshot_checksum、snapshot_validate、snapshot_prepare、snapshot_install、snapshot_installed、log_replay、complete(部分阶段对新建 Slot 或兼容适配器缺失),另外还有checkpoint_reuse与checkpoint_fallback。complete只表示启动时已提交后缀恢复完成,不等同于服务 ready。实现见 pkg/slot/multiraft/recovery.go,测试覆盖见 recovery_progress_test.go。

完成审计与实测证据

常规重启对比(流式恢复阶段)

来源:docs/reports/2026-09-27-startup-recovery.md。

版本内存限制结果ready 耗时产品 RSS 峰值全量记录核对
基线2 GiBOOM,未 ready1.54 秒时退出1,975 MiB未进行
基线4 GiB成功5.91 秒2,322 MiB3,000,000
流式恢复2 GiB成功6.50 秒553 MiB3,000,000
流式恢复4 GiB成功3.80 秒572 MiB3,000,000

成功用例均完成 257 次凭据验证;基线 2 GiB 的 cgroupoom_kill从 0 增至 1。报告明确:单次 ready 时间受 Controller/Slot 选举与缓存影响,不能用单次差异宣称稳定的启动延迟百分比收益;流式安装解决峰值内存但仍重写快照(ready 前进程写入约 451 MiB),这正是 checkpoint 要省掉的成本。

初始规模验证的 checkpoint-v2 候选

路径限制ready 耗时恢复阶段耗时RSS 峰值ready 前进程写入
旧数据首次升级,完整安装2 GiB5.91 秒2.14 秒518 MiB591 MiB
随后复用 checkpoint2 GiB5.40 秒0.24 秒126 MiB2.41 MiB
旧数据首次升级,完整安装4 GiB6.71 秒1.54 秒545 MiB575 MiB
随后复用 checkpoint4 GiB5.40 秒0.22 秒128 MiB2.40 MiB
安装期间 SIGKILL,重试完整安装2 GiB5.72 秒1.99 秒491 MiB603 MiB

五例均核对全部 3,000,000 条用户/设备记录并通过 257 次凭据验证、无 OOM;复用例日志确认未进入snapshot_install。首次升级仍需完整恢复,不能承诺升级第一次启动就省去快照写入。

最终交付二进制的 2 GiB 复测

路径ready恢复阶段RSS 峰值
首次升级28.30 秒13.820 秒465.8 MiB
再次启动复用5.70 秒0.238 秒144.2 MiB
中断后重试4.21 秒1.690 秒451.8 MiB

复测三例均核对全部 300 万记录并通过 257 次认证。注意首次升级的 28.30 秒与宿主 E2E 并发执行,报告明确不据此宣称稳定的首次升级延迟;复用检查点仍跳过快照安装,恢复阶段约 0.238 秒。

新写入开销(ABBA 试点)

相同 2 GiB / 4 CPU、空数据库、64 个并行公开导入批次,按 基线→候选→候选→基线 顺序各写入 25,000 个用户/设备:

顺序版本写入耗时用户/秒
1基线22.77 秒1,098
2checkpoint 候选22.52 秒1,110
3checkpoint 候选21.59 秒1,158
4基线22.36 秒1,118

结论:没有观察到新写入吞吐退化;但每版仅两次短样本,不能据此宣称吞吐提升或代表持续高负载稳定性。

启动 CPU 归因与诊断 overlay

基线启动 profile 共 3.76 秒 CPU 样本,runtime.memmove占 flat 21.28%,Slot 恢复调用链与后台压缩占用明显——与完整快照加载、复制、解码、重写路径一致;checkpoint 复用的启动 profile 共 0.71 秒,热点转为 CRC、SHA-256 与系统调用。两份 profile 均由观察到 ready 终止而非触发两分钟上限。归因使用完全相同的诊断专用 Go build overlay(基线与候选一致),从程序 init 开始到 harness 观察到 ready(两分钟上限)为止,输出范围/耗时/终止原因收据;插桩不进入产品源码,profile-only 用例不承担全量 inventory 验收。

兼容性限制(必须如实表述)

  • 无证书、无快照的遗留数据库(snapshotless legacy)保留既有 applied-watermark 恢复语义,在真实 compaction 建立锚点之前不会发布新证书;这不能描述为对任意旧/离线变更的完整无快照修复。
  • 原有动态 onboarding/send 场景在迁移前以ReasonAuthFail失败,基线与候选相同,不计入迁移覆盖;新增场景用显式创建的凭据验证迁移后重启。

审查与合入建议

独立的预 PR 复审(见 docs/reports/2026-09-27-startup-recovery-review.md)在 Standards 轴与 Spec 轴各修复并关闭了关键发现:多 Slot 首次升级/无快照邻居造成的证书连锁失效,以及旧写者 reseal 后休眠证书复活边界;修复后多 Slot 升级在第二次重启可逐 Slot 复用、无快照邻居不再拖累其他 Slot,未打开 Slot 的旧证书会在 reseal 前被同步清除。复审的最终结论是:基于证据具备进入代码审查与合并的资格,建议合并后在反馈环境灰度验证;实现、证据与限制全部交付在带日期的恢复报告中,实际合并或发布不属于本次完成的验证。项目知识库对整个过程的一致性摘要见 docs/development/PROJECT_KNOWLEDGE.md,Slot 元数据流的总览见 pkg/slot/FLOW.md。

总结

WuKongIM 的启动恢复走过了"有界流式恢复"(解决峰值内存)到"认证检查点快速重启"(在证明有效时跳过快照重写)两个阶段,并最终以 300 万用户/设备、真实 2/4 GiB 硬上限的 Linux 规模矩阵完成验收:基线在 2 GiB 下 OOM 被复现,优化候选全数通过全量库存核对与 257 次凭据认证,checkpoint 复用的恢复阶段仅约 0.2 秒、RSS 峰值降至约 126–144 MiB,且通过 SIGKILL 中断重试、三节点/四节点整集群重启、旧写者回退、多 Slot 旧版升级等一系列故障场景。支撑这一切的是三重独立证明——物理序列封条、原子 FSM 证据与精确 Raft 历史 SHA-256 链——以及"证书缺失/过期/不匹配一律回退到已验证快照路径"的保守策略。任何想在生产环境复用该快速路径的团队,都应先在本仓库对应的test/e2e/cluster/startup_recovery场景下跑通同样的门禁证据。

  • 即时通讯
  • 后端

【免费下载链接】WuKongIM

More than just IM 不只是即时通讯(IM)

项目地址:https://gitcode.com/gh_mirrors/wu/WuKongIM
点击查看免费下载

相关推荐

上一篇:RemoveWindowsAI 实测:把 Windows 11 的 Copilot、Recall 和 CBS 存储里的 AI 包连根清除
下一篇:Office RibbonX Editor:零代码定制Office界面的终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询