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 --> A3. 现象总结
触发 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) / 10000D. 推荐配置
vm.watermark_scale_factor=10002. 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[停止回收]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=52. 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 64mb3. 监控指标
A. 关键指标
- NUMA 页面迁移次数
- 跨节点内存访问次数
- 内存使用分布
- kswapd 回收频率
B. 告警规则
- NUMA 页面迁移次数突增
- P99 延迟超过基线 20%
- 跨节点内存分配比例超过 10%