我们有一台运行 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
/proc/meminfo
有
Committed_AS: 12951172 kB
因此,即使分配的所有内容实际上都被立即使用,仍然有大量的可用内存。然而,系统甚至会立即对正在运行的进程进行分页。
这在 Gitlab 中最为显着,这是一个使用 Unicorn 的 Rails 应用程序:新分叉的 Unicorn 工作线程会立即交换,当收到请求时,需要以约 1400kB/s 的速度从磁盘读取(数据来自iotop
),并会遇到超时(目前为 30 秒) ,以使其及时重新启动。正常请求在完全加载到内存之前不应花费超过 5 秒,从而立即被杀死。请注意,这只是一个示例,我已经看到这种情况发生在 redis、amavis、postgres、mysql、java(openjdk) 等上。
否则系统处于低负载情况,CPU 利用率约为 5%,平均负载约为 2(在 8 个内核上)。
我们尝试过的(排名不分先后):
swapoff -a
: 800M左右失败仍然交换- 使用 减少交换性(逐步)
sysctl vm.swappiness=NN
。这似乎根本没有影响,我们降到了 0%,但仍然存在完全相同的行为 - 停止非必要的服务(Gitlab,一个基于 Jetty 的网络应用程序......),释放约。 8G 已提交但未映射的内存,并将 Comfilled_AS 减少到大约 5G。一点变化都没有。
- 使用 清除系统缓存
sync && echo 3 > /proc/sys/vm/drop_caches
。这会释放内存,但对交换情况没有任何作用。 - 上述的组合
重新启动机器以通过 fstab 完全禁用交换作为测试并不是真正的选择,因为某些服务存在可用性问题并且需要计划停机时间,而不是“四处寻找”......而且我们真的不想禁用交换作为倒退。
我不明白为什么这里会发生任何交换。有什么想法可能会发生什么吗?
这个问题已经存在了一段时间了,但它首先出现在高IO负载(长时间的后台数据处理任务)期间,所以我无法确定具体的事件。这个任务已经完成几天了,问题仍然存在,因此这个问题。
答案1
记住我是怎么说的:
该系统使用 lxc 容器进行划分,但这在这里并不重要。
好吧,事实证明做过事情。或者更确切地说,处于 lxc 核心的 cgroup 很重要。
主机只能看到内核升级时的重新启动。那么,最后使用的内核是什么? 3.19,两个月前被 4.0.5 取代,昨天被 4.1.3 取代。昨天发生了什么?左、右、中的进程被 memkilled。经检查/var/log/kern.log
,受影响的进程位于内存为512M的cgroup中。等等,512M?这是不对的(当预期要求约为 4G 时!)。事实证明,这正是我们几个月前设置时在 lxc 配置中配置的内容。
所以,3.19 完全忽略了 cgroup 的内存限制;如果 cgroup 需要的数量超过允许的数量,4.0.5 总是进行分页(这是这个问题的核心问题),并且只有 4.1.3 执行完整的 memkiller-sweep。
主机系统的交换性对此没有影响,因为它从来没有接近物理内存不足的情况。
解决方案:
对于临时更改,您可以直接修改 cgroup,例如调用名为box1
cgroup 的lxc 容器lxc/box1
,并且您可以执行(作为主机中的 root):
$ echo 8G > /sys/fs/cgroup/memory/lxc/box1/memory.limit_in_bytes
永久的解决方案是正确配置容器/var/lb/lxc/...
lxc.cgroup.memory.limit_in_bytes = 8G
故事的道德启示:始终检查您的配置。即使您认为这不可能是问题(并且内核中存在不同的错误/不一致实际上会失败)。