7.8 KiB
7.8 KiB
崩溃保护与 MTBF 统计设计文档
概述
本文档描述服务端代理进程的崩溃保护机制和可靠性统计功能。
功能目标
- 崩溃保护:防止代理进程连续崩溃导致的无限重启循环
- 崩溃统计:记录崩溃次数、时间、退出代码等信息
- MTBF 计算:收集数据用于计算平均故障间隔时间(Mean Time Between Failures)
一、崩溃保护机制
1.1 触发条件
| 参数 | 值 | 说明 |
|---|---|---|
| 窗口期 | 5 分钟 | CRASH_WINDOW_MS = 300000 |
| 阈值 | 3 次 | CRASH_THRESHOLD = 3 |
| 快速崩溃定义 | 30 秒内退出 | FAST_CRASH_TIME_MS = 30000 |
触发逻辑:在 5 分钟窗口期内,代理进程发生 3 次快速崩溃(启动后 30 秒内异常退出),则触发崩溃保护。
1.2 判定标准
只有同时满足以下条件才计入崩溃:
- 退出代码 ≠ 0(正常退出不计入)
- 运行时间 < 30 秒(长时间运行后退出不计入)
设计原则:程序正常退出必须返回 0,任何非 0 退出代码都视为异常退出。包括:
- Windows 异常(如
0xC0000005ACCESS_VIOLATION) - 自定义错误码(如
1001CONFIG_ERROR) - 其他非零退出码
1.3 保护行为
触发崩溃保护后:
- 服务停止自动重启代理进程
- 写入
AgentCrashProtected = 1到配置 - 下次程序启动时检测到此标志,切换到普通运行模式
- 弹出提示框告知用户
1.4 状态持久化
崩溃窗口状态持久化到注册表,确保服务重启后状态不丢失:
配置 section: [crash]
| 配置键 | 类型 | 说明 |
|---|---|---|
winCount |
int | 窗口期内崩溃次数 |
winStart |
string (uint64) | 窗口起始时间 (GetTickCount64) |
服务重启时的恢复逻辑:
加载保存的状态
↓
检查 savedFirstCrashTime <= 当前时间?
├─ 否 → 系统重启过,清除状态
└─ 是 → 检查是否仍在 5 分钟窗口内?
├─ 否 → 窗口已过期,清除状态
└─ 是 → 恢复状态,继续计数
注意:GetTickCount64() 在系统重启后会重置为 0,因此如果保存的时间戳大于当前时间,说明系统重启过,需要清除状态重新开始。
二、崩溃统计
2.1 记录内容
每次崩溃时记录以下信息(section: [crash]):
| 配置键 | 类型 | 说明 | 示例 |
|---|---|---|---|
count |
int | 总崩溃次数 | 15 |
lastTime |
string | 最后崩溃时间 | "2024-01-15 10:30:45" |
lastCode |
string | 最后退出代码 | "0xC0000005 (ACCESS_VIOLATION)" |
lastRunMs |
string (uint64) | 最后运行时间(ms) | "25000" |
2.2 退出代码描述
常见的 Windows 异常代码:
| 代码 | 描述 |
|---|---|
0xC0000005 |
ACCESS_VIOLATION(访问违规) |
0xC0000094 |
INTEGER_DIVIDE_BY_ZERO(整数除零) |
0xC00000FD |
STACK_OVERFLOW(栈溢出) |
0xC0000409 |
STACK_BUFFER_OVERRUN(栈缓冲区溢出) |
0xC000001D |
ILLEGAL_INSTRUCTION(非法指令) |
0x80000003 |
BREAKPOINT(断点) |
正常退出:
| 代码 | 描述 |
|---|---|
0 |
NORMAL(正常退出) |
自定义错误代码(1000-1999):
| 代码 | 描述 |
|---|---|
1001 |
CONFIG_ERROR(配置错误) |
1002 |
NETWORK_ERROR(网络错误) |
1003 |
AUTH_FAILED(认证失败) |
1004 |
RESTART_REQUEST(请求重启) |
1005 |
MANUAL_STOP(手动停止) |
三、MTBF 统计
3.1 数据收集
| 配置键 | 类型 | 说明 |
|---|---|---|
starts |
int | 启动次数 |
totalRunMs |
string (uint64) | 累计运行时间(ms) |
count |
int | 崩溃次数 |
注意:totalRunMs 和 lastRunMs 使用字符串存储 64 位整数,避免 32 位整数的限制(最大约 49 天)。
3.2 计算公式
MTBF(平均故障间隔时间):
MTBF = 累计运行时间 / 崩溃次数
失败率(Failure Rate):
失败率 = 崩溃次数 / 启动次数
3.3 示例
假设:
- 启动次数:100 次
- 崩溃次数:5 次
- 累计运行时间:30 天
计算结果:
- MTBF = 30 天 / 5 = 6 天(平均每 6 天发生一次崩溃)
- 失败率 = 5 / 100 = 5%(每次启动有 5% 概率崩溃)
四、回调函数设计
4.1 回调类型
| 回调 | 触发时机 | 参数 |
|---|---|---|
onAgentStart |
代理进程启动成功 | processId, sessionId |
onAgentExit |
代理进程退出(任何原因) | exitCode, runtimeMs |
onCrash |
检测到快速崩溃 | exitCode, runtimeMs |
onCrashWindowChange |
崩溃窗口状态变化 | crashCount, firstCrashTime |
onCrashProtection |
触发崩溃保护 | 无 |
4.2 调用顺序
正常退出:
onAgentExit(exitCode=0, runtime)
快速崩溃:
onAgentExit(exitCode, runtime)
↓
onCrash(exitCode, runtime)
↓
[如果 count >= 3]
onCrashProtection()
↓
onCrashWindowChange(count, startTime)
五、配置键汇总
Section: [crash]
| 配置键 | 类型 | 用途 | 持久性 |
|---|---|---|---|
count |
int | 总崩溃次数 | 永久 |
lastTime |
string | 最后崩溃时间 | 永久 |
lastCode |
string | 最后退出代码 | 永久 |
lastRunMs |
string | 最后运行时间 | 永久 |
totalRunMs |
string | 累计运行时间 | 永久 |
starts |
int | 启动次数 | 永久 |
winCount |
int | 窗口期崩溃次数 | 临时* |
winStart |
string | 窗口起始时间 | 临时* |
protected |
int | 崩溃保护标志 | 一次性** |
* 临时:窗口期过期或系统重启后自动清除 ** 一次性:程序启动时读取并清除
六、文件改动
| 文件 | 改动内容 |
|---|---|
CrashReport.h |
配置键定义、退出代码常量、MTBF 计算函数 |
ServerSessionMonitor.h |
回调类型定义、监控器结构体 |
ServerSessionMonitor.cpp |
崩溃检测逻辑、回调调用 |
ServerServiceWrapper.cpp |
回调实现、状态持久化/恢复 |
2015Remote.cpp |
启动时检查崩溃保护标志 |
七、使用场景示例
场景 1:连续崩溃
T=00:00 代理启动 (startCount=1)
T=00:05 代理崩溃 (crashCount=1, 窗口开始)
T=00:10 代理重启 (startCount=2)
T=00:15 代理崩溃 (crashCount=2)
T=00:20 代理重启 (startCount=3)
T=00:25 代理崩溃 (crashCount=3, 触发保护!)
→ 服务停止重启代理
→ 写入 AgentCrashProtected=1
T=00:30 用户手动启动程序
→ 检测到保护标志,切换到普通模式
→ 弹出提示框
场景 2:服务重启后恢复
T=00:00 代理崩溃 (crashCount=1)
T=00:30 代理崩溃 (crashCount=2, 保存到注册表)
T=01:00 服务重启(非系统重启)
→ 加载状态: count=2, elapsed=1分钟
→ 仍在5分钟窗口内,恢复状态
T=01:30 代理崩溃 (crashCount=3, 触发保护!)
场景 3:窗口过期
T=00:00 代理崩溃 (crashCount=1)
T=02:00 代理崩溃 (crashCount=2)
T=08:00 代理崩溃
→ 距离第一次崩溃已超过5分钟
→ 重置窗口: crashCount=1, 新窗口开始
八、设计决策记录
| 问题 | 决策 | 理由 |
|---|---|---|
| 窗口期时长 | 5 分钟,不可配置 | 足够检测连续崩溃,避免误判 |
| 崩溃阈值 | 3 次,不可配置 | 平衡敏感度和容错 |
| 快速崩溃定义 | 30 秒 | 覆盖大多数初始化场景 |
| 系统重启处理 | 清除窗口状态 | 系统重启后问题可能已修复 |
| 统计数据重置 | 暂不实现 | 需求不明确,后续按需添加 |
| 日志记录 | 使用 Mprintf | 与现有日志系统一致 |
| 非零退出码 | 都算崩溃 | 正常退出必须返回 0 |
| lastRunMs 类型 | string (uint64) | 支持超过 24 天的运行时间 |