SWAP的罪与罚

SWAP的罪与罚

发表于2012-11-08html

说个案例:一台Apache服务器,因为其MaxClients参数设置过大,而且刚好又碰到访问量激增,结果内存被耗光,从而引起SWAP,进而负载攀升,最终致使宕机。java

 

正所谓:SWAP,性能之大事,死生之地,存亡之道,不可不察也。node

哪些工具能够监测SWAP

最容易想到的就是free命令了,它指明了当前SWAP的使用状况:mysql

shell> free -m
             total       used       free
Swap:        34175      11374      22801

另外一个经常使用的是sar命令,它能列出系统在各个时间的SWAP使用状况:linux

shell> sar -r
kbswpfree kbswpused  %swpused  kbswpcad
 23345644  11650572     33.29   4656908
 23346452  11649764     33.29   4656216
 23346556  11649660     33.29   4650308
 23346932  11649284     33.29   4649888
 23346992  11649224     33.29   4648848

不过free命令和sar命令显示的都不是实时数据,若是须要,可使用vmstat命令:git

shell> vmstat 1
-----------memory------------- ---swap--
  swpd   free   buff   cache     si   so
11647532 123664 305064 7193168    0    0
11647532 123672 305064 7193172    0    0
11647532 125728 305064 7193468    0    0
11647532 125376 305064 7193476    0    0
11647532 124508 305068 7193624    0    0

每秒刷新一次结果,在SWAP一栏里列出了相关数据,至于si和so的解释,大体以下:github

  • si: Amount of memory swapped in from disk (/s).
  • so: Amount of memory swapped to disk (/s).

若是它们一直是零固然最好不过了,偶尔不为零也没啥,糟糕的是一直不为零。sql

前面介绍的方法,看到的都是SWAP的总体状况,但是若是我想查看究竟是哪些进程使用了SWAP,应该如何操做呢?这个问题有点棘手,咱们来研究一下:shell

好消息是top命令能提供这个信息,不过缺省并无显示,咱们须要激活一下:数据库

  1. 打开top;
  2. 按「f」进入选择字段的界面;
  3. 按「p」选择「SWAP」字段;
  4. 按回车确认。

坏消息是top命令提供的SWAP信息只是一个理论值,或者更直白一点儿来讲它根本就是不可信的(在top里SWAP的计算公式是:SWAP=VIRT-RES)。

BTW:相比之下,top里的「nFLT」字段更有价值,它表示PageFault的次数。

那到底咱们能不能获取到进程的SWAP状况呢?别着急,看代码:

#!/bin/bash

cd /proc

for pid in [0-9]*; do
    command=$(cat /proc/$pid/cmdline)

    swap=$(
        awk '
            BEGIN  { total = 0 }
            /Swap/ { total += $2 }
            END    { print total }
        ' /proc/$pid/smaps
    )

    if (( $swap > 0 )); then
        if [[ "${head}" != "yes" ]]; then
            echo -e "PID\tSWAP\tCOMMAND"
            head="yes"
        fi

        echo -e "${pid}\t${swap}\t${command}"
    fi
done

说明:请使用root权限来运行此脚本。

哪些因素可能影响SWAP

内存不足无疑会SWAP,但有些时候,即使看上去内存很充裕,还可能会SWAP,这种现象被称为SWAP Insanity,罪魁祸首主要有如下几点:

Swappiness的迷失

实际上,当可用内存不足时,系统有两个选择:一个是经过SWAP来释放内存,另外一个是删除Cache中的Page来释放内存。一个很常见的例子是:当拷贝大文件的时候,时常会发生SWAP现象。这是由于拷贝文件的时候,系统会把文件内容在Cache中按Page来缓存,此时一旦可用内存不足,系统便会倾向于经过SWAP来释放内存。

内核中的swappiness参数能够用来控制这种行为,缺省状况下,swappiness的值是60:

shell> sysctl -a | grep swappiness
vm.swappiness = 60

它的含义是:若是系统须要内存,有百分之六十的几率执行SWAP。知道了这一点,咱们很天然的会想到用下面的方法来下降执行SWAP的几率:

shell> echo "vm.swappiness = 1" >> /etc/sysctl.conf
shell> sysctl -p

这样作的确能够下降执行SWAP的几率,但并不意味着永远不会执行SWAP。据网友报道某些状况下,直接改成0有可能出现灵异问题,因此建议改成1。

NUMA的诅咒

NUMAMySQL社区有不少讨论,这里很少说了,直击NUMA和SWAP的恩怨纠葛。

大概了解一下NUMA最核心的numactl命令:

shell> numactl --hardware
available: 2 nodes (0-1)
node 0 size: 16131 MB
node 0 free: 100 MB
node 1 size: 16160 MB
node 1 free: 10 MB
node distances:
node   0   1
  0:  10  20
  1:  20  10

能够看到系统有两个节点(其实就是两个物理CPU),它们各自分了16G内存,其中零号节点还剩100M内存,一号节点还剩10M内存。设想启动了一个须要11M内存的进程,系统把它分给了一号节点来执行,此时虽然系统整体的可用内存大于该进程须要的内存,但由于一号节点自己剩余的可用内存不足,因此仍然可能会触发SWAP行为。

