问题
通常是发现服务器的内存先呈现出较高的资源占比,然后 CPU 资源暴涨,导致服务器无法工作。经过查看发现是 kswapd0 进程大量占用 CPU 资源所导致的。
操作系统会将磁盘的一部分构建为虚拟内存,但由于物理内存的速度要远远快于硬盘,所以操作系统会通过换页机制来实现物理内存与磁盘的通信。换页机制将暂时不需要的页面换到磁盘中,而需要的页面换到内存中。kswapd0进程即为负责换页的。在内存不足时,kswapd0会执行换页操作换页的操作。此操作十分占用CPU资源,并且由于磁盘的读写速度相较于内存慢上千倍,此操作一般会持续进行较长时间,从而导致系统出现无法访问之类的,似乎卡死的现象。
概念
物理内存和虚拟内存
物理内存(RAM)就是我们通常所理解的通过插入内存条而获得的内存。
虚拟内存是将硬盘的一块区域划分出来作为逻辑内存。这部分空间也被称为交换空间(swap space)。当物理内存不足时,可以用虚拟内存代替。
swap 分区和物理都有缓存区,缓存着之前使用过的数据,以便后续快速打开访问。
kswapd0
Linux uses kswapd for virtual memory management such that pages that have been recently accessed are kept in memory and less active pages are paged out to disk.
(what is a page?)…Linux uses manages memory in units called pages.
So,the kswapd process regularly decreases the ages of unreferenced pages…and at the end they are paged out(moved out) to disk系统每过一定时间就会唤醒 kswapd,看看内存是否紧张,如果不紧张,则睡眠。在 kswapd 中,有2个阀值,pages_hige 和 pages_low,当空闲内存页的数量低于 pages_low 的时候,kswapd 进程就会扫描内存并且每次释放出32个 free pages,直到 free page 的数量到达pages_high。
所有的进程都需要内存,但仅需要将常用的数据块一直保存在内存中,而不常用的对象可以在合适的时候读写到硬盘中。基于这点,Linux kernel通过采用分页和交换对内存进行调控,将进程的部分或全部内存换出到磁盘上,释放物理内存,以便充分利用物理内存的同时实现对常用文件的快速访问。将上述过程称之为交换区的换进换出(swap si/so )。其中:
si:将分页被重新读取到物理内存。也称作page-in
so:将内存中要交换的分页写到磁盘上。也称作page-out
当物理内存不足时,kswapd0 进程会控制持续进行换页操作,由于使用swap分区进行数据交换,因此 CPU 占用会很高。
swappiness
Linux 内核会在物理内存不足的时将暂时不用的内存块信息写到交换空间,以释放物理内存。
vm.swappiness是Linux内核的一个参数,用来决定是否进行物理内存和虚拟内存的数据交换。其取值范围为0~100,默认值为60,表示当物理内存低于40%(100-60)时使用swap空间。swappiness参数越低,表示Linux系统尽量少用swap分区,多用物理内存;swappiness参数值越高,表示使内核更多地去使用swap空间,交换的页面文件也越多。
- 查看 swappiness 参数
cat /proc/sys/vm/swappiness
- 根据需要,修改 swappiness 参数
vi /etc/sysctl.conf
在sysctl.conf文件中,修改vm.swappiness值为合适大小,然后保存退出。
- 重新加载sysctl.conf配置文件,使其生效
sysctl -p
通常,swap空间设为物理内存的1~2倍。若分配的swap空间太多会浪费磁盘空间,太少则会发生错误。系统的物理内存用光的时候,系统会跑的很慢(由于磁盘的读写速度远远小于物理内存),但仍然可以运行。但如果swap空间用光,此时的服务进程会出现“application is out of memory”的错误,严重时会造成服务进程的死锁。此外,若只有一个swap交换区,交换操作会使交换区工作变得繁忙而CPU的占用却较小。此时系统大多数时间处于等待状态,效率很低。这时候系统的速度取决于IO,因为swap交换页面的操作是通过磁盘IO进行的。而如果设置有多个swap交换区,swap空间的分配会以轮流的方式操作于所有的swap。大大均衡了IO的负载,加快了swap交换的速度。因此,swap空间分配设置是非常重要的。
buffer/cache
在 Linux 的内存管理中,buffer 和 cache 分别指 Buffer cache 和 Page cache,即缓冲区缓存和页面缓存。在过去,buffer 是被用来当成对 io 设备写的缓存,而cache 是被用来当作对 io 设备的读缓存。但在当前的内核中,page cache 就是针对内存页的缓存,即如果有内存是以 page 进行分配管理的,都可以使用 page cache 作为其缓存来管理使用;当有内存是以块 block 进行分配管理的,就会使用 buffer cache 来进行缓存。不过通常的操作下,二者是在一起配合产生作用的,例如对一个文件进行写入的时候,page cache 的内容会被改变,而 buffer cache 则负责将 page 标记为不同的缓冲区,并记录修改了哪一个缓冲区,这样如果后续需要执行脏数据的回写,内核就只需要写回修改的部分而不用将整个 page 写回。
通常缓存的使用情况如下图所示:
Mem 指物理内存,total 表示物理内存总量;used 表示分配给缓存(包括buffers和cached的)已使用的内存;free 表示未被分配的内存;shared 表示多个进程的共享内存;buff/cache 是系统分配但未被使用的内存;available 表示可用内存。它们之间满足:total = used + free + shared + buff/cache。真正使用的内存即为 used + free + shared 部分(或 total – buffers/cache)的值。
建议方案
-
无需干涉,停止对于服务器的操作,静待换页完成。
-
如上所述,修改vm.swappiness参数值
-
释放缓存
free -m # 查看当前剩余内存
此时窗口会呈现图 2 所示的对话列表,用以查看内存的使用情况。
/proc是一个虚拟文件系统,可以通过修改/proc中的文件,来对当前kernel的行为做出调整。因此,我们可以通过调整/proc/sys/vm/drop_caches来释放内存。操作如下:
sync # 写缓存到文件系统
echo 1 > /proc/sys/vm/drop_caches # 释放内存
echo 0 > /proc/sys/vm/drop_caches # 释放完内存后把drop_caches值改回去让系统重新自动分配内存
需要注意的是,一般情况下,系统将内存管理的很好,我们在生产环境中的服务器不要频繁的去释放内存,只在必要时候清理内存即可。主要应该考虑的是从应用程序层面去优化内存的利用和释放,其他的交给操作系统自己来管理。