文章摘要
文章讲述了作者在使用async-profiler工具调试QuestDB数据库性能时,意外触发了Linux内核的一个bug导致机器冻结。尽管作者并非内核开发者,但仍深入研究了内核源代码以定位问题根源。这反映了开源数据库QuestDB在性能优化过程中遇到的技术挑战,以及开发者对问题追根究底的态度。
文章总结
内核漏洞导致机器冻结:调试Async-profiler死锁问题
问题背景
作者在使用Linux系统时,发现每当运行async-profiler工具时,机器会完全冻结。该问题出现在Ubuntu 25.10和Fedora系统中,均使用6.17版本的内核。经过排查,确认这是一个内核漏洞,与perf_events子系统的hrtimer处理有关。
问题复现与定位
- 现象:当尝试使用async-profiler进行CPU性能分析时,机器无响应,只能强制重启。
- 排查过程:
- 排除QuestDB集成代码的问题,确认问题与环境相关。
- 发现Ubuntu 25.10和Fedora均使用6.17内核,且旧版本系统无此问题。
- 通过Google搜索,找到类似问题的报告,并定位到相关内核补丁。
内核漏洞分析
- 根本原因:内核提交
18dbcbfabfff修复了另一个漏洞,但引入了cpu-clock事件处理的死锁问题。- 当
PERF_EVENT_IOC_REFRESH(1)计数器归零时,hrtimer_cancel()在回调函数内部被调用,导致无限等待。
- 当
- 死锁流程:
hrtimer触发perf_swevent_hrtimer()。__perf_event_overflow()决定停止事件,调用cpu_clock_event_stop()。cpu_clock_event_stop()调用hrtimer_cancel(),而当前正在执行回调函数,导致死锁。
解决方案
- 临时规避:使用
-e ctimer选项启动async-profiler,避免触发有问题的内核功能。 - 内核修复:
- 将
hrtimer_cancel()替换为非阻塞的hrtimer_try_to_cancel()。 - 使用
PERF_HES_STOPPED标志作为延迟停止信号,确保定时器最终停止。
- 将
内核调试实践
作者通过QEMU模拟环境复现问题,并利用GDB调试内核:
1. 环境搭建:在QEMU中安装Ubuntu 25.10,并禁用KASLR以方便调试。
2. 调试过程:
- 使用GDB连接QEMU的内核调试服务器,查看死锁时的线程堆栈。
- 确认hrtimer_cancel()在回调函数内部被调用,导致死锁。
3. 尝试修复:通过GDB强制修改寄存器值,试图解除死锁,但未完全成功。
结论与建议
- 用户建议:在6.17内核版本中,使用
-e ctimer选项进行性能分析,或等待内核修复。 - 技术收获:作者通过本次调试深入理解了Linux内核的
perf_events和hrtimer机制,并掌握了内核调试的基本方法。
后续尝试
在后续实验中,作者通过GDB直接修改内核内存,强制终止Java进程并解除死锁,成功恢复了系统响应。尽管这种方法不适用于生产环境,但为理解内核行为提供了宝贵经验。
注:本文保留了关键的技术细节和调试过程,删减了部分实验失败的冗余描述,突出了问题定位和解决的主线。
评论总结
以下是评论内容的总结:
作者自述
作者表示对内核感兴趣但无实际经验,认为本文是了解内核内部的一种实践方式。
引用:
"Consider this either a collection of impractical party tricks or a hands-on way to get a feel for kernel internals."
"我一直对内核感到好奇,尽管从未亲自参与过相关工作。"技术分享与推荐
有评论推荐了async-profiler的热图功能及Netflix相关技术博客,认为这些工具能帮助发现时间模式。
引用:
"these heatmaps make it much easier to see patterns over time"
"热图能更轻松地观察时间模式"代码缺陷讨论
有评论指出代码中运算符优先级可能导致的bug,建议使用括号明确逻辑。
引用:
"The bug being that the precedence of || is higher than the precedence of != ?"
"||的优先级高于!=,这是否是个bug?"内核复杂性批评
有评论认为Linux内核过于复杂,存在许多未发现的bug,推荐seL4作为替代方案。
引用:
"with the complexity of the Linux kernel, this is definitely not the only bug"
"Linux内核如此复杂,这肯定不是唯一的bug"实际使用问题
用户报告在高负载Docker环境下偶发内核死锁问题,但难以复现。
引用:
"it leads to a complete deadlock somewhere inside of the kernel"
"导致内核某处完全死锁"工具建议
有评论建议使用bpftrace进行调试,认为比qemu+gdb更高效。
引用:
"That would be less effort than qemu + gdb"
"这比qemu+gdb省力"文章评价
多位读者称赞文章是优秀的"调试历程"记录,并提到该问题曾导致Minecraft系统冻结。
引用:
"This kind of 'debugging journey' post is gold"
"这种'调试历程'文章很有价值"
"the bug that froze the system when Minecraft was running"
"这个bug曾导致运行Minecraft时系统冻结"