Redis NUMA 架构下的延迟性能优化案例分析

一、事件概述

1. 事件背景

Redis 作为核心存储组件,对实时性要求非常高。在长期运行后,Redis 服务会出现性能下降,导致较大的查询延迟,拖慢整个链路的响应速度。

2. 影响范围

A. 影响功能

Redis 数据库的所有查询操作

B. 性能指标

P99 延迟从 9.2ms 降至 5.7ms,下降约 37%

3. 严重程度

P2 级性能问题(核心业务响应速度受影响)

二、问题分析

1. 直接原因

通过 HUATUO 系统观测指标分析,发现 Redis 延迟升高时,NUMA 页面迁移指标(huatuo_bamai_vmstat_numa_pages_migrated)同步升高,两者趋势一致。

2. 根本原因(5 Whys 分析)

A. 为什么出现这个问题?

Redis 进程在 NUMA 架构下,内存分散在不同的内存节点上,访问远端节点内存时触发 NUMA balancing,导致页面迁移,在 page fault 中产生额外开销。

B. 为什么内存会分散?

  • 负载变化导致 Redis 进程在 node 之间迁移
  • AOF 备份产生的文件缓存持续占用内存,导致某个 node 可用内存减少,后续分配从另一个 node 进行

C. 为什么没有自动优化?

内核默认的 NUMA balancing 策略旨在提高访存速度,但对内存带宽敏感型的数据库服务,页面迁移本身的开销超过了收益。

3. 深层反思

容器化环境下,NUMA 架构与内存管理策略需要针对不同类型的负载进行调优,通用内核参数无法满足所有场景。

三、问题定位过程

1. 观测指标

使用 HUATUO 提供的关键指标:

  • huatuo_bamai_vmstat_numa_pages_migrated:系统级 NUMA 页面迁移次数
  • huatuo_bamai_vmstat_container_numa_pages_migrated:容器级 NUMA 页面迁移次数
  • nr_inactive_file:非活跃文件缓存页数
  • nr_active_file:活跃文件缓存页数
  • nr_free_pages:空闲内存页数

2. 指标关联分析

graph TD
    A[Redis 延迟升高] --> B[NUMA 页面迁移指标升高]
    B --> C[发现关联性]
    C --> D[AOF 操作]
    D --> E[nr_inactive_file 升高]
    E --> F[nr_active_file 升高]
    F --> G[nr_free_pages 下降]
    G --> H[跨 node 内存分配]
    H --> I[NUMA balancing 触发]
    I --> J[页面迁移开销]
    J --> A

mermaid

3. 现象总结

触发 NUMA balancing 的两个条件:

A. 进程迁移

随着负载变化,Redis 进程会在 node 之间迁移,导致内存分散在两个内存节点上。

B. 文件缓存占用

Redis 定期进行数据备份(AOF),将数据保存在文件里。这些磁盘数据写完后一般不再使用,但仍留在文件缓存中,导致某个 node 可用内存特别少。

四、解决方案

1. 临时方案

A. 提升内存水位参数

将 vm.watermark_scale_factor 设定为 1000,使内核的 low 水位被设定为总内存的 1/10。

B. 效果评估

kswapd 可以频繁回收文件缓存,让 free 内存保持合理水平,内存分配不会被迫横跨节点,NUMA miss 减少到接近 0。

2. 永久方案

A. 提升内存水位

调整 vm.watermark_scale_factor 参数

B. 关闭 NUMA balancing

对于内存带宽敏感型的数据库服务,关闭 NUMA balance 策略

C. 实施计划

  • 测试环境验证参数调整效果
  • 生产环境分批次灰度调整

五、技术细节

1. vm.watermark_scale_factor 参数详解

A. 参数作用

控制内存水位的间距,影响内核的内存回收行为,主要是 kswapd 守护进程的唤醒和睡眠时机。

B. 参数特性

  • 不改变 min 水位
  • 只影响 min 水位到 low 和 high 的间距
  • 默认值为 10(对应总内存的 0.1%)
  • 取值范围为 0-3000(即 0% 到 30%)

