共计 3355 个字符,预计需要花费 9 分钟才能阅读完成。
MySQL 的内存和相关问题排查是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
我们都知道数据库是 IO 密集型一类应用,为了提高其性能大量使用内存代替文件(交换分区)的 IO 操作是保证数据库稳定、高效的基本原则。那么数据库是如何使用内存的,我们如何查看数据库内存的占用,如何通过通过数据库内存配置设置提高其性能?以 Mysql 数据库(InnoDB 引擎)为例和大家一起了解下 Linux 数据库和内存相关的主题。读取内存数据非常快,为了提高性能我们要尽可能把数据集都放到内存中以保证高效。但是 Swap 交换分区作为一个救命的稻草,我们还必须要给 mysql 设置,防止突发情况下内存不够,mysql 服务直接被 OOM 杀掉的情况。同时 mysql 交换分区占用也是我们衡量一个数据是否健康与否的手段,如果一个数据库频繁的使用了 swap 则说明,我们需要人工干预优化数据库了。
内存占用
在 Linux 下,我们可以通过使用一些 shell 命令来了解 MySQL 的内存使用情况。
首先使用 ps 命令来查看 mysqld 进程的内存使用情况:
ps -eo size,pid,user,command --sort -size|grep mysqld |awk {hr=$1/1024;printf( %13.2f MB ,hr)} {for (x=4;x x++){printf( %s ,$x)}print } |cut -d -f2|cut -d - -f1
1990.88 MB/usr/local/mariadb/bin/mysqld 0.49 MB/bin/sh/usr/local/mariadb/bin/mysqld_safe
top 命令也可以查看对应上面的结果也可以用 top 来得到:
top -b -o %MEM -n1 -p $(pidof mysqld) | grep PID -A
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2239 mysql 20 0 2108536 316836 7548 S 0.0 4.0 48:47.37 mysqld
其中,VIRT(virtual memory usage)表示 mysql 使用的虚拟内存总量。它包括所有代码,数据和共享库以及最终要被置换出的页面。
RES(resident memory usage) 常驻内存, 包括当前进程使用的内存,不包括置换出的内存。
SHR(shared memory)共享内存,进程使用的的共享内存,也包括其他进程的共享内存。
交换分区
我们再来检查检查 mysqld 是否正在使用交换分区,首先用 free - m 检查是否有用到交换分区。
free -m
total used free shared buff/cache available Mem: 7822 5091 178 83 2552 2290 Swap: 3999 2 3997
上面结果了,系统使用少量的交换分区(2M),那怎么判断是不是 MySQL 用的呢?我们来验证:
cat /proc/$(pidof gitlab)/status | grep Swap
VmSwap:0 kB
可见 mysqld 不没用用到交换区,说明我的 mysqld 在高效运行中。
这儿我们提供一个脚本,遍历每一个进程,找出那些进程使用了交换分区:
for i in $(ls -d /proc/[0-9]*) do out=$(grep Swap $i/status 2 /dev/null) if [ x$(echo $out | awk {print $2} ) != x0 ] [ x$(echo $out | awk {print $2} ) != x ] then echo $(ps -p $(echo $i | cut -d / -f3) | tail -n 1 | awk {print $4}): $(echo $out | awk {print $2 $3} ) fi done
当然,交换中的页面可能已经存在很长时间了,自从使用一次后,后面就没有在用过。为了获取实时交换分区情况,我们可以用 vmstat:
vmstat 1 10
在这个服务器上,我们可以看到 mysqld 没有使用交换,如果系统内存充足,但是 mysqld 还占用了部分交换分区,是怎么回事?怎么排查呢?
如果遇到这种情况,可能的直接原因有 swappiness 和 Numa。
Swappiness
swappiness 参数控制内核将进程移出物理内存并将其放入交换磁盘分区的趋势。我们之前也说过了磁盘 IO 操作要比 RAM 慢很多很多,因此如果进程过于频繁地从内存中置换出,这会导致系统和应用程序的响应时间变慢。高 swappiness 值意味着内核更容易取消内存页面。低 swappiness 相反,内核将不太容易取消内存页面。swappiness 值越高,系统内存置换的越多。
linux 下系统(CentOS、Red Hat、ubuntu)默认的 swappiness 值为 60。如果内存较小则应适当调高这个值。对于内存足够的 MySQL 服务器,这个默认设置就有点太高了,应该减少。一般情况下,业界建议这个值可以设置到 5. 或者更小。设置 swappiness 方法是使用 sysctl 命令直接改变内核参数。
sysctl -w vn.swappinness = 1
NUMA 设置
还有一个方面就是 NUMA 设置。对于具有多个 NUMA 核心的服务器,建议将 NUMA 模式设置为交错,以平衡所有节点的内存分配。在 *** 的 MySQL 8.0 中支持为 InnoDB 设置 NUMA。可以在配置通过启动:innodb_numa_interleave = 1
要检查是否有多个 NUMA 节点,可以使用 numactl -H
这是两种不同的输出:
我们可以看到,当有多个 NUMA 节点(下)时,默认情况下,内存不会在所有节点之间平均分配。这可以导致更多内存置换。
文件系统缓存
默认情况下,Linux 将使用文件系统会对所有的 I / O 操作进行缓存(这是不建议使用 MyISAM 的原因之一,MyISAM 存储引擎依赖于 FS 缓存,并且可能导致丢失数据)。Mysql InnoDB 引擎中使用 O_DIRECT 作为 innodb_flush_method,MySQL 将绕过文件系统缓存,不会将任何 FS Cache Memory 用于数据文件(* .ibd)。
当然在 MySQL 中使用的其他非数据文件仍会使用 FS Cache。我们来看个例子:
dbsake fincore binlog.000017 binlog.000017: total_pages=120841 cached=50556 percent=41.84 ls -lh binlog.000017 -rw-r----- 1 mysql mysql 473M Sep 18 07:17 binlog.000017free -m
total used free shared buffers cached Mem: 5965 4608 1356 128 435 2456 -/+ buffers/cache: 1716 4249 Swap: 2045 30 2015 dbsake uncache binlog.000017 Uncached binlog.000017 #free -m
total used free shared buffers cached Mem: 5965 4413 1552 128 435 2259 -/+ buffers/cache: 1718 4247 Swap: 2045 30 2015
开始检查文件系统缓存中存在多少二进制日志(使用 dbsake fincore),我们可以看到 473M 中有 42% 使用 RAM 作为 FS 缓存。然后我强制取消在缓存中使用这些页面(使用 fincore uncache),结果,我们释放了 +/- 195MB 的 RAM。
关于 MySQL 的内存和相关问题排查是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注丸趣 TV 行业资讯频道了解更多相关知识。