须要说明的一点事,numactl命令中看到的各节点剩余内存中时不包括Cache内存的,若是须要知道,咱们能够利用drop_caches参数先释放它:

shell> sysctl vm.drop_caches=1

注:这步操做可能会引发系统负载的震荡。

另:如何肯定一个进程的节点及内存分配状况?网络上有现成的脚本

若是要规避NUMA对SWAP的影响,最简单的方法就是在启动进程的时候禁用它:

shell> numactl --interleave=all ...

此外,内核参数zone_reclaim_mode一般也很重要,当某个节点可用内存不足时,若是为0的话,那么系统会倾向于从远程节点分配内存;若是为1的话,那么系统会倾向于从本地节点回收Cache内存。多数时候,Cache对性能很重要,因此0是一个更好的选择。

shell> echo "vm.zone_reclaim_mode = 0" >> /etc/sysctl.conf
shell> sysctl -p

另:网络上有一些关于MySQL和SWAP的讨论,对于理解SWAP有必定意义,推荐:

补:Memcached在启动的时候若是带上了k选项,就能避免使用SWAP,但要慎用。

早些年,YouTube曾经被SWAP问题困扰过,他们当时的解决方法很极端:删除SWAP!不得不说这真是艺高人胆大,惋惜对芸芸众生的咱们而言,这实在是太危险了,由于如此一来,一旦内存耗尽,因为没有SWAP的缓冲,系统会当即开始OOM,结果可能会让问题变得更加复杂,因此你们仍是安分守己作个老实人吧。

 

  1. Jacky在2012-11-08 16:33:29说道:

    Google内部绝大部分的服务都是直接取消swap的,由于相对于swap致使系统变慢而言,不如直接OOM死掉反而是很方便的方法——反正系统自己具备鲁棒性,原本就设计有容错机制的。

    回复 ↓

  2. 聪在2012-11-08 19:53:40说道:

    个人程序可能也遇到了这个问题。。线上导出大文件后,cache被吃掉不少内存,可能致使java那边的一些内存就被挤到swap了(但我在sar的历史日志里,没有看到swap明显升高,因此还不肯定。。)

    另外,若是用mlockall事先锁住一起内存给java使用是否可行呢?盼赐教。

    回复 ↓

    • 老王在2012-11-08 21:22:51说道:

      第一个问题信息不足没法回答;第二个问题答案是确定的,事实上,memcached就是用mlockall方法来禁止swap的(k选项)。

    • 聪在2012-11-08 21:35:29说道:

      多谢!

      我想进一步问一下。咱们线上用的是一台5g的虚拟机,ulimit -l结果是32。请问这个能不能设置成unlimited呢?
      比较担忧会对同宿主的其余虚拟机形成影响。

    • 老王在2012-11-08 22:22:36说道:

      理论上是能够设置max locked memory到unlimited的,不过这样虽然能够避免SWAP,可是还须要注意OOM的影响,你能够结合本身的程序模拟一些极端状况看看。只有测试才能给出正确的答案。

    • 聪在2012-11-09 09:40:30说道:

      好的。

  3. Pingback引用通告: 【转载】SWAP的罪与罚 | 一意孤星的世界

  4. 王子2012-11-10 21:16:10说道:

    这个东西玄乎的好像根本不可控制同样,这种资源问题原本就应该让系统来支配才对!本身还要去管理,好麻烦啊

    回复 ↓

  5. 轩脉刃2012-12-07 09:52:32说道:

    参考这篇文章:说的是为了追求程序速度,手动绑定NUMA,看来速度和内存是两个须要平衡的东西。。。

    回复 ↓

  6. link-tec2012-12-25 21:04:02说道:

    au,very nice..

    回复 ↓

  7. Terry2012-12-31 09:40:50说道:

    其实 dstat 也是很不错的工具;-) 从系统管理的角度来说(对 mysql 理解不够深刻),只要 vmstat 输出中 si/so 不频繁即说明物理内存还够用。free 输出中 free + cached + buffer = + buffers/cache 的值,内核参数 drop_caches 只能释放 page cache 一般内核会管理,不用人肉 drop ...

    经验告诉我在最好别设置 swappiness 为 0 不然系统可能出现诡异的性能问题,由于存在没法判断的突发内存消耗,致使 page out 系统性能急速恶化。

    回复 ↓

  8. ACb0y在2014-12-08 19:21:58说道:

    很好的分享。

    回复 ↓

  9. YQ在2015-01-16 10:25:45说道:

    “另外一个经常使用的是sar命令,它能列出系统在各个时间的SWAP使用状况:shell> sar -r”
    这里应该是 sar -S 吧。

    回复 ↓

  10. C永东在2015-09-22 16:10:03说道:

    今年新到一台HP服务器 安装了windows 08R2 数据库 MS SQL 08R2 双cpu 发现满负载的时候,任务管理器显示49% 其中的10核20线程所有到顶了;可是另一个CPU动都不动一下~ 这个是否是得取消掉默认的numa,改成普通的smp

相关文章
相关标签/搜索