我在两台 Debian 服务器上有一个由 PostgreSQL 驱动的 Web 服务,一台是运行 Linux 内核 3.2.0-2 的虚拟主机,具有 2GB RAM,另一台是运行 Linux 内核 2.6.26-1 的专用服务器,具有 6GB RAM。虽然应用程序占用的内存非常小,但随着时间的推移,缓存会填满到一定量,此时进程会被换出,从而增加系统负载,最终耗尽内存并最终导致内核崩溃(两个系统上的行为相同,只是时间段不同)。崩溃前,free -m
报告类似以下内容:
$ free -m
total used free shared buffers cached
Mem: 1978 1583 394 0 147 1208
-/+ buffers/cache: 227 1751
如果我重新启动系统,它会顺利运行一段时间(通常是几周或几个月,但有时只有几天),直到缓存再次填满。 重启后,free -m
报告:
$ free -m
total used free shared buffers cached
Mem: 1978 452 1526 0 6 302
-/+ buffers/cache: 143 1835
如果由于过度使用而出现峰值,服务器由于磁盘 I/O 而变慢,这对我来说是可以接受的,但是如果进程暂时需要更多内存,则磁盘缓存内存不会被回收,从而导致系统崩溃,这是不可接受的。
因此,在一台服务器上,我完全禁用了交换(因为交换时负载会增加到 300 - 400(如果进程被终止,就会产生连锁反应),导致系统无法使用,甚至无法通过远程登录启动重新启动。此外,我确实设置了内核调整参数vm.swappiness=0
,并vm.overcommit_memory=2
按照 PostgreSQL 高性能调整指南中的建议强制内核从缓存中回收内存并避免过度提交。
但这似乎没有达到预期的效果——上面的输出根本free
没有显示缓存缩小,而程序再次开始崩溃并出现no memory available
错误消息(上面的输出free
是在大约两个月的平稳运行后,在第一条no memory available
消息出现在系统日志中几秒钟后产生的)。
是否有可能避免这种过度缓存,以便能够将内存用于应用程序而不是用于磁盘 I/O?
增加物理内存并没有帮助,因为在配备 6GB 的系统上,当更多客户端连接到服务时,我迟早会得到相同的结果(这是一个免费公共使用的热点认证服务器,用户数量未知,由于各种原因,我需要坚持使用这两个服务器一段时间)。在虚拟主机上,我首先使用了 1GB,现在是 2GB - 这是我的虚拟主机的极限 - 到目前为止,我得到的只是缓存存储的增加,但进程的内存没有增加。这是它在 Linux 上应该工作的方式吗?只有 12% 的内存用于进程?还是 HPT 书中的上述建议不正确?
提前感谢任何提示!
你好,Michael,是的,看起来是这样。我还认为,如果用户空间应用程序需要更多内存,则应该释放内核缓存内存。但是看看这个输出,free(1)
我确实偶尔注意到系统何时再次变得无响应,这表明这种情况迟早会导致 OOM 杀手被踢出:
total used free shared buffers cached
Mem: 1978 981 997 0 142 638
-/+ buffers/cache: 200 1777
Swap: 0 0 0
在系统最终崩溃之前,我可以看到free Mem
降到零,但仍显示一些高值。我立即通过ing 和写入 3 来-/+ buffers/cache
清除缓存,从而释放内核内存:sync
/proc/sys/vm/drop_caches
total used free shared buffers cached
Mem: 1978 481 1496 0 1 283
-/+ buffers/cache: 196 1782
Swap: 0 0 0
因此,为了解决这个问题,我会不时手动清除缓存。不幸的是,我无法直接更新生产系统上的操作系统,而必须在更新之前更改系统以确保 99% 的可用性。在我们的临时系统上测试内核是可能的,但毫无用处,因为所描述的情况只会在我们每天处理数万个登录请求的生产系统上出现一段时间后。
free -m
顺便说一句,这是今天的输出:
total used free shared buffers cached
Mem: 1978 1107 871 0 146 753
-/+ buffers/cache: 207 1771
Swap: 0 0 0
如果我理解正确的话,应用程序和内核使用大约 190 到 227 MB,而缓冲区和缓存则消耗其余内存。我确信问题与某些应用程序无关,因为如果我重新启动应用程序,什么都不会改变,但它有助于手动清除缓存。
答案1
一些内部内核添加更多控制超过页面缓存限制。如果您选择的内核有限,也许可以使用 cgroup 来限制整个 LXC 的内存使用量。最后一种方法是,由于许多应用服务器不需要大量磁盘 io。如果是这种情况,只需添加一个 cron 作业来执行:
echo 1 > /proc/sys/vm/drop_caches