MySQL 修改内存管理器为 tcmalloc

1、 背景

经常在项目上碰到在没有大并发活跃 SQL 的情况下,MySQL 所占用的物理内存远大于InnoDB_Buffer_Pool 的配置大小,因此需要解决由此带来的内存问题。

环境说明:

系统为 Centos7, MySQL 版本为5.7,且为手动安装(跟yum安装区别在于目录差异,其它更改不受限)。

关于内存分配机制,这里不展开,可参考下方详解:

关于centos7中linux内存管理详解
计算mysql服务当前可消耗的最大内存

2、更换内存管理器

常见的内存分配器包括:ptmalloc(Glibc)、tcmalloc(Google)、jemalloc(FreeBSD)。
MySQL 默认情况下使用的是 glibc 的 ptmalloc 作为内存分配器。

关于tcmalloc跟jemalloc内存管理器的对比:

2.1、tcmalloc

  • 优势
    Google 开发的tcmalloc在多线程环境下通常表现出色,它能有效减少锁竞争,降低内存碎片。在高并发、多线程的 MySQL 环境中,tcmalloc可以显著提升性能,尤其适用于需要频繁分配和释放内存的场景。

  • 劣势
    相比jemalloc,tcmalloc对内存的控制可能不够精细,在某些特定的内存使用模式下,可能会导致内存占用稍高。

2.2、jemalloc

  • 优势
    jemalloc 以其出色的内存管理策略而闻名,它能够更精确地控制内存分配,减少内存碎片。此外,jemalloc 还提供了丰富的配置选项,可以根据不同的应用场景进行优化。对于内存资源有限的系统,jemalloc 可能是更好的选择。

  • 劣势
    在一些极端的多线程场景下,jemalloc 的性能可能不如 tcmalloc。

2.3、更适合的场景

  • 如果你的 MySQL 服务器具有以下特点,tcmalloc 可能更适合:

    1. 高并发的多线程工作负载,例如大型电商网站的数据库服务器,需要处理大量的并发查询和事务。
    2. 对内存分配和释放的性能要求较高,希望在高负载下能够快速响应。
  • 如果你的 MySQL 服务器具有以下特点,jemalloc 可能更适合:

    1. 内存资源有限,需要更精细地控制内存使用,避免内存浪费。
    2. 对内存碎片比较敏感,希望减少内存碎片对系统性能的影响。

3、查看当前使用的内存管理器

3.1、查找配置文件

  1. 查看 /etc/init.d/mysqld 脚本
grep LD_PRELOAD /etc/init.d/mysqld
  1. 查看 /etc/sysconfig/mysql 配置文件
grep LD_PRELOAD /etc/sysconfig/mysql

若上述命令有输出,且指定了其他内存分配器的库文件(如 /usr/lib64/libtcmalloc.so.4 或 /usr/lib64/libjemalloc.so.1),则说明 MySQL 没有使用 ptmalloc;若没有输出,则表明没有明确指定其他内存分配器,大概率使用的是 ptmalloc。

3.2、使用 lsof 命令检查

lsof -p <MySQL-PID>| grep -E 'libtcmalloc|libjemalloc'

若有输出:说明 MySQL 与 tcmalloc 或 jemalloc 有链接,没有使用 ptmalloc。
若无输出:则可能使用的是 ptmalloc。

4、安装 tcmalloc

4.1、安装 tcmalloc 库

# 安装EPEL仓库(如未安装)
sudo yum install -y epel-release

# 安装gperftools(包含tcmalloc)
sudo yum install -y gperftools

4.2、确认 tcmalloc 库路径

# 查找libtcmalloc.so的位置(通常是以下路径)
ls /usr/lib64/libtcmalloc.so.4

4.3、配置 MySQL 使用 tcmalloc

① 查看 MySQL 启动命令位置(手动跟自动安装目录不同)

[root@nodex ~]# systemctl status mysql
● mysql.service - LSB: start and stop MySQL
   Loaded: loaded (/etc/rc.d/init.d/mysql; generated)
   Active: inactive (dead)
     Docs: man:systemd-sysv-generator(8)

Mar 19 10:43:51 node1 systemd[1]: Stopping LSB: start and stop MySQL...
Mar 19 10:43:51 node1 mysql[29012]:  ERROR! MySQL server PID file could not be found!
Mar 19 10:43:51 node1 systemd[1]: Stopped LSB: start and stop MySQL.

