今天机缘巧合搜到一篇微软CSS团队的一篇案例分享,在本人学习SQL On Linux过程中,对很多知识点存在不理解,看了这篇文章之后,觉得很有必要存起来,不管有没有其他人看,对我自己还是很有用,所以决定翻译一下,我相信在不久的将来这篇文章会被重视,因为SQL On Linux已经出来了一段时间,并且部分客户已经在用,国内市场的改变也只是时间上的问题。
这是一篇关于SQL Server运行在Linux环境下的异常Failover场景的案例,下面是译文,读者如有兴趣可以阅读原文:How to safeguard SQL Server on Linux from OOM-Killer
在Windows平台上,当所有可用内存包括页文件(page file)被消耗干净,那么服务器的性能就会严重下降同时事件日志(event log)会记录OOM(out of memory)错误。在Linux平台,这种行为就略微不同,当服务器运行在低可用内存情况下,Linux内核会选择某个可被杀掉(kill)的进程进行清除以便恢复系统的平稳运行。这个Linux上的机制称为OOM-Killer。
对于SQL Server所在的服务器,SQL Server这种比其他进程消耗更多内存的进程很可能成为被优先杀掉的对象(oom-score记录了可能要被杀掉的进程的得分,从高到底进行kill)。本文将回顾一个客户场景,它强调了在Linux上安装SQL Server后,需要进行额外的配置调整。
SQLServer技术支持组最近收到一个客户案例,情景如下:
现状是:当在一个大表(大概25G)在进行索引重建时,重建操作被终止,同时可用性组Failover到其他副本。在进行深入研究后发现SQL Server进程在重建索引操作运行时被终止并导致Failover。
为了定位异常关闭的原因,我们检查了Linux系统日志(RHEL上/var/log/messages)和pacemaker日志。从日志中看出到oom-killer被调用,然后导致SQL Server进程被终止。
下面是pacemaker日志的部分内容,在/var/log/messages文件中也能看到类似内容:
Sep 13 16:17:30 l99s0004kernel: [9264025.516359] sqlservr invoked oom-killer:gfp_mask=0x280da, order=0, oom_score_adj=0
Sep 13 16:17:30 l99s0004kernel: [9264025.516555] 184007 total pagecache pages
Sep 13 16:17:30 l99s0004kernel: [9264025.516556] 0 pages in swap cache
Sep 13 16:17:30 l99s0004kernel: [9264025.516558] Swap cache stats: add 0, delete 0, find 0/0
Sep 13 16:17:30 l99s0004kernel: [9264025.516558] Free swap = 0kB
Sep 13 16:17:30 l99s0004kernel: [9264025.516559] Total swap = 0kB
Sep 13 16:17:30 l99s0004kernel: [9264025.516560] 3145598 pages RAM
注意:加粗部分代表服务器没有配置swap file。
同时日志也包含了在OOM-Killer发起时所有系统进程的内存消耗快照。下面是整理过格式的结果:
Pid |
Uid |
Tgid |
Total_vm |
Rss |
Nr_ptes |
Swapents |
Oom_score_adj |
name |
46206 |
0 |
46206 |
26370 |
247 |
54 |
0 |
-1000 |
Sshd |
33492 |
992 |
33492 |
49412 |
3805 |
46 |
0 |
0 |
Sqlservr |
33495 |
992 |
33495 |
3029788 |
2418852 |
5059 |
0 |
0 |
Sqlservr |
注意:加粗部分的数值是在4K页,Rss列(内存使用)的SQL Server进程接近9448MB(2418852*4)/1024
此外还有:
Sep 13 16:17:30 l99s0004kernel: [9264025.516658] Out of memory: Kill process 33495 (sqlservr) score 799or sacrifice child
Sep 1316:17:30 l99s0004 kernel: [9264025.516709] Killed process 33495 (sqlservr)total-vm:12119152kB, anon-rss:9675408kB, file-rss:0kB, shmem-rss:0kB
Sep 13 16:17:30 l99s0004kernel: sqlservr invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
上面加粗部分可以看到SQL Server有一个anon-rss值9675408kB代表着“resident set size”,这是当前分配给进程的RAM部分。File-rss是系统所有进程在swap file(交换文件)中的内存量为0KB。
当SQL Server启动时,SQL Server可用的物理内存数有memory.memorylimitmb配置来控制,默认为物理内存的80%,基于这个设置,SQL Server的anon-rss值9675408KB(约为12GB的80%)是有意义的,因为服务器有12GB内存。
这个值在SQL Server启动时的错误日志信息中也能看到:
2017-09-1316:23:17.62 Server Detected 9478 MB of RAM. This is an informational message;no user action is required.
在默认配置中,SQL Server可以使用大约12GB的80%即9.5GB的内存(服务器安装内存)。也就是留了大概2.5GB内存给服务器用于Linux内核和其他进程运行。首先,SQL Server仅用了9.5GB的一部分,在系统上保留了大量可用的内存。但是在重建索引运行时,SQL Server使用了所有可用的9.5GB的内存(译者注:索引重建理论上需要1~1.2倍左右的临时存储空间,而大部分处于内存的缓存当中,25G的表显然足够撑爆9.5G内存)。这时候就引起了Linux服务器只剩下很少内存可用,导致触发了OOM-Killer。作为当前最高内存使用进程(oom分数最高)的SQL Server就被当作牺牲者杀掉,
为了减少SQL Server被OOM影响,建议使用下面的一个或者两个:
在这个客户场景中,通过设置memory.memorylimitmb为6GB或者创建swap文件并调整大小来避免了oom-killer再次运行。
译者注:如果MSSQL进程突然挂了,可以用dmesg查看是否有OOM