一段时间以来,我一直在处理一个奇怪的问题:运行几天后,我的一个虚拟机似乎在执行 CPU 密集型任务时变慢了。这种情况发生的一个例子是在 ClamD 中读取病毒签名数据库,只需重新启动守护进程,发送信号USR2
再次读取签名,或者因为配置的签名检查超时已过。
重新启动虚拟机后,读取病毒数据库是一个快速的操作,大约需要 35 秒,如果重复,则非常稳定。运行几天后,会发生“某些事情”,使加载这些签名成为一项非常缓慢的操作,如果虚拟机在白天额外处理它通常需要做的事情,则需要 15 分钟甚至 20 分钟(!)。在晚上,它会快一点,可能只需要一半的时间,但仍然需要很多分钟,而如果没有发生“某些事情”,它总是远远少于一分钟。
我的问题是,我找不到导致这些问题的“原因”。但在发生那件奇怪的事情之后,它不仅影响了 ClamD 的签名加载,人们只能在这种情况下很好地看到问题,而且似乎影响了所有受 CPU 限制的事物。我感觉好像 CPU 上出现了某种手刹:每当进行受 CPU 限制的事物时,所有其他进程似乎也会累积起来,给系统带来非常高的负载,使其变慢,直到无法再使用简单的光标键导航(例如 Midnight Commander ( mc
))。在发生那件“事情”之后,重新启动为多个不同的 Web 应用程序提供服务的 Apache Tomcat 也会触发这种影响,重新启动所需的时间比以前要长得多。
这些影响显而易见htop
:
如此高的负载只是因为 ClamD 进程,通常负载不会这么高,尤其是对 Tomcat 的请求通常处理得相当快。一旦 ClamD 完成,总体负载就会再次降低很多。另外请注意,ClamD 占用的 CPU 超过 100%,这通常不是这种情况,因为读取签名仅由一个 CPU 完成。下一张图片也很有趣:
Tomcat 处理完上述请求后,所有 CPU 上的负载都会下降,ClamD 恢复到正常的状态,负载约为 100%。但事实并非如此,ClamD 耗时太长,它已经工作了几分钟,其他顶级进程(如htop
它自己)也不应该产生如此高的负载。没有运行 ClamD 时,负载约为 2-3%。
因此,看起来那些处理时间短的东西正在变慢,但仍然“足够快”,而所有消耗大量 CPU 的东西,如 ClamD 或 Tomcat,都变得非常慢,并且使其他进程也变慢。这甚至可以在 ClamD 的日志中看到,它开始快速重新加载,然后变得更慢:
Tue May 1 11:56:26 2018 -> Reading databases from /var/lib/clamav
Tue May 1 11:57:01 2018 -> Database correctly reloaded (10566159 signatures)
Tue May 1 19:11:07 2018 -> Reading databases from /var/lib/clamav
Tue May 1 19:11:47 2018 -> Database correctly reloaded (10566159 signatures)
Wed May 2 00:51:15 2018 -> Reading databases from /var/lib/clamav
Wed May 2 00:51:53 2018 -> Database correctly reloaded (10578504 signatures)
Wed May 2 03:41:56 2018 -> Reading databases from /var/lib/clamav
Wed May 2 03:42:31 2018 -> Database correctly reloaded (10579770 signatures)
Wed May 2 20:45:32 2018 -> Reading databases from /var/lib/clamav
Wed May 2 20:46:07 2018 -> Database correctly reloaded (10579770 signatures)
Thu May 3 00:52:29 2018 -> Reading databases from /var/lib/clamav
Thu May 3 00:53:08 2018 -> Database correctly reloaded (10584928 signatures)
Thu May 3 03:42:07 2018 -> Reading databases from /var/lib/clamav
Thu May 3 03:42:46 2018 -> Database correctly reloaded (10586235 signatures)
Thu May 3 08:52:18 2018 -> Reading databases from /var/lib/clamav
Thu May 3 08:53:06 2018 -> Database correctly reloaded (10586235 signatures)
Fri May 4 01:00:30 2018 -> Reading databases from /var/lib/clamav
Fri May 4 01:01:53 2018 -> Database correctly reloaded (10586721 signatures)
Fri May 4 03:42:43 2018 -> Reading databases from /var/lib/clamav
Fri May 4 03:44:01 2018 -> Database correctly reloaded (10588026 signatures)
[...]
Sat May 5 00:56:17 2018 -> Reading databases from /var/lib/clamav
Sat May 5 00:59:48 2018 -> Database correctly reloaded (10589668 signatures)
Sat May 5 03:47:01 2018 -> Reading databases from /var/lib/clamav
Sat May 5 03:53:47 2018 -> Database correctly reloaded (10590874 signatures)
Sat May 5 13:40:49 2018 -> Reading databases from /var/lib/clamav
Sat May 5 13:56:33 2018 -> Database correctly reloaded (10590874 signatures)
Sun May 6 01:00:20 2018 -> Reading databases from /var/lib/clamav
Sun May 6 01:09:27 2018 -> Database correctly reloaded (10597394 signatures)
Sun May 6 03:51:45 2018 -> Reading databases from /var/lib/clamav
Sun May 6 03:59:11 2018 -> Database correctly reloaded (10598555 signatures)
更糟糕的是,我无法在具有几乎相同硬件和软件设置的非常相似的 VM 上重现问题。我在其他 3 台具有相同 OS 等但不同负载、软件等的 VM 中使用具有相同版本、设置和签名的 ClamD,问题并未在这些 VM 上发生,尽管 ClamD 几乎每小时都会重新加载一次,因此在日志中可以更容易地发现这一点。此外,当 VM 运行缓慢时,没有繁重的 I/O 负载(iostat
),没有繁重的上下文切换(mpstat
),VM 主机本身不会耗尽资源,并且无法通过从头开始重新创建 VM 并安装新 OS 来解决问题。我很确定这也不是纯粹的性能瓶颈,因为 1. 问题仅在某些事件之后开始发生,之前一切都很快,并且 2. 我尝试使用资源少得多的 VM 重现该问题,但并未发生该问题。
VM 本身是 Ubuntu 16.04,8 个 vCPU,48 GB RAM。VM 主机是 Ubuntu 16.04,配备 2 个 Intel(R) Xeon(R) CPU X5675 @ 3.07 GHz,启用超线程,因此总共有 24 个逻辑 CPU 和 148 GB RAM。通常这些资源足以快速为我的应用程序提供服务。使用的虚拟机管理程序是 VirtualBox 5.2.10。
还有什么想法可以调试这个问题吗?是什么“东西”造成了问题?谢谢!
答案1
至少在这个特定情况下,它与分配给虚拟机的内存量有关。问题发生在使用具有 48 GiB RAM 的虚拟机可靠运行几个小时或几天后,而使用更少的内存则不会发生,目前测试的最大内存为 24 GiB。详细信息可在另一个问题中阅读:
使用 48 GB RAM 的虚拟机运行几天后就会变得很慢,而使用 6 GB RAM 则不会
甚至如下方法似乎largepages
也无法完全解决问题:
https://superuser.com/questions/1326572/maximum-ram-size-for-a-vm-with-largepages-off-in-virtualbox
我看到的行为非常符合以下情况Linux 内核讨论的问题:
内存管理性能倒退的决斗
尽管它主要谈论的是交换,补丁修复者这也只会导致 CPU 负载过重:
vfio 是一个很好的测试,因为通过固定所有内存,它可以避免交换,并且回收只浪费 CPU,基于 memhog 的测试会产生交换风暴,并且可能会显示更大的 stddev。
有一件事我不确定,那就是影响,Transparent Huge Pages
因为虽然在我的系统中默认启用了它们,但 VirtualBox 似乎并不使用它们,而且它们似乎是针对操作系统设置而选择的:
$ cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never
$ cat /sys/kernel/mm/transparent_hugepage/defrag
always defer defer+madvise [madvise] never
其余一切都与我所看到的完全吻合。