高性能MySQL:内存交换区

作者:港云互联 时间:2020-01-08

        当操作系统因为没有足够的内存而将一 些虚拟内存写到磁盘就会发生内存交换。内存交换对操作系统中运行的进程是透明的。只有操作系统知道特定的虚拟内存地址是在物理内存还是硬盘。



        内存交换对MySQL性能影响是很精糕的。它破坏了缓存在内存的目的,并且相对于使用很小的内存做缓存,使用交换区的性能更差。MySOL和存储引单有很多算法来区别对待内存中的数据和硬盘上的数据,因为般都假设内存数据访向代价更低。



        因为内存交换对用户进程不可见,MySQL (成存储引擎)并不知道数据实际上已经移动到磁盘,还会以为在内存中。



        结果会导致很差的性能。例如,若存储引擎认为数据依然在内存,可能觉得为“短析”的内存操作锁定一个全局互斥变量(例如InoDB缓冲池Mutex)是OK的。如果这个操作实际上引起了硬盘I/O,直到I/0操作完成前任何操作都会被挂起。这意味着内存交换比直接做硬盘I/O操作还要糟糕。

高性能MySQL:内存交换区


        在GNU/Linux上,可以用vmstat (在下一部分展示了一些例子)来监控内存交换。最好查看si和so列报告的内存交换1I/O活动,这比看swpd列报告的交换区利用率更重要。swpd列可以展示那些被载入了但是没有被使用的进程,它们并不是真的会成为问题。我们喜欢si和so列的值为0,并且一定要保证它们低于每秒10个块。



        极端的场景下,太多的内存交换可能导致操作系统交换空间溢出。如果发生了这种情况,缺乏虚拟内存可能让MySQL崩溃。但是即使交换空间没有溢出,非常活跃的内存交换也会导致整个操作系统变得无法响应,到这种时候甚至不能登录系统去杀掉MySQL进程。有时当交换空间溢出时,甚至Linux内核都会完全hang住。



        绝不要让系统的虚拟内存溢出!对交换空间利用率做好监控和报警。如果不知道需要多少交换空间,就在硬盘上尽可能多地分配空间,这不会对性能造成冲击,只是消耗了硬盘空间。有些大的组织清楚地知道内存消耗将有多大,并且内存交换被非常严格地控制,但是对于只有少量多用途的MySQL实例,并且工作负载也多种多样的环境,通常不切实际。如果后者的描述更符合实际情况,确认给服务器一些 “呼吸” 的空间,分配足够的交换空间。



        在特别大的内存压力下经常发生的另一件事是内存不足(OOM), 这会导致踢掉和杀掉一些进程。在MySQL进程这很常见。在另外的进程上也挺常见,比如SSH,甚至会让系统不能从网络访问。可以通过设置SSH进程的oom adj 或oom score adj 值来避免这种情况。



        可以通过正确地配置MySQL缓冲来解决大部分内存交换问题,但是有时操作系统的虚拟内存系统还是会决定交换MySQL的内存。这通常发生在操作系统看到MySQL发出了大量I/O,因此尝试增加文件缓在来保在更多数据时,如果没有足够的内存,有些东西就必须被交换出去,有些可能就是MySQL本身。有些老的Linux内核版本也有些适得其反的优先级,导致本不应该被交换的被交换出去,但是在最近的内核都被缓解了。



        有些人主张完全禁用交换文件。尽管这样做有时在某些内核拒绝工作的极端场景下是可行的,但这降低了操作系统的性能(在理论上不会,但是实际上会的)。同时这样做也是很危险的,因为禁用内存交换就相当于给虚拟内存设置了一个不可动摇的限制。如果MySQL需要临时使用很大一块内存, 或者有很耗内存的进程运行在同一台机器(如夜间批量任务),MySQL 可能会内存溢出、崩溃,或者被操作系统杀死。



        操作系统通常允许对虚拟内存和I/O进行一些控制。我们提供过一些GNU/Linux上控制它们的办法。最基本的方法是修改/proc/sys/vm/swappiness为一个 很小的值,例如0或1.这告诉内核除非虚拟内存完全满了,否则不要使用交换区。下面是如何检查这个值的例子:



$ cat /proc/sys/vm/swappiness


60



        这个值显示为60,这是默认的设置(范围是0~ 100)。对服务器而言这是个很糟糕的默认值。这个值只对笔记本适用。服务器应该设置为0 :



$ echo 0 > /proc/sys/vm/swappiness



        另一个选项是修改存储引擎怎么读取和写人数据。例如,使用innodb_flush method=0_DIRECT,减轻I/O压力。Direct I/O并不缓存,因此操作系统并不能把MySQL视为增加文件缓存的原因。这个参数只对InnoDB有效。你也可以使用大页,不参与换入换出。这对MyISAM和InnoDB都有效。



        另一个选择是使 用MySQL的memlock配置项,可以把MySQL锁定在内存。这可以避免交换,但是也可能带来危险:如果没有足够的可锁定内存,MySQL在尝试分配更多内存时会崩溃。这也可能导致锁定的内存太多而没有足够的内存留给操作系统。



        很多技巧都是对于特定内核版本的,因此要小心,尤其是当升级的时候。在某些工作负载下,很难让操作系统的行为合情合理,井且仅有的资源可能让缓冲大小达不到最满意的值。


新人注册,即送价值满880元现金劵

立即注册>>
客服 电话 反馈 活动 回顶部

服务热线

+852-5764-9835

1对1贴心服务,7X24小时热线