如下所示,当我们使用服务器进行比较耗内存的操作的时候,我们的进程通常会出现由于内存不足被系统内核Kill掉的情况。
#tail -f /var/log/messages
Mar 26 12:53:14 iZbp10exab3v6j02ja125lZ kernel: [ 6569] 501 6569 6123845 1789213 0 0 0 mysqld
Mar 26 12:53:14 iZbp10exab3v6j02ja125lZ kernel: [ 6973] 0 6973 6821 131 0 0 0 mysqldump
Mar 26 12:53:14 iZbp10exab3v6j02ja125lZ kernel: Out of memory: Kill process 6569 (mysqld) score 875 or sacrifice child
Mar 26 12:53:14 iZbp10exab3v6j02ja125lZ kernel: Killed process 6569, UID 501, (mysqld) total-vm:24495380kB, anon-rss:7156712kB, file-rss:140kB
如何尽量避免服务器出现内存不足的错误?最简单的方法就是增加交换空间。Swap是存储盘上的一块自留地,操作系统可以在这里暂存一些内存里放不下的东西。
这从某种程度上相当于增加了服务器的可用内存。虽然从swap读写比内存慢,但总比没有好,算是内存不够时的安全网。
如果没有swap,则服务器一旦内存不足,就会开始终止应用以释放内存,甚至会崩溃,这会让你丢失一些还没来得及保存的数据,或者造成当机。有些应用明确要求系统配置swap以确保数据访问的可靠性。
首先我们需要检查系统的存储,看看是否已经配置过swap。一个系统可以设置多个swap文件或分区,不过一般来说一个就够了。
使用swapon命令可以检查系统是否已经配置过swap,这是一个通用的swap工具。使用-s标签可列出当前存储设备上的swap使用情况:
swapon -s
如果该命令没有返回出结果,则代表该系统尚未配置过swap。
或者使用 top 命令
[root@iZbp10exab3v6j02ja125lZ log]# top
top - 13:23:12 up 10 days, 22:22, 1 user, load average: 0.08, 0.03, 0.05
Tasks: 241 total, 1 running, 240 sleeping, 0 stopped, 0 zombie
Cpu0 : 0.3%us, 0.3%sy, 0.0%ni, 99.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu1 : 0.7%us, 0.3%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 8193452k total, 3570536k used, 4622916k free, 78428k buffers
Swap: 0k total, 0k used, 0k free, 314148k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
993 root 20 0 3536 260 172 S 0.3 0.0 5:51.26 aliyun-service
通常,我们建立一个单独的分区作为swap。然而有时候由于硬件或软件的限制,新建分区的方式无法实现,这种情况下就可以建立一个swap文件来实现同样的功能。
开始之前,先检查一下磁盘的可用空间。输入如下指令:
#df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 59G 1.5G 55G 3% /
devtmpfs 2.0G 0 2.0G 0% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 2.0G 8.3M 2.0G 1% /run
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
这里的-h标记是为了告诉df将信息输出为对人类友好的格式,比如以MB或GB为单位输出空间使用和空余情况,而不是直接输出内存块的个数。
从第一行可以看到我们的存储分区上还有55GB的空间剩余,这足够我们操作了。
合适的swap空间是多大?关于这个问题有很多种选择,这取决于你的应用需求和你个人的偏好。一般来说,内存容量的两倍就是个不错的起点。
我的系统内存有8GB,如果设置8GB的swap会占据太多空间,所以我决定只设置4GB就好。
接下来我们将在文件系统上创建swap文件。我们要在根目录(/)下创建一个名叫swapfile的文件,当然你也可以选择你喜欢的文件名。该文件分配的空间将等于我们需要的swap空间。
最快捷的创建方式是fallocate命令,该命令能够创建一个预分配指定大小空间的文件。输入如下指令创建一个4GB的文件:
fallocate -l 4G /swapfile
swap文件将立即创建完毕。我们可以用ls命令检查文件大小:
[root@iZbp10exab3v6j02ja125lZ /]# ls -lh /swapfile
-rw-r--r-- 1 root root 4.0G Mar 26 13:24 /swapfile
至此,我们的swap文件就创建完毕了。
现在我们已经有了swap文件,但系统还不知道应该使用该文件作为swap,这就需要我们告知系统将该文件格式化为swap并启用起来。
首先我们需要更改swap文件的权限,确保只有root才可读,否则会有很大的安全隐患。使用chmod命令进行权限操作:
chmod 600 /swapfile
如此,该文件的读写都只有root才能操作。使用ls -lh命令检查一下:
[root@iZbp10exab3v6j02ja125lZ /]# ls -lh /swapfile
-rw------- 1 root root 4.0G Mar 26 13:24 /swapfile
然后,使用如下命令告知系统将该文件用于swap:
[root@iZbp10exab3v6j02ja125lZ /]# mkswap -f /swapfile
Setting up swapspace version 1, size = 4194300 KiB
no label, UUID=2a92ce63-8f40-40ff-9de3-5240a6469cf8
现在,这个swap文件就可以作为swap空间使用了。输入如下命令开始使用该swap:
swapon /swapfile
我们可以输入如下命令来确认一下设置是否已经生效:
[root@iZbp10exab3v6j02ja125lZ /]# swapon -s
Filename Type Size Used Priority
/swapfile file 4194300 0 -1
可以看到返回的结果中已经有我们刚才设置的swap。再使用top工具确认一下:
[root@iZbp10exab3v6j02ja125lZ /]# top
top - 13:26:47 up 10 days, 22:26, 1 user, load average: 0.24, 0.09, 0.06
Tasks: 241 total, 1 running, 240 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.3%us, 0.7%sy, 0.0%ni, 97.8%id, 1.2%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 8193452k total, 3600800k used, 4592652k free, 86496k buffers
Swap: 4194300k total, 0k used, 4194300k free, 324044k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1650 root 10 -10 130m 11m 2340 S 1.3 0.1 65:08.36 AliYunDun
至此我们已经在系统中启用了swap文件,然而一旦系统重启后,服务器还不能自动启用该文件。要让系统在重启后自动生效swap,我们可以通过修改fstab文件来实现(这是一个管理文件系统和分区的表)。
用sudo权限打开该文件编辑:
vim /etc/fstab
在文件末尾加入下面这行内容,告诉操作系统自动使用刚才创建的swap文件:
/swapfile swap swap sw 0 0
添加完毕后,保存退出。以后服务器每次重启都会检查该文件并自动启用swap。
swappiness参数决定了系统将数据从内存交换到swap空间的频率,数值设置在0到100之间,代表系统将数据从内存交换到swap空间的力度。
该数值越接近于0,系统越倾向于不进行swap,仅在必要的时候进行swap操作。由于swap要比内存慢很多,因此减少对swap的依赖意味着更高的系统性能。
该数值越接近于100,系统越倾向于多进行swap。有些应用的内存使用习惯更适合于这种情况,这也于服务器的用途有关。
输入如下命令查看当前的swappiness数值:
cat /proc/sys/vm/swappiness
30
CentOS 7默认设置了30的swappiness,这对于大部分桌面系统和本地服务器是比较中庸的数值。
一般来讲,我们期望系统越倾向于不进行swap,仅在必要的时候进行swap操作。
#vim /etc/sysctl.conf
vm.swappiness = 0