Redis CPU 分析

CPU 上分析和跟踪的性能工程指南

Redis 堆栈 Redis 社区版

填写性能检查清单

Redis 的开发非常重视性能。我们尽最大努力 每个版本,以确保您体验到非常稳定和快速的产品。

不过,如果你正在寻找提高 Redis 或 正在进行性能回归调查,您将需要一个简洁的 监控和分析 Redis 性能的方法。

为此,您可以依赖不同的方法(有些方法比其他方法更适合 取决于我们打算制作的问题/分析的类别)。精选列表 的方法及其步骤由 Brendan Greg 在以下链接中列举。

我们建议使用利用率饱和和错误 (USE) 方法进行回答 你的瓶颈是什么的问题。检查以下 系统资源、指标和工具进行实际深入研究:USE 方法

确保 CPU 是您的瓶颈

本指南假定您已按照上述方法之一执行 完成系统运行状况检查,并确定瓶颈是 CPU。如果您已确定大部分时间都花在 I/O 上,则锁定、 timers、paging/swapping 等,本指南不适合您

构建先决条件

为了进行适当的 CPU 上分析,Redis(以及任何动态加载的库,如 Redis Modules)要求堆栈跟踪可供跟踪器使用,您可以 需要先修复。

默认情况下,Redis 是使用-O2switch 的 在分析期间)。这意味着启用了编译器优化。多 编译器省略帧指针作为运行时优化(保存寄存器), 从而打破了基于帧指针的堆栈遍历。这使得 Redis executable 更快,但同时它使 Redis(就像任何其他程序一样) 更难追踪,可能会错误地将 CPU 上的时间精确定位到最后一个 可用的帧指针,该指针可以变得更深(但 无法追踪)。

请务必确保:

  • 存在调试信息:编译选项-g
  • 存在帧指针寄存器:-fno-omit-frame-pointer
  • 我们仍然使用优化来准确表示生产运行时间,这意味着我们将保留:-O2

您可以在 redis main repo 中执行以下作:

$ make REDIS_CFLAGS="-g -fno-omit-frame-pointer"

一组用于识别性能回归和/或潜在的 CPU 性能改进的工具

本文档特别关注 CPU 上的资源瓶颈分析。 这意味着我们有兴趣了解线程在哪些方面花费了 CPU 周期 在 CPU 上运行时,同样重要的是,这些周期是否有效 用于计算或停止等待(未阻塞)内存 I/O, 和缓存未命中等。

为此,我们将依赖工具包(perf、bcc 工具)和特定于硬件的 PMC (性能监控计数器),以继续:

  • 热点分析(perf 或 bcc 工具):分析代码执行并确定哪些函数消耗的时间最多,因此是优化的目标。我们将提供两个选项来使用 perf 或 bcc/BPF 跟踪工具收集、报告和可视化热点。

  • 调用计数分析:对包括函数调用在内的事件进行计数,使我们能够一次关联多个调用/组件,依靠 bcc/BPF 跟踪工具。

  • 硬件事件采样:对于了解 CPU 行为至关重要,包括内存 I/O、停顿周期和缓存未命中。

工具先决条件

以下步骤依赖于 Linux perf_events(又名“perf”)、bcc/BPF 跟踪工具和 Brendan Greg 的 FlameGraph 存储库

我们假设您事先有:

  • 已在系统上安装 perf 工具。大多数 Linux 发行版可能会将其打包为与内核相关的包。有关 perf 工具的更多信息,请访问 perf wiki
  • 按照安装 bcc/BPF 说明在您的计算机上安装 bcc toolkit。
  • 克隆了 Brendan Greg 的 FlameGraph 存储库,并使其可访问difffolded.plflamegraph.pl文件生成折叠的堆栈轨迹和火焰图。

使用 perf 或 eBPF 进行热点分析(堆栈跟踪采样)

通过定时对堆栈跟踪进行采样来分析 CPU 使用率是一种快速且 识别性能关键型代码段 (热点) 的简单方法。

使用 perf 对堆栈跟踪进行采样

要分析特定 redis-server 的用户级和内核级堆栈 采样频率为 999 个样本的时间长度,例如 60 秒 每秒:

$ perf record -g --pid $(pgrep redis-server) -F 999 -- sleep 60

使用 perf report 显示记录的配置文件信息

默认情况下,perf 记录会在当前 目录。

然后,您可以使用调用图输出(调用链、堆栈回溯)、 最小调用图包含阈值为 0.5%,其中:

$ perf report -g "graph,0.5,caller"

请参阅 perf report 文档,了解高级筛选、排序和聚合功能。

使用 Flame Graphs 可视化记录的配置文件信息

火焰图允许快速 以及频繁代码路径的准确可视化。它们可以使用 Brendan Greg 在 github 上的开源程序, ,它们从折叠的堆栈文件创建交互式 SVG。

具体来说,对于 perf,我们需要将生成的 perf.data 转换为 捕获的堆栈,并将其每个堆栈折叠成单行。然后,您可以渲染 CPU 上的火焰图,其中包含:

$ perf script > redis.perf.stacks
$ stackcollapse-perf.pl redis.perf.stacks > redis.folded.stacks
$ flamegraph.pl redis.folded.stacks > redis.svg

