1 . 前置檢查:確認 CPU 真的是瓶頸
在正式打性能“補丁”前,務必跑一遍系統級健康核對表(推薦 Brendan Greg 的 USE Method):
資源 | 關注指標 | 常用工具 |
---|---|---|
CPU | Util/Idle、RunQueue | top 、vmstat 、sar |
內存 | Fault、Swap、Cache Miss | free 、perf stat |
I/O | IOPS、Latency、Wait | iostat 、pidstat -d |
網絡 | PPS、Rtt、Drop | ifstat 、ss |
當你確認 Redis 主要耗時在 CPU on-cpu,再繼續以下步驟。
2 . 為可追蹤重新編譯 Redis
目標:既保留
-O2
優化獲得真實的生產時序,又保證棧幀可解析。
# 從 Redis 源碼根目錄編譯
make clean
make REDIS_CFLAGS="-g -fno-omit-frame-pointer"
-g
??? : 保留調試符號,便于棧回溯-fno-omit-frame-pointer
: 強制保留 FP 寄存器-O2
???: 維持 Release 優化級別
3 . 熱點采樣(Hotspot Analysis)
3.1 使用 perf 采樣用戶態 + 內核態棧
# 60 s 內以 999 Hz 頻率采樣 redis-server 進程
perf record -g -F 999 --pid $(pgrep redis-server) -- sleep 60
分析報告
perf report -g "graph,0.5,caller"
graph
?展示調用關系0.5
? 截斷閾值(≥0.5 %)caller
自上而下查看“誰調用了熱點函數”
3.2 使用 eBPF/BCC 的 profile 工具
內核 4.9+ 之后,BPF 方案可在內核空間折疊棧,再回寫到用戶態,極大降低開銷。
/usr/share/bcc/tools/profile -F 999 -f \--pid $(pgrep redis-server) --duration 60 > redis.folded.stacks
一步到位獲得 folded 格式(形如 main;call;dictFind 12
),后續直接生成火焰圖。
4 . 可視化:生成交互式 Flame Graph
# perf 采樣
perf script > redis.perf.stacks
stackcollapse-perf.pl redis.perf.stacks > redis.folded.stacks# 或 bcc 已直接輸出 folded
flamegraph.pl redis.folded.stacks > redis.svg
- 橫軸 = 調用棧聚合后 樣本占比
- 縱軸 = 調用深度
- 點擊 SVG 方塊可下鉆到更深層棧幀
5 . 調用頻次分析(Call Counts)
高 CPU 占用可能是 單次調用很慢,也可能是 調用極其頻繁。用 BCC 的 funccount
快速把函數調用次數統計出來:
/usr/share/bcc/tools/funccount 'redis-server:(call*|*Read*|*Write*)' \--pid $(pgrep redis-server) --duration 60
輸出示例:
FUNC COUNT
call 334
handleClientsWithPendingWrites 388
prepareClientToWrite 1442
配合熱點棧信息,就能判斷該優化“減肥”還是“減次數”。
6 . 硬件事件采樣:PMCs 診斷失速
通過
perf stat
一次性拉齊真正的 CPU IPC、Cache Miss 與 Stall 周期。
perf stat -e \cpu-clock,cpu-cycles,instructions, \uops_executed.core,uops_executed.stall_cycles, \cache-references,cache-misses, \cycle_activity.stalls_l1d_miss,cycle_activity.stalls_l2_miss, \cycle_activity.stalls_l3_miss \--pid $(pgrep redis-server) -- sleep 60
關鍵指標解讀:
指標 | 理想 | 診斷思路 |
---|---|---|
IPC (instructions / cycles ) | > 2(現代 x86) | 低則說明管線空轉或 Cache Miss |
cache-miss / cache-ref | < 3 % | > 10 % 多半緩存友好度差 |
stall_cycles / cycles | 越低越好 | 高說明 CPU 在等數據 |
7 . 一鍵腳本示例
下面腳本可把 采樣 + 折疊 + FlameGraph 合并執行,適合 CI / 回歸測試:
#!/usr/bin/env bash
PID=$(pgrep redis-server)
DUR=60
FREQ=999
OUT=/tmp/redis_$(date +%s)# 1) 采樣
perf record -g -F $FREQ --pid $PID -- sleep $DUR# 2) 轉棧
perf script > $OUT.stacks
stackcollapse-perf.pl $OUT.stacks > $OUT.folded# 3) 火焰圖
flamegraph.pl $OUT.folded > $OUT.svg
echo "🔥 FlameGraph ready: $OUT.svg"
8 . 生產環境落地建議
- 采樣頻率:
999 Hz
已覆蓋絕大多數業務;異常抖動場景可降到199 Hz
減少開銷。 - 采樣窗口:確保覆蓋 GC、AOF rewrite、慢查詢 等高峰時段。
- 分段對比:升級或改代碼前后做 差分 FlameGraph,一眼看出新增/消失的熱點。
- 自動歸檔:用
perf-archive.sh
+tar
保存perf.data
與 Build-ID,方便異地復盤。 - 代碼熱補丁:熱點定位后,可先試
serverCron
、dictFind
等典型函數的算法或數據結構優化,再決定是否拆分 RDB、AOF 線程。
9 . 常見疑難解答
癥狀 | 排查點 |
---|---|
FlameGraph 棧幀只有不到兩層 | 未加 -fno-omit-frame-pointer 或 strip 了 debug 符號 |
perf record 提示 “PERF_EVENT_OPEN failed” | 當前用戶無 CAP_SYS_ADMIN ,用 sudo 或調整 kernel.perf_event_paranoid=-1 |
采樣時 Redis 延遲抖高 | 頻率過大 / 容器 cgroup 受限,先用 eBPF profile 或降低采樣率 |
火焰圖找不到內核函數 | 確保安裝 kernel-debuginfo 或 linux-image-*-dbgsym |
結語
- perf + eBPF 解決“算在哪”的問題;
- PMCs 解決“慢在哪”的問題;
- 系統方法論 (USE / RED) 解決“該不該”的問題。
把三者串起來,就形成了 Redis CPU 優化的閉環:定位 → 可視化 → 改進 → 回歸。
愿你下次再看火焰圖時,只為欣賞那條平穩而美麗的線!