写点什么

LinkedIn 如何发现导致系统反复死机的内核锁竞争问题

作者:Sergio De Simone
  • 2026-06-02
    北京
  • 本文字数:1226 字

    阅读完需:约 4 分钟

LinkedIn 的工程师们遇到了一种短暂且反复出现的故障,即支撑用户信息流的数据库会突然不可用,随后又恢复正常,而且没有留下任何有用的痕迹。他们不得不设计一种新方法,利用 eBPF 进行离线 CPU 性能分析(off-CPU profiling)来查明根本原因。

正如 LinkedIn 工程师 Pratikmohan Srivastav 所介绍的那样,调查这些事件尤为困难,因为它们转瞬即逝,仅持续 10 到 15 秒,而且未留下任何有用的日志。此外,该类事件反复发生,既无明显规律,也未显示出明确的外部触发因素。

通过将这些事件与系统内存行为进行关联,他们初步发现了一个线索:每个事件都伴随着内存分配的短暂激增,然后迅速恢复,系统在更高的基准水平上趋于稳定。进一步分析排除了其他常见的原因,包括 CPU 降频、内存碎片化和压缩以及文件 I/O。

因此,基于常规监控和指标的分析未能触及问题的根本原因,这促使 LinkedIn 工程师深入探究了系统冻结期间操作系统和运行时层面的行为。他们转而采用离线 CPU 性能分析方法来了解当时哪些线程被阻塞了。

我们的解决方案是构建一种监控机制。我们编写了一个监控脚本,一旦检测到系统卡死,该脚本就会立即自动进行离线 CPU 性能分析。

该脚本的工作原理如下:

该脚本使用了一个名为 BCC 的 eBPF 工具包,用于持续监控数据库健康状况,并在检测到异常时立即触发 BCC 的 offcputime.py 分析器,记录被阻塞或处于休眠状态的线程在 15 秒钟内的内核堆栈跟踪信息。

这使得 LinkedIn 的工程师们能够在系统实时冻结期间捕获离线 CPU 性能分析信息:

这是关键的突破口。这些事件发生得太过短暂,常规监控无法捕捉其根本原因,因此要观察根本原因,唯一的方法就是在系统冻结开始时,用已经部署好的性能分析工具获取当时的信息。

经排查,根本原因在于一次约 3.5 GB 的大规模内存分配,这导致 mmap_lock 信号量在内核级被锁定,从而阻塞了所有线程。

任何修改进程虚拟地址空间的操作(如大规模的 mmap 分配)都必须以写模式持有此锁。在持有写锁期间,所有需要进行内存操作的其他线程(包括用于清理的 madvise 以及用于 I/O 的页面故障处理)都会被阻塞。

进一步分析发现,这次内存分配是由 Rust 内存中的 HashMap(pkey_vs_docref)触发的。该 HashMap 负责将主键映射到内部文档引用。当条数超过 58,720,256 时,达到了调整大小阈值,进行了翻倍操作。

查明根本原因之后,LinkedIn 工程师便通过预分配 HashMap 的方式迅速地解决了该问题,避免了运行期间的调整操作。这一措施会导致启动时额外占用约 3 GB 的驻留内存,但事实证明这是一个可以接受的权衡。

Srivastav 指出,这一事件揭示了几个重要的教训:预分配大型数据结构有助于防止延迟敏感路径中出现突发的内存激增;基于 eBPF 的离线 CPU 性能分析是诊断“无声死机”(这类故障几乎不留痕迹)的强大工具;对于瞬时性问题,在发生故障时可以自动触发的自动化监控机制,对于在问题发生时捕获有意义的诊断信息至关重要。

原文链接:https://www.infoq.com/news/2026/05/linkedin-kernel-lock-freeze/