比如本篇是手动安装的mysql,目录为:/etc/rc.d/init.d/mysql

② 如果是自动安装,目录可能如下(仅参考)

sudo cp /usr/lib/systemd/system/mysqld.service /etc/systemd/system/  # 备份原服务文件
sudo vi /etc/systemd/system/mysqld.service

无论哪种方式安装,找到这个启动文件,先备份,然后修改

③ 在 [Service] 部分添加环境变量:

[Service]
# 原有内容保持不变,添加以下行:
Environment="LD_PRELOAD=/usr/lib64/libtcmalloc.so.4"

④ 重启 MySQL

注意不要 restart , stop / start 同时把 MySQL 日志挂着,方便看出报错:

# 停止MySQL服务
sudo systemctl stop mysql        

⑤ 重新加载配置并启动 MySQL

sudo systemctl daemon-reload
# systemctl start mysql
sudo service mysql start

⑥ 验证是否生效

# 检查MySQL进程是否加载了tcmalloc
sudo lsof -p $(pgrep mysqld) | grep tcmalloc

# 预期输出应包含类似:
# mysqld 1234 root mem  REG  8,3 1234567 /usr/lib64/libtcmalloc.so.4

# 查看MySQL进程内存使用情况
ps -p $(pgrep mysqld) -o pid,ppid,cmd,%mem,%cpu,rsz,vsz

⑦ 高级配置(可选)
调整 tcmalloc 参数,通过环境变量控制 tcmalloc 行为(在 systemd 服务文件中添加):

# 设置线程缓存大小为256MB
Environment="TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=268435456"

5、常见问题

5.1、修改配置不生效

这种情况一般都是改错了问题,或者被 mysqld_safe 进程启动时配置被覆盖。
比如查找到所有目录只有这一个名称的文件:/run/systemd/generator.late/mysql.service
尝试修改了,重启,无效。应当以 systemctl status mysql 中的目录输出结果为准。

5.2、修改配置后启动报错

启停MySQL都会报错如下,找不到目录,实际是权限问题。

shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
chdir: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

比如通过 ps -ef|mysql 进程发现,比如我的服务前缀是 /usr/local/mysql/bin/mysqld ,并且我是用 mysql 用户进行安装的,也就代表了只能访问 mysql 组文件的权限,那么就用 root 切到目录授权。

chown -R mysql:mysql /usr/local/mysql/bin

5.3、配置文件确认无误,还是无效怎么办

如果 systemd 配置仍不生效,可以手动启动 MySQL 以验证:

# 停止 MySQL 服务
sudo systemctl stop mysqld

# 手动加载 tcmalloc 启动 MySQL
sudo LD_PRELOAD=/usr/lib64/libtcmalloc.so.4 /usr/local/mysql/bin/mysqld --user=mysql &

如果此时 lsof -p | grep tcmalloc 显示成功加载,说明问题出在 systemd 配置。
如果仍不加载,检查 tcmalloc 库路径和权限:

# 确认库文件存在且可读
sudo ls -l /usr/lib64/libtcmalloc.so.4

# 检查 MySQL 用户(如 mysql)是否有权限读取库文件
sudo -u mysql head -c 1 /usr/lib64/libtcmalloc.so.4

5.4、处理手动安装的 MySQL 启动脚本干扰

如果手动安装的 MySQL 使用了 mysqld_safe 或自定义启动脚本,这里简单说明一下 mysqld_safe ,主要是针对 mysqld 服务的监控跟保活,当 mysqld 进程不存在时重新创建,所以会涉及启动逻辑。因此可能覆盖 LD_PRELOAD。需在启动脚本中注入环境变量:
(仅参考,我没到这一步,以及正常了,若依旧不行可尝试)

# 找到 MySQL 启动脚本(通常在 /usr/local/mysql/support-files/ 或 /etc/init.d/)
sudo vi /usr/local/mysql/support-files/mysql.server

# 在启动命令前添加 LD_PRELOAD
修改前:
$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" "$@"

修改后:
export LD_PRELOAD=/usr/lib64/libtcmalloc.so.4
$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" "$@"

5.5、手动安装 MySQL 未更新动态库

# 更新缓存
sudo ldconfig

# 查看 tcmalloc 是否在缓存中
ldconfig -p | grep tcmalloc

# 预期输出
libtcmalloc.so.4 (libc6,x86-64) => /usr/lib64/libtcmalloc.so.4

over.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值