Skip to main content

MySQL 8.0 启用 Jemalloc

虽然本文标题说是 Jemalloc,但 TCmalloc 等也是同理。

随便一搜你大概会找到这样的建议:

#修改my.cnf文件 [mysqld_safe] 配置区间,加上 malloc-lib 选项,指向 Jemalloc 路径
[mysqld_safe]
malloc-lib = /usr/lib64/libjemalloc.so

但这是给 MySQL 5.6 用的,从 MySQL 5.7 版本开始,已经默认不使用 mysqld_safe 来启动了。

所以这是行不通的。


MySQL 8.0 启用替代 malloc

安装 Jemalloc

A. 手动安装

https://github.com/jemalloc/jemalloc/releases 下载并编译安装


B.使用包管理器

RHEL 系列可以在 EPEL 源中找到。
其他系统请自行搜索。


手动启动 MySQL

呃,你不应该手动启动 mysql,但你一定要的话:

LD_PRELOAD=/usr/lib64/libjemalloc.so.2 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid --user mysql

LD_PRELOAD= 指向你的 Jemalloc 实际路径。
如 jemalloc 5.1.2 应该是 /usr/lib64/libjemalloc.so.2
或者 cat /usr/bin/jemalloc.shLD_PRELOAD=${libdir}/libjemalloc.so.2 这一行会告诉你实际路径。


使用 Systemd 启动 MySQL

在你的 mysql.serive(/usr/lib/systemd/system/mysqld.service 或者使用 systemctl status mysql 查看路径) 中的 [Service] 部分添加:

EnvironmentFile=-/etc/sysconfig/mysql

*可能已经有这一行了

例如:

[Service]
User=mysql
Group=mysql
# Use this to switch malloc implementation
EnvironmentFile=-/etc/sysconfig/mysql
  • Systemd 中的 =- 表示:可选前缀“-”,表示如果文件不存在,则不会读取它,并且不会记录错误或警告消息。

然后新建 /etc/sysconfig/mysql 文件,在其中写写入:

LD_PRELOAD=/usr/lib64/libjemalloc.so.2

LD_PRELOAD= 指向你的 Jemalloc 实际路径。
如 Jemalloc 5.1.2 应该是 /usr/lib64/libjemalloc.so.2
而 Percona 储存库中带的 jemalloc-3.6.0-1.el8.x86_64.rpm 则是 /usr/lib64/libjemalloc.so.1

或者 cat /usr/bin/jemalloc.shLD_PRELOAD=${libdir}/libjemalloc.so.2 这一行会告诉你实际路径。

检查 MySQL 是否正在使用 Jemalloc

执行 lsof -Pn -p $(pidof mysqld) | grep jemalloc,有指向 /usr/local/lib/libjemalloc.so.2 或者你的 Jemalloc 路径则为成功。


 

LD_PRELOAD 是什么?

LD_PRELOAD 是 Linux 系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

简单来说,比如系统自带一个 random.so 里面有一个 rand() 函数,返回一个随机数。
你自己做了一个 random_hack.so,里面也有一个 rand() 函数,但是永远返回 6。

在你的程序里调用 rand(),但是以下面的方式允许

LD_PRELOAD=/path/random_hack.so /path/你的程序

或者

export LD_PRELOAD=/path/libmyrand.so
/path/你的程序

你会发现 rand() 永远只返回 6。

 

 

注意事项

Percona 建议在启用 Jemalloc 时禁用透明大页:

在谈到透明大页( Transparent Huge Pages / THP)时,它们可能会占用更多的内存。内核的内存分配功能会分配请求的页面大小,有时甚至更多,以适应可用内存。换句话说,即使您的应用程序只需要少量内存,也至少会分配一个完整的页面。

此外,页面必须在内存中连续,这适用于“巨页”。这意味着如果服务器找不到一整个可用的连续页面,它会在分配之前对内存进行碎片整理。这可能会对性能产生负面影响并导致延迟。

InnoDB 建立在 B* 树的索引上,这意味着它的工作负载通常会是稀疏的而非连续的内存访问,因此,它在使用 THP 时的表现可能会明显变差。

如果你在使用 jemalloc 与 THP 结合时,服务器可能会随着时间的推移而耗尽内存,因为未使用的内存无法被释放。因此,建议禁用数据库服务器上的透明巨页,以避免这种情况。

使用 Jemalloc 代替 glibc 内存分配器用于 MySQL,可以减少内存碎片化并更有效地管理资源。当禁用透明巨页时,这一点尤其明显。

 

机器翻译自 https://www.percona.com/blog/dont-start-using-your-mysql-server-until-youve-configured-your-os/

检查是否已启用透明大页:

>$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
  • [always] 表示已经开启
  • [never] 表示透明大页禁用
  • [madvise] 表示只在 MADV_HUGEPAGE 标志的 VMA 中使用 THP

更多信息请参阅:


主要参考