MongoDB Powercycle 测试机制全解析:双机断电循环压测的架构、命令与源码实现
MongoDB Powercycle 测试机制全解析双机断电循环压测的架构、命令与源码实现【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongoPowercycle 测试是 MongoDB 开源仓库resmoke 测试框架中用于验证 mongod 在反复经历断电—重启式崩溃后数据完整性与可恢复性的专项测试它在一台**控制机server与一台被测机client**之间协同工作周期性把远程机器上的 mongod 强行崩溃再拉起检验数据库能否在非正常关机后完成恢复。本文以仓库中的 buildscripts/resmokelib/powercycle/README.md 为主体结合resmokelib/powercycle包内全部源码与任务配置文件完整讲解 powercycle 的四个子命令、双机主循环、远程崩溃注入、数据备份校验与诊断收集机制读完即可独立配置并运行一套 powercycle 测试。Powercycle 是什么双机架构与核心思路Power cycling断电循环指先关闭硬件、再重新上电的过程。数据库在突然断电、内核崩溃等非正常关机场景下可能面临 WiredTiger 存储引擎未完成 checkpoint、日志未落盘等问题这正是存储恢复逻辑最容易出错的场景。Powercycle 测试因此被设计为跨两台机器运行server控制机运行在本地Evergreen 中即执行该任务的 localhost负责编排整个测试流程、通过 ssh 下发远程操作、执行本地校验。client被测机运行 MongoDB 服务端mongod被 server 周期性远程崩溃。在 Evergreen 中它由host.create命令动态创建与 localhost 使用相同 distro 规格。从 powercycle.py 的模块注释可以看到它的定位Tests robustness of mongod to survive multiple powercycle events——即验证 mongod 在多次断电事件中的存活与恢复健壮性。Powercycle 是 resmoke 框架的一个子命令SUBCOMMAND powercycle见init.py因此它的运行入口统一是buildscripts/resmoke.py。运行环境与前置准备运行 resmoke 的 powercycle 子命令要求Python 3.13 且配备 python venv 虚拟环境。README 推荐优先使用 mongodbtoolchain 提供的 python3。在 mongo 仓库根目录下按如下步骤创建并激活虚拟环境python3 -m venv python3-venv source python3-venv/bin/activate pip install -r buildscripts/requirements.txt如果虚拟环境已经创建好只需在每次运行前激活source python3-venv/bin/activate之后即可随时查看 powercycle 子命令的帮助信息python buildscripts/resmoke.py powercycle --help该子命令的主入口解析与分发位于 buildscripts/resmokelib/powercycle/init.py其内部通过PowercyclePlugin挂载了 4 个子子命令见_add_powercycle_commands()init.py。四个子命令总览Powercycle类通过run_option分发执行init.py共支持四个动作子命令枚举值作用入口实现powercycle setup-hostHOST_SETUP通过 ssh 准备远程被测机setup/init.pypowercycle runRUN在本地执行完整 powercycle 测试powercycle.pypowercycle save-diagnosticsSAVE_DIAG把远程诊断文件拷贝回本地主要供 Evergreen 使用save_diagnostics/init.pypowercycle remote-hang-analyzerREMOTE_HANG_ANALYZER在远程机上运行 hang analyzer主要供 Evergreen 使用remote_hang_analyzer/init.py其中只有run子命令需要进一步处理参数其余三个子命令不需要额外参数源码中_add_powercycle_commands()注释明确说明Only need to return run_parser for further processing; others dont need additional args。第一步准备远程主机setup-host在 Evergreen 中远程机由host.create命令创建会与 localhost 使用相同 distro并在后续步骤前建立初步连接确认其可用。随后执行python buildscripts/resmoke.py powercycle setup-hostsetup-host通过 ssh 在远程机上依次执行多组操作对应 setup/init.py 中的SetUpEC2Instance类其操作配置来自expansions.yml——该文件由 Evergreen 的expansions.write命令生成在 CI 中位于${workdir}的上一级目录本地复现时则放在当前工作目录见 powercycle_constants.py创建远程目录创建/log/powercycleREMOTE_DIR与/data/dbDB_PATH并设置属主与chmod -R 777权限Windows 上改用setfacl -s user::rwx,group::rwx,other::rwx。拷贝文件把etc、buildscripts、dist-test/bin若存在还包括dist-test/lib、uv.lock、pyproject.toml从本地拷贝到远程机确保被测机上拥有完整的 resmoke 脚本与 mongod 可执行文件。搭建远程 python venv使用 mongodbtoolchain 的 python默认/opt/mongodbtoolchain/v5/bin/python3.13可用expansions中的python覆盖创建venv_powercycleVIRTUALENV_DIR并通过uv sync --locked --all-groups --no-group powercycle-incompatible --no-install-project安装全部依赖组。部署 curator 采集器下载固定版本的curator二进制用于持续采集系统指标与进程指标输出到system.json与proc.json。Linux 上通过 crontab 的reboot条目在每次重启后自动重启采集Windows 上则注册为cygrunsrv服务。安装崩溃工具仅 Windows下载并解压 Sysinternals 的 NotMyFault。远程 ssh 操作本身的实现位于 lib/remote_operations.py统一支持三种原语copy_to本地 → 远程拷贝文件copy_from远程 → 本地拷贝文件shell在远程机上执行 shell 命令。RemoteOperations在初始化时即会发起一次ssh ... date探测_remote_access()remote_operations.py并对 Connection refused、Permission denied、System is booting up. 等已知 ssh 连接错误进行带重试的访问建立默认重试 5 次每次间隔 10 秒。第二步运行 Powercycle 测试runrun子命令在 localhost 上执行通过 ssh 向远程机下发远程操作并执行本地校验。README 给出的标准调用形式为python buildscripts/resmoke.py powercycle run \ --sshUserHost${user_name}${host_ip} \ --sshConnection-i ${ssh_public_key_file} \ --taskName${task_name}run 子命令的参数详解所有参数都在init.py 的add_subcommand()函数中定义按功能分为四组Test Options测试选项参数说明默认值--sshUserHost远程机 ssh 用户名/主机格式userhost必填无--sshConnection附加的 ssh 连接参数如-i ident.pem会追加到默认 ssh 连接选项之后空--taskNamepowercycle 任务名据此从任务配置文件中加载额外配置powercycle--sshAccessRetryCountssh 访问重试次数隐藏参数5MongoDB Options参数说明默认值--downloadUrl被测 tarball 的下载地址不指定时使用最新版 tarballlatestmongod Options隐藏参数由程序内部传递参数说明--mongodHost启动并连接 mongod 的主机由脚本内部填充不供用户指定--mongodPort当前使用的端口由脚本内部填充Program Options参数说明默认值--logLevel日志级别可选debug/info/warning/errorinfo--logFile日志输出文件缺省输出到 stdout无--remoteOperation标记本次调用为远程调用隐藏参数见下文False--rsyncDestrsync 目标目录二元组隐藏参数无remote_operations远程操作列表位置参数隐藏无README 特别指出当 powercycle 测试在远程机上执行远程操作时实际调用的是被拷贝到远程机上的同一份脚本。因此--remoteOperation、--mongodHost、--mongodPort、--rsyncDest这类参数是远程调用所需的内部参数不应在 localhost 上手动指定。main()在构造远程调用命令时会把本地调用中所有非默认值的选项原样转发给远程脚本并妥善处理含空格/引号的字符串值加引号与列表值join 成字符串见 powercycle.py。另外 README 记录了一个已知问题从mongod_options配置项解析--setParameter等 mongod 选项时存在处理不当的问题即 SERVER-47621。任务配置powercycle_tasks.yml--taskName的值用于在 buildscripts/resmokeconfig/powercycle/powercycle_tasks.yml 中查找对应的任务配置。该文件完整定义了每个任务可用的配置项配置项含义默认值name必填任务名须与--taskName匹配无crash_method崩溃方式internal整机崩溃或kill仅杀 mongod 进程internaltest_loops测试循环次数15seed_doc_num预置seed的文档数量10000write_concernmongod 的 writeConcern 设置YAML 字典{}read_concern_levelreadConcern 级别无fcv要设置的 Feature Compatibility Version支持特殊值last_lts解析为multiversionconstants.LAST_LTS_FCV无repl_set是否以副本集模式启动值为副本集名无mongod_options附加 mongod 启动参数见下方默认值其中mongod_options的默认值定义于 powercycle_constants.py为--setParameter enableTestCommands1 --setParameter logComponentVerbosity{storage:{recovery:2}} --storageEngine wiredTiger --wiredTigerEngineConfigString debug_mode[table_loggingtrue]PowercycleTaskConfig类powercycle_config.py负责把上述 YAML 解析为任务配置对象get_task_config()在本地/远程模式下会从不同路径加载配置远程模式读取远程机REMOTE_DIR下的拷贝见 powercycle_config.py。仓库内置了 8 个开箱即用的任务可作参考模板tasks: - name: powercycle # 默认任务 - name: powercycle_smoke # 冒烟3 轮循环、1000 文档 test_loops: 3 seed_doc_num: 1000 - name: powercycle_smoke_skip_compile test_loops: 3 seed_doc_num: 1000 - name: powercycle_kill_mongod # 仅杀 mongod不整机崩溃 crash_method: kill - name: powercycle_last_lts_fcv # 测试 last_lts FCV fcv: last_lts - name: powercycle_replication # 副本集模式 repl_set: powercycle - name: powercycle_replication_smalloplog # 副本集 小 oplog repl_set: powercycle mongod_options: --setParameter enableTestCommands1 --setParameter logComponentVerbosity{storage:{recovery:2}} --oplogSize 20 --storageEngine wiredTiger --wiredTigerEngineConfigString debug_mode[table_loggingtrue] - name: powercycle_syncdelay # 调整 syncdelay mongod_options: --setParameter enableTestCommands1 --setParameter logComponentVerbosity{storage:{recovery:2}} --syncdelay 10 --storageEngine wiredTiger --wiredTigerEngineConfigString debug_mode[table_loggingtrue] - name: powercycle_write_concern_majority # 强制 majority 写关注 write_concern: {w: majority}Powercycle 测试主循环11 步全流程测试的主实现位于 powercycle.py 的main()函数。main()启动时会注册atexit退出处理器与信号处理器用于超时时 dump 所有线程堆栈随后根据--remoteOperation决定是进入远程处理分支还是本地主循环远程分支直接调用remote_handler()执行用户指定的远程操作后退出本地分支构建REPORT_JSON报告文件report.json与退出码文件powercycle_exit.yml进入无限循环直到循环次数用尽或任一步骤失败。主循环的核心常量powercycle_constants.py包括标准端口STANDARD_PORT 20000、秘密端口SECRET_PORT 20001、数据库名power、集合名cycle、数据目录/data/db、备份目录/log/powercycle/beforerecovery-*与/log/powercycle/afterrecovery-*。每一轮测试循环源码中Main loop for running the powercycle test的注释powercycle.py按如下顺序执行Rsync 崩溃后的数据库第 2 轮起在恢复前把崩溃现场的数据备份到beforerecovery-N目录。rsync 命令为rsync -va --delete --quiet并排除diagnostic.data/metrics.interim*临时指标文件针对 Windows/Cygwin 下偶发的 No medium found 错误最多重试 5 次。在秘密端口20001启动 mongod 并等待恢复通过MongodControl管理服务Linux 上 fork、Windows 上以服务方式运行见 powercycle.py启动后轮询buildinfo/serverStatus确认服务可用第 1 轮还会额外执行set_fcv若配置了 fcv与seed_docs预置随机文档。本地校验金丝雀文档第 2 轮起用 pymongo 直连远程 mongod 的秘密端口检查上一轮崩溃前写入的 canary 文档是否仍然存在。本地校验集合可选调用 resmoke 对远程 mongod 执行集合校验jstests/hooks/run_validate_collections.js校验时设置skipValidationOnNamespaceNotFound: True与allowUncleanShutdowns: True——允许非正常关机是 powercycle 语义的关键。若第 1 轮就出现isMaster网络错误则按 ssh 故障处理很可能与 ssh 隧道/端口转发未就绪有关。在秘密端口关闭 mongod通过 mongo client 发送shutdown命令shutdown_mongod并等待进程真正停止wait_for_mongod_shutdown最多等 2 小时停止后再额外 sleep 60 秒等待文件 flush避免 rsync file has vanished 错误。Rsync 恢复后的数据库把恢复后的数据备份到afterrecovery-N目录。在标准端口20000启动 mongod。在本地启动 CRUD 与 FSM 客户端调用 resmoke 运行jstests/hooks/crud_client.jsCRUD 客户端与jstests/libs/fsm_serial_client.jsFSM 状态机客户端各默认 20 个并发客户端、每轮repeat 100次、以后台进程方式运行no_waitTrue日志分别写入crud_i.log/fsm_i.log。生成金丝雀文档用 pymongo 以jTruejournal 已落盘的写关注写入{x: time.time()}金丝雀文档mongo_insert_canarypowercycle.py作为下一轮恢复后校验的基准。崩溃远程服务器或杀掉 mongod按任务配置的crash_method执行crash_server整机崩溃或kill_mongod仅杀进程详见下一节。崩溃前会先 sleepCRASH_WAIT_TIME 随机抖动45 0~5 秒。Windows 上执行磁盘检查对非 C 盘的 NTFS 分区运行chkdsk跳过 C 盘是因为其偶发 Snapshot was deleted 错误且系统盘若能正常重启即可认为健康。循环退出条件只有两种循环次数达到test_loops或任一步骤失败。崩溃后还需重新建立 ssh 连接verify_remote_access并通过noop远程操作读取系统启动时间比对恢复后与崩溃后的开机时间确认真实发生了一次系统重启见 powercycle.py。每次循环结束时Processes.kill_all()清理所有客户端进程与临时配置文件。在 Windows 上源码对任务参数做了额外收敛powercycle.py循环次数上限 3 轮、CRUD/FSM 客户端各上限 10 个。远程操作实现remote_handler所有远程操作都通过remote_handler()powercycle.py执行。该函数在远程机上运行操作通过 ssh 调用远程拷贝的脚本每次仅执行一个操作操作列表由remote_operations位置参数给出按顺序依次执行、任一出错即返回。源码中的op_map完整映射了 README 列出的全部 11 种操作操作名行为实现要点noop什么都不做用于崩溃后验证 ssh 连通性并读取启动时间crash_server整机崩溃调用internal_crash()Windows 上用 NotMyFaultLinux 上通过 sysrq 触发kill_mongod无条件杀掉 mongod 进程Windows 用taskkill /f /im mongod.exeLinux 用pkill -9 mongod随后确保服务停止最多等 2 小时WiredTiger 干净关闭可能耗时 10 分钟以上install_mongod安装 mongod下载/解压 tarball支持.tgz/.zip/.msi并建立bin符号链接Windows 上还会chmod w数据/日志目录并调用set_windows_bootstatuspolicy关闭崩溃后开机提示start_mongod启动 mongod 进程先update()服务再启动若配置了repl_set则调用mongo_reconfig_replication初始化/重配副本集stop_mongod停止 mongod 进程等待进程真正退出shutdown_mongod用 mongo client 优雅关闭发送admin.command(shutdown, forceTrue)rsync_data备份 mongod 数据从/data/dbrsync 到目标目录必要时重命名seed_docs预置随机文档向power.cycle集合批量写入随机值文档{x: 随机数, doc: 随机字符串}单批最多 1 万条set_fcv设置 FCV发送setFeatureCompatibilityVersion命令需confirmTruecheck_diskWindows 磁盘检查对所有非 C 盘 NTFS 分区执行chkdsk其中internal_crash()powercycle.py是真·断电的实现Linux 上通过sudo tee /proc/sys/kernel/sysrq写入1、再向/proc/sysrq-trigger写入b以触发内核级立即重启相当于模拟控制台重启执行前还会wall广播 Server crashing nowWindows 上则调用notmyfault/notmyfaultc64.exe -accepteula crash 1。需要说明的是crash_server返回码在整机崩溃场景下必然非零因为 ssh 会话随崩溃中断因此main()中对internal方式会忽略其非零返回码只在输出中出现 ssh 错误时按故障处理。数据完整性校验体系Powercycle 对断电后数据是否完好的验证分三层金丝雀文档canary崩溃前以jTrue写关注写入一条带时间戳的文档恢复后从本地用 pymongo 查询该文档是否存在。mongo_validate_canary只要find_one(doc)能命中即算通过直白验证已确认落盘的写入在断电后必须存在。集合校验collection validation复用 resmoke 的run_validate_collections.js钩子对远程 mongod 全库校验并显式允许非正常关机场景allowUncleanShutdowns: True。FSM 状态机客户端fsm_serial_client.js在标准端口上持续执行状态机工作负载仅第 1 个 FSM 客户端开启集合校验与 CRUD 客户端一起模拟断电瞬间正在进行的写入流量从而把崩溃点落在写路径中间这一最恶劣场景纳入覆盖。第三步保存诊断信息save-diagnosticsrun结束后可用以下命令把远程机上的诊断文件拉回本地主要供 Evergreen 使用python buildscripts/resmoke.py powercycle save-diagnostics实现位于 save_diagnostics/init.py同样通过expansions.yml加载配置依次执行 6 个 ssh 操作执行顺序见init.py 的_exec_powercycle_save_diagnosticsgatherRemoteEventLogs仅 Windows用wevtutil qe导出 Application/Security/System 三个事件日志各最近 1 万条到/log/powercycle/eventlog/。README 特别解释了收集事件日志的价值它们曾揭示 mongod.exe 在反复崩溃测试中因无法打开文件而异常退出的根因。tarEC2Artifacts打包诊断产物为ec2_artifacts.tgz。成功时仅归档mongod.log失败时额外归档数据目录与全部 before/after 恢复备份Windows 失败时还包含事件日志。使用--ignore-failed-read容忍文件缺失。copyEC2Artifacts把ec2_artifacts.tgz从远程拷贝到本地。copyEC2MonitorFiles把 curator 采集的system.json与proc.json打成ec2_monitor_files.tgz拷回本地。gatherRemoteMongoCoredumps在远程机上查找所有*.coreLinux与*.mdmpWindows核心转储文件并集中到REMOTE_DIR。copyRemoteMongoCoredumps把核心转储文件拷回本地先用ls探测是否存在避免 scp 因文件缺失而重试报错。此外main()的exit_handler()powercycle.py在测试退出时会把测试结果写入report.json含status/exit_code/elapsed等字段与powercycle_exit.yml含退出码、以及 ssh 失败时的错误输出ec2_ssh_failure并统一杀掉所有残留进程、清理临时文件。这些文件也是 Evergreen 判定任务成败与定位 ssh 故障的重要依据。第四步远程 Hang Analyzer可选若怀疑远程机上的 mongod 发生挂起而非崩溃可运行python buildscripts/resmoke.py powercycle remote-hang-analyzer该命令remote_hang_analyzer/init.py通过 ssh 在远程机上激活 venv 后调用python buildscripts/resmoke.py hang-analyzer默认对dbtest,java,mongo,mongod,mongos,python,_test进程执行分析可用expansions覆盖输出到文件与 stdout可配合-c选项转储核心。分析前还会把本地的.debug/.dSYM/.pdb调试符号文件上传到远程机分析完成后把debugger*.*与核心转储文件拷回本地。该命令在expansions缺少private_ip_address时直接跳过。关键常量与调优速查以下常量集中在 powercycle_constants.py是理解与调优测试行为的关键常量值说明STANDARD_PORT/SECRET_PORT20000/20001常规端口 / 恢复验证用秘密端口REMOTE_DIR/log/powercycle远程机上所有产物与脚本的根目录DB_PATH/data/dbmongod 数据目录DB_NAME/COLLECTION_NAMEpower/cycle金丝雀与 seed 文档所在库/集合CRASH_WAIT_TIME/CRASH_WAIT_TIME_JITTER45/5崩溃前等待秒数及随机抖动NUM_CRUD_CLIENTS/NUM_FSM_CLIENTS20/20并发 CRUD / FSM 客户端数量DEFAULT_TEST_LOOPS/DEFAULT_SEED_DOC_NUM/DEFAULT_CRASH_METHOD15/10000/internal循环数、seed 文档数、默认崩溃方式DEFAULT_SSH_CONNECTION_OPTIONS见源码含ServerAliveCountMax10、ServerAliveInterval6、StrictHostKeyCheckingno、ConnectTimeout30、GSSAPIAuthenticationno等面向 AWS 实例间直连的优化项RSYNC_EXCLUDE_FILESdiagnostic.data/metrics.interim*rsync 备份时排除的临时指标文件小结Powercycle 测试以双机 周期性整机崩溃 前后备份比对的方式把数据库恢复逻辑置于真实断电场景下反复锤炼。从 README.md 定义的四个子命令出发其完整能力链是setup-host准备远程被测机 →run执行 11 步主循环含崩溃注入、金丝雀校验、集合校验、CRUD/FSM 客户端压测与前后备份→save-diagnostics收集崩溃产物 →remote-hang-analyzer排查挂起问题。任务行为则由 powercycle_tasks.yml 中的crash_method、test_loops、repl_set、mongod_options等配置项灵活定制。对于需要验证存储引擎恢复健壮性、或想在 CI 中持续回归断电安全特性的团队而言这套机制既是开箱即用的测试工具也是理解 WiredTiger 恢复语义与崩溃一致性测试设计的绝佳参考实现。【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考