【免费下载链接】BqLog
A lightweight, high-performance, industrial-grade cross-language logging library (C++/Java/C#/Kotlin/TS/Python/Go), battle-tested in Honor of Kings.
进程突然崩溃,最关键的那几条日志却"凭空消失"了——这是每个写日志的人都踩过的坑。BqLog 是一个轻量级、高性能的工业级跨语言日志库(支持 C++/Java/C#/Kotlin/TypeScript/Python/Go),已在《王者荣耀》等生产环境稳定运行。它通过内置的Recovery(数据恢复)机制,让异步缓冲区里还没来得及落盘的日志,在进程下次启动时"起死回生",尽量找回崩溃前丢失的数据。
💡 一句话概括:开启
log.recovery后,日志先进入内存映射文件(mmap)暂存,崩溃时数据仍在,重启后校验并依序回放到日志文件。
为什么崩溃时日志会"凭空消失"
要理解恢复机制,先要明白数据为什么会丢。
BqLog 默认采用异步模式:业务线程把日志写入一块共享缓冲区(环形缓冲),由后台的日志线程统一落盘。这样主流程几乎零阻塞,性能极佳。
但问题在于——缓冲区是内存里的数据。当进程崩溃、被kill -9或断电时:
- 缓冲区里还积压着尚未写入磁盘的日志;
- 操作系统不会替你把内存里的脏数据抢救出来;
- 这些日志就彻底丢失了。
如果这次崩溃恰好发生在"复现问题的关键时刻",丢失的日志往往就是最要命的那几行。BqLog 的 Recovery 机制,正是为了堵住这个缺口。
一键开启:如何配置 log.recovery
恢复能力由一个配置项控制,开箱即用。
在日志配置中加入:
log.recovery=true| 取值 | 行为 |
|---|---|
log.recovery=true | 程序异常退出时,缓冲区中尚未落盘的数据会在下次启动后重新写入日志文件 |
log.recovery=false(默认) | 进程异常退出且未手动force_flush()时,缓冲中的数据将丢失 |
配置项的详细说明可参考 CONFIGURATION_CHS.md,其中对log.recovery有一段专门的行为描述。
⚠️ 需要提醒:恢复依赖平台的mmap与跨进程文件锁。少数平台(例如 Solaris)不具备这两项能力,此时配置会被忽略,日志照常工作,只是不开启恢复,并打印一条警告:
[Bq]log <name>: recovery needs a cross-process file lock and this platform has none, so recovery stays offRecovery 机制原理:mmap 存根 + 崩溃后回放
BqLog 恢复机制的核心思路非常朴素:把"内存缓冲区"变成"磁盘上的临时存根",用空间换数据。
1. 崩溃现场:未落盘的数据留在哪里
当启用恢复后,BqLog 会把缓冲区内容同时映射到一组.mmap文件里。进程一旦崩溃,这些文件依然完整保留在磁盘上,未消费的数据就"冻结"在文件里。
恢复所需的存储目录由 log_storage.cpp 统一管理,典型结构如下:
<log_name>/ ├── lp.mmap # 低优先级缓冲(MISO 环形缓冲) ├── hp/ │ └── <index>.mmap # 高优先级缓冲,一个 Group 一个文件 ├── os/ │ └── <index>.mmap # 超大记录(oversize)单独存放 └── appenders/ └── <appender>.mmap # 各 Appender 的已编码写缓存2. 重启回放:校验、丢弃、依序重建
进程重启后,BqLog 进入"复盘"阶段,流程分四步:
- 逐文件校验和:对每个
.mmap文件做完整性校验(checksum)。好的整块保留,崩溃瞬间写了一半的"半成品"直接作废,绝不带着脏数据继续; - 版本递增:例如从
v7推进到v8,让同一版本内的"剩余记录"自动失效,避免误读旧数据; - 扫描旧记录:按线程本地序号(per-thread seq)建立最小序号表,用 16 位索引把数据块重新串联起来;
- 依序回放:严格按每个线程的序号顺序,把有效记录回放进新日志文件的"恢复段",随后切回实时写入(live writing)。
整个回放与错误标记逻辑由 log_imp.cpp 与 log_record_reader.cpp 驱动:读取缓冲时一旦发现无效数据,会生成"恢复错误"标记,交由 Appender 处理。
3. 两种残留数据,两条恢复路径
崩溃后剩下的数据并非同一种状态,BqLog 用两条路径分别处理,这正是它能"既正确又高效"的关键:
- 已编码的缓存项(Appender cache):这类日志已经完成了模板绑定与编码,语义完整。回放时直接追加到原日志文件末尾的"恢复段",沿用旧段落的模板字典,只是加密材料换新——因为解码器会先读旧段,模板与时间基线都已知。
- 从未编码的记录(Bus 记录):这类日志还停留在"原始格式串 + 原始参数",尚未绑定模板。由于从未编码,从头重新编码是绝对安全的,于是写入新文件(新流),模板从索引 0 重建。
这种"能续接的续接、不能续接的重建"的分流策略,保证了无论崩溃发生在哪一步,恢复都不会产生脏数据。
平台支持:如何查询恢复能力
并非所有系统都满足恢复的前置条件。BqLog 提供跨语言的get_recovery_capability()接口,让宿主程序在运行时主动探测当前平台到底支持到什么程度,再决定 UI 或策略。
实现见 log_utils.h,判断逻辑非常清晰——先看有没有 mmap,再看有没有跨进程文件锁:
recovery_capability log_utils::get_recovery_capability() { if (!bq::memory_map::is_platform_support()) return recovery_capability::no_memory_map; // 缺内存映射 if (!bq::platform::is_cross_process_file_lock_supported()) return recovery_capability::no_instance_lock; // 缺跨进程锁 return recovery_capability::ready; // 全齐,可恢复 }返回三种枚举值:
| 枚举值 | 含义 |
|---|---|
ready | 平台完全支持,恢复可用 |
no_memory_map | 缺少内存映射,无法恢复 |
no_instance_lock | 缺少跨进程文件锁,无法恢复 |
以 POSIX 为例,内存映射的支持判断见 memory_map_posix.cpp(Linux / Android / Apple / Unix 均返回true)。
调用方式(以 C++ 为例,其余语言同名 API):
bq::recovery_capability capability = bq::log::get_recovery_capability();完整的多语言调用示例见 API_REFERENCE_CHS.md。
补充:POSIX 异常信号兜底处理
除了"事后恢复",BqLog 还提供了一个事前补救手段——enable_auto_crash_handle()。
调用它之后,BqLog 会在POSIX 系统上通过sigaction注册信号处理器:
- 当进程收到
SIGABRT、SIGSEGV、SIGBUS等异常信号时,在信号回调里强制刷新缓冲区(force_flush_all_logs); - 注册前会保存旧的信号处理句柄,处理完再调用原逻辑,尽量不干扰宿主程序。
需要清醒认识它的边界:
- 这本质是紧急补救,不保证 100% 成功——如果内存本身已被严重破坏,任何操作都可能失败;
- 该机制仅对 POSIX 平台生效,Windows 上不会启用。
因此,最佳实践是两者并用:enable_auto_crash_handle()争取"当场抢救",log.recovery=true兜底"重启复盘",双保险最大化数据存活率。
总结
BqLog 的 Recovery 机制用一句话就能讲清:把内存缓冲区落到 mmap 存根,崩溃后逐文件校验、丢弃半成品、按线程序号依序回放到日志文件的恢复段。
它的价值在于三点:
- ✅数据不丢:崩溃前未落盘的日志,重启后可找回;
- ✅不产生脏数据:校验和 + 版本递增,坏的整块作废;
- ✅跨语言开箱即用:一个配置项开启,
get_recovery_capability()即可探测支持度。
如果你正在为"崩溃日志丢失"头疼,不妨在配置里加上log.recovery=true——这是工业级日志库该有的底线能力。更多原理细节可阅读 ADVANCED_USAGE_CHS.md 的"程序异常退出的数据保护"章节,以及 PERFORMANCE_DESIGN.md 系列文章中关于崩溃恢复的深入图解。
【免费下载链接】BqLog
A lightweight, high-performance, industrial-grade cross-language logging library (C++/Java/C#/Kotlin/TS/Python/Go), battle-tested in Honor of Kings.
相关推荐
KeyCastr崩溃恢复机制:应用异常退出后的状态恢复方案
KeyCastr崩溃恢复机制:应用异常退出后的状态恢复方案 引言:痛点与解决方案概述 作为一款开源的按键可视化工具(KeyCastr, an open sour
桌面应用从崩溃到恢复:Apache Kafka 3.1日志自愈机制深度解析
从崩溃到恢复:Apache Kafka 3.1日志自愈机制深度解析 日志恢复的重要性 你是否遇到过Kafka集群意外宕机后数据丢失的情况?作为分布式消息系统的核
消息队列流处理数据集成存储de4dot异常处理机制:ExitException与错误恢复策略
de4dot异常处理机制:ExitException与错误恢复策略 引言:.NET反混淆工具的异常处理挑战 在.NET反混淆(Deobfuscation)领域,
逆向工程开发工具CLI应用安全静态分析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考