Linux transparent hugepage 的 always / madvise / never 模式对 Redis 的影响

8次阅读

应禁用 thp,设为 never;因 redis 的 fork 和 jemalloc 与 thp 冲突,导致 fork 延迟、rss 虚高、oom 及 active-defrag 失效,需通过 systemd 或 rc.local 永久配置并验证生效。

Linux transparent hugepage 的 always / madvise / never 模式对 Redis 的影响

redis 启动报 WARNING: The TCP backlog setting of 511 cannot be enforced 或内存分配慢,可能和 THP 有关

linux 的 transparent hugepage(THP)默认开启 always 模式时,内核会主动合并小页为 2MB 大页。Redis 的内存分配模式(尤其是 jemalloc)和 fork() 行为对大页不友好——它会导致 fork 延迟飙升、RSS 内存虚高、甚至触发 OOM killer。

常见现象包括:

  • Redis 日志里反复出现 WARNING: You have Transparent Huge Pages (THP) support enabled in your kernel
  • INFO memory 显示 mem_allocator 是 jemalloc,但 used_memory_rss 远大于 used_memory
  • 主从全量同步或 RDB save 期间,redis-server 进程卡住数秒,系统负载突增

这不是 Redis 配置问题,而是内核内存管理策略与 Redis 工作方式的冲突。解决方向很明确:关掉 THP 的自动合并行为。

/sys/kernel/mm/transparent_hugepage/enabled 三个值的实际效果差异

always:内核强制对所有匿名内存区域尝试合并为 huge page,Redis 的、fork 出的子进程内存都会被卷入,最危险;

madvise:只对显式调用 madvise(..., MADV_HUGEPAGE) 的内存生效——Redis 默认不这么干,所以等效于关闭;

never:彻底禁用 THP,连 madvise 请求都拒绝,最保守也最安全。

生产环境推荐直接设为 never,别贪 madvise 那点理论收益。因为:

  • Redis 没有在关键路径上标记 MADV_HUGEPAGEmadvise 实际不起作用
  • 某些内核版本(如 centos 7.6+ 的 3.10.0-1127)在 madvise 下仍会 fallback 到 always 行为
  • never 对性能无负面影响,反而让 RSS 和实际使用内存更接近

如何永久禁用 THP(避免重启后恢复 always

临时改只是治标:echo never > /sys/kernel/mm/transparent_hugepage/enabled,但重启就丢。必须写进启动流程。

不同发行版写法略有区别,核心是确保在 Redis 启动前执行:

  • Systemd 系统(ubuntu 16.04+/CentOS 7+):新建 /etc/systemd/system/disable-thp.service,在 [Service] 下加 ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled',然后 systemctl enable disable-thp
  • 旧 SysVinit(CentOS 6):在 /etc/rc.local 里加同一行 echo never > /sys/kernel/mm/transparent_hugepage/enabled,并确保文件有执行权限
  • 注意:不能写进 /etc/default/grubtransparent_hugepage=never 参数——这个内核参数在较新内核(>=4.12)已废弃,无效

验证是否生效:cat /sys/kernel/mm/transparent_hugepage/enabled 输出应为 [never],中括号包住的那个值才是当前生效项。

Redis 6.0+ 开启 active-defrag 时更要关 THP

内存碎片整理(activedefrag)依赖频繁的 mremapmmap 调用,而 THP 会让这些系统调用变慢甚至失败。开启 defrag 后若 THP 仍为 always,会出现:

  • INFO statsactive_defrag_running 长期为 1,但 mem_fragmentation_ratio 不降反升
  • 日志里出现 Failed to allocate memory for defrag 类错误
  • Redis 主进程 CPU 使用率异常升高,但吞吐没提升

这不是配置错了,是 THP 干扰了内存重映射路径。哪怕你开了 active-defrag,也得先确保 THP 是 never——否则碎片整理根本跑不起来。

THP 的影响藏得深,不报错、不 crash,只悄悄拖慢 fork、涨 RSS、卡 defrag。检查它,比调 maxmemory-policytimeout 更优先。

text=ZqhQzanResources