根据digitalocean的文章:
Transparent Huge Pages and Alternative Memory Allocators: A Cautionary Tale
最近,我们的站点可靠性工程团队开始收到关于我们的一些 Redis 实例的内存压力的警报,这些实例的工作集非常小。1 当我们开始深入研究这个问题时,很明显在初始分配后释放内存存在问题,因为存在键的数量相对较少,但由 redis-server 进程分配的内存量相对较大。尽管最初看起来像是泄漏,但问题实际上是替代内存分配器和透明大页面之间的问题。
为什么需要禁用 THP?
redis-server
当一个最近被移到 的进程LD_PRELOAD jemalloc.so
开始使用大量内存时,这个兔子洞就开始了。最初的迹象表明,使用替代分配器可能是问题的一部分,所以这就是我们开始挖掘的地方。
事实证明,jemalloc(3)
它madvise(2)
广泛用于通知操作系统它已经完成了它之前已经malloc
编辑过的内存范围。由于机器使用透明大页面,页面大小为2MB。因此,许多被标记的内存都madvise(..., MADV_DONTNEED)
在远小于 2MB 的范围内。这意味着操作系统永远无法驱逐范围标记为的页面,MADV_DONTNEED
因为必须不需要整个页面才能使其被重用。
madvise(2)
因此,尽管最初看起来像是泄漏,但由于透明的大页面,操作系统本身无法释放内存。这导致机器上持续存在内存压力,并redis-server
最终导致 OOM 被杀死。
根据Redis 延迟问题故障排除文档:
必须从内核禁用透明大页面。用于echo never > /sys/kernel/mm/transparent_hugepage/enabled
禁用它们,然后重新启动您的 Redis 进程。
透明大页面引起的延迟
不幸的是,当 Linux 内核启用了透明的大页面时,Redis 在使用 fork 调用以在磁盘上持久化后会产生很大的延迟损失。巨大的页面是导致以下问题的原因:
- 调用 fork,创建了两个共享大页面的进程。
- 在繁忙的实例中,一些事件循环运行将导致命令针对几千页,从而导致几乎整个进程内存的写入时复制。
- 这将导致大延迟和大内存使用。