默认情况下,perf 脚本会在当前 worker 中生成一个 perf.data 文件 目录。请参阅 perf 脚本文档 了解高级用法。

请参阅 FlameGraph 使用选项,了解更高级的堆栈跟踪可视化效果(如差分可视化效果)。

存档和共享录制的配置文件信息

这样就可以在 other 机器上分析 perf.data 内容 而不是发生集合的那个,您需要与 perf.data 文件,并在记录数据文件中找到具有 build-ID 的所有对象文件。 这可以在 perf-archive.sh 脚本的帮助下轻松完成:

$ perf-archive.sh perf.data

现在请运行:

$ tar xvf perf.data.tar.bz2 -C ~/.debug

在需要运行的机器上perf report.

使用 bcc/BPF 的配置文件对堆栈跟踪进行采样

与 perf 类似,从 Linux 内核 4.9 开始,BPF 优化的分析现在完全 可用,并承诺降低 CPU 开销(因为堆栈跟踪是 frequency 在内核上下文中计数)和磁盘 I/O 资源。

除此之外,仅依靠 bcc/BPF 的配置文件工具,我们还 删除了 perf.data 和 intermediate 步骤(如果 Stack Traces 分析是我们的 主要目标。您可以使用 bcc 的配置文件工具直接输出折叠格式,对于 火焰图生成:

$ /usr/share/bcc/tools/profile -F 999 -f --pid $(pgrep redis-server) --duration 60 > redis.folded.stacks

通过这种方式,我们删除了所有预处理,并可以渲染 CPU 上的火焰 graph 替换为单个命令:

$ flamegraph.pl redis.folded.stacks > redis.svg

使用 Flame Graphs 可视化记录的配置文件信息

使用 bcc/BPF 进行呼叫计数分析

函数可能会消耗大量 CPU 周期,因为其代码速度较慢 或者因为它经常被调用。要回答函数的速率是多少 调用的,您可以依赖使用 BCC 的funccount工具:

$ /usr/share/bcc/tools/funccount 'redis-server:(call*|*Read*|*Write*)' --pid $(pgrep redis-server) --duration 60
Tracing 64 functions for "redis-server:(call*|*Read*|*Write*)"... Hit Ctrl-C to end.

FUNC                                    COUNT
call                                      334
handleClientsWithPendingWrites            388
clientInstallWriteHandler                 388
postponeClientRead                        514
handleClientsWithPendingReadsUsingThreads      735
handleClientsWithPendingWritesUsingThreads      735
prepareClientToWrite                     1442
Detaching...

上面的输出显示,在跟踪时,Redis 的 call() 函数是 调用 334 次,handleClientsWithPendingWrites() 388 次,等等。

使用性能监控计数器 (PMC) 进行硬件事件计数

许多现代处理器都包含性能监控单元 (PMU) 公开 性能监控计数器 (PMC)。PMC 对于了解 CPU 至关重要 行为,包括内存 I/O、停顿周期和缓存未命中,并提供 其他任何地方都无法获得的低级 CPU 性能统计数据。

PMU 的设计和功能是特定于 CPU 的,您应该评估 使用 CPU 支持的计数器和功能perf list.

要计算每个周期的指令数,微作数 executed 的 Cycle 数,则表示未调度 Micro Ops 的周期数, 内存上停止的周期数(包括每个内存类型的停止),对于 持续时间为 60 秒,特别是对于 Redis 进程:

$ perf stat -e "cpu-clock,cpu-cycles,instructions,uops_executed.core,uops_executed.stall_cycles,cache-references,cache-misses,cycle_activity.stalls_total,cycle_activity.stalls_mem_any,cycle_activity.stalls_l3_miss,cycle_activity.stalls_l2_miss,cycle_activity.stalls_l1d_miss" --pid $(pgrep redis-server) -- sleep 60

Performance counter stats for process id '3038':

  60046.411437      cpu-clock (msec)          #    1.001 CPUs utilized          
  168991975443      cpu-cycles                #    2.814 GHz                      (36.40%)
  388248178431      instructions              #    2.30  insn per cycle           (45.50%)
  443134227322      uops_executed.core        # 7379.862 M/sec                    (45.51%)
   30317116399      uops_executed.stall_cycles #  504.895 M/sec                    (45.51%)
     670821512      cache-references          #   11.172 M/sec                    (45.52%)
      23727619      cache-misses              #    3.537 % of all cache refs      (45.43%)
   30278479141      cycle_activity.stalls_total #  504.251 M/sec                    (36.33%)
   19981138777      cycle_activity.stalls_mem_any #  332.762 M/sec                    (36.33%)
     725708324      cycle_activity.stalls_l3_miss #   12.086 M/sec                    (36.33%)
    8487905659      cycle_activity.stalls_l2_miss #  141.356 M/sec                    (36.32%)
   10011909368      cycle_activity.stalls_l1d_miss #  166.736 M/sec                    (36.31%)

  60.002765665 seconds time elapsed

重要的是要知道 PMC 可以通过两种截然不同的方式 (计数和采样),我们只关注 PMC 计数 为了这个分析。Brendan Greg 在下面的链接中清楚地解释了这一点。

为本页评分
返回顶部 ↑