具有大量空闲内存的永久交换

Mar*_*tok 6 linux debian swap cgroups lxc

我们有一台运行 Debian 4.0.5(内核 4.0.0-2)的 Linux 服务器,安装了 32G RAM 并配置了 16G Swap。系统使用 lxc 容器进行分区,但这在这里无关紧要。该问题存在于不同容器的内部和外部。

这是一个典型的free -h

              total        used        free      shared  buff/cache   available
Mem:            28G        2.1G         25G         15M        936M         26G
Swap:           15G        1.4G         14G
Run Code Online (Sandbox Code Playgroud)

/proc/meminfo

Committed_AS:   12951172 kB
Run Code Online (Sandbox Code Playgroud)

所以有足够的空闲内存,即使分配的所有内容都被一次实际使用。但是,系统会立即对正在运行的进程进行分页。

这在 Gitlab 中最为显着,这是一个使用 Unicorn 的 Rails 应用程序:新分叉的 Unicorn 工作线程会立即交换,并且当需要以 ~1400kB/s(来自 的数据iotop)从磁盘读取请求时,会遇到超时(现在为 30 秒) , 以使其及时重新启动。正常请求不会超过 5s) 才能完全加载到内存中,从而立即被杀死。请注意,这只是一个例子,我在 redis、amavis、postgres、mysql、java(openjdk) 和其他人身上看到过这种情况。

否则,系统处于低负载状态,CPU 利用率约为 5%,平均负载约为 2(8 核)。

我们尝试了什么(没有特别的顺序):

  1. swapoff -a: 在大约 800M 处失败仍然交换
  2. 使用sysctl vm.swappiness=NN. 这似乎根本没有影响,我们降到了 0%,但仍然存在完全相同的行为
  3. 停止非必要服务(Gitlab,一个基于 Jetty 的网络应用程序......),释放大约。8G 已提交但未映射的内存,并将 Committed_AS 降至约 5G。根本没有变化。
  4. 使用sync && echo 3 > /proc/sys/vm/drop_caches. 这释放了内存,但对交换情况没有任何作用。
  5. 以上的组合

重新启动机器以通过 fstab 完全禁用交换作为测试并不是一个真正的选择,因为某些服务存在可用性问题并且需要计划停机时间,而不是“四处闲逛”......而且我们真的不想禁用交换作为倒退。

我不明白为什么这里会发生任何交换。任何想法可能会发生什么?


这个问题已经存在一段时间了,但是在高IO负载(长时间的后台数据处理任务)期间首先出现,因此我无法确定特定事件。此任务已完成几天,问题仍然存在,因此出现此问题。

Mar*_*tok 8

记得我是怎么说的:

系统使用 lxc 容器进行分区,但这在这里无关紧要。

好吧,事实证明这确实很重要。或者更确切地说,lxc 核心的 cgroup 很重要。

主机只能看到内核升级的重启。那么,最后使用的内核是什么?3.19,在 2 个月前和昨天被 4.0.5 替换为 4.1.3。昨天发生了什么?进程在左、右和中间被 memkilled。检查/var/log/kern.log,受影响的进程在具有 512M 内存的 cgroups 中。等等,512M?这不可能是对的(当预期的要求是 4G 左右时!)。事实证明,这正是我们几个月前在 lxc 配置中配置的内容。

所以,发生的事情是 3.19 完全忽略了 cgroup 的内存限制;4.0.5 总是在 cgroup 需要的超过允许的范围内分页(这是这个问题的核心问题),并且只有 4.1.3 会执行完整的 memkiller-sweep。

主机系统的swappiness对此没有影响,因为它从来没有接近物理内存不足。

解决方案:

对于临时更改,您可以直接修改 cgroup,例如box1调用名为cgroup的 lxc 容器lxc/box1,您可以执行(在主机中以 root 身份执行):

$ echo 8G > /sys/fs/cgroup/memory/lxc/box1/memory.limit_in_bytes
Run Code Online (Sandbox Code Playgroud)

永久的解决方案是正确配置容器 /var/lb/lxc/...

lxc.cgroup.memory.limit_in_bytes = 8G
Run Code Online (Sandbox Code Playgroud)

故事寓意:始终检查您的配置。即使您认为这不可能是问题(并且内核中存在不同的错误/不一致导致实际失败)。