C. 计算公式

WMARK_LOW  = WMARK_MIN + (zone->managed_pages * vm_watermark_scale_factor) / 10000
WMARK_HIGH = WMARK_LOW + (zone->managed_pages * vm_watermark_scale_factor) / 10000

D. 推荐配置

vm.watermark_scale_factor=1000

2. NUMA balancing 策略

A. 工作原理

NUMA balance 调度策略会在进程尝试访问远端 NUMA node 内存时,把远端 NUMA node 上的内容复制到本地,目的是提高访存速度。

B. 适用场景

通用计算负载,访存局部性较好的应用

C. 不适用场景

数据库或内存带宽敏感型服务

D. 关闭方法

echo 0 > /proc/sys/kernel/numa_balancing
# 或者在内核启动参数中添加
numa_balancing=0

六、优化效果

1. 集群 A 调整结果

A. 调整内容

调整业务集群 A 宿主机参数 vm.watermark_scale_factor=1000

B. 性能提升

周五晚高峰 P99 均值从 9.2ms 降为 5.7ms,下降约 37%

2. 集群 B 调整结果

A. 调整内容

关闭 NUMA balance 策略

B. 性能提升

P99 耗时有明显下降

3. 综合评估

通过内核参数调优和 NUMA 策略调整,业务层面的延迟整体降低 30% 以上。

七、内存回收机制

1. 内存水位管理

graph LR
    A[内存使用] --> B{低于 min 水位}
    B -->|是| C[同步回收]
    B -->|否| D{低于 low 水位}
    D -->|是| E[kswapd 后台回收]
    D -->|否| F{低于 high 水位}
    F -->|是| G[kswapd 继续回收]
    F -->|否| H[停止回收]

mermaid

2. kswapd 工作流程

  • 监控内存水位
  • 低于 low 水位时唤醒
  • 回收文件缓存和匿名内存
  • 达到 high 水位时休眠

3. watermark_scale_factor 影响

增大该参数会扩大 low 和 high 水位之间的差距,使 kswapd 更早开始回收,更激进地释放内存。

八、经验总结

1. 做得好的地方

  • 使用系统可观测性工具(HUATUO)进行根因定位
  • 从指标关联分析到问题定位的逻辑清晰
  • 方案实施前后有明确的性能对比

2. 需要改进的地方

  • 容器环境下的 NUMA 感知调度需要更多优化
  • AOF 备份产生的文件缓存应该主动清理

3. 流程优化建议

  • 建立数据库类服务的内核参数基线
  • NUMA 架构服务器上的服务部署规范
  • 定期检查 NUMA 页面迁移指标

九、最佳实践

1. 数据库类服务内核参数推荐

# 提升内存水位,激进回收文件缓存
vm.watermark_scale_factor=1000

# 关闭 NUMA balancing
kernel.numa_balancing=0

# 调整 vm.dirty_ratio,控制脏页比例
vm.dirty_ratio=10
vm.dirty_background_ratio=5

2. Redis 部署建议

A. 绑定 CPU 核心

使用 taskset 或 cset 将 Redis 进程绑定到特定 CPU 核心

B. 绑定 NUMA 节点

使用 numactl 将 Redis 进程绑定到特定 NUMA 节点

C. AOF 配置优化

# AOF 文件路径放在独立磁盘
# 定期压缩 AOF 文件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

3. 监控指标

A. 关键指标

  • NUMA 页面迁移次数
  • 跨节点内存访问次数
  • 内存使用分布
  • kswapd 回收频率

B. 告警规则

  • NUMA 页面迁移次数突增
  • P99 延迟超过基线 20%
  • 跨节点内存分配比例超过 10%

参考资料

  1. 延迟降低30%! redis 延迟性能问题分析
  2. Redis 延迟问题全面排障指南
  3. Redis 实战:延迟问题排障指南
最后修改:2026 年 01 月 15 日
如果觉得我的文章对你有用,请随意赞赏