Holmesian Blog

FreeBSD在ESXi中性能极差

五一的时候 yycrazy 本来准备对服务器上的应用进行一次分离操作,但是由于极差的网络性能铩羽而归。自从五一过后,服务器一直处于极度不稳定状态:系统会不定期且毫无征兆地出现所有 phpcgi 进程突然卡死的情况,这会导致 CPU 负载飙升,并使得全站所有动态内容访问变得很慢,最终全线崩溃。

一开始找了很多资料,尝试了很多方法,但都没有明显的好转。因为没有任何明确的触发条件,并且所有等级的日志和监控都无法记录任何蛛丝马迹,所以一时很难做出准确判断。无意中在网上看到有用户反映 Discuz X 1.5 在 nginx + php-cgi 环境下使用 manyou 应用的时候,很容易导致 php-cgi 进程高负载运行,大量消耗 CPU 资源。于是尝试将开启的 Discuz X 1.5 的 manyou 应用关闭,发现问题得到了很大的缓解。本来以为已经解决了,但是第二天凌晨时,再度出现毫无征兆的所有 phpcgi 进程突然卡死的情况,这让我无奈地从更底层的角度去考虑解决办法。

经过漫长的排查与测试,最终发现问题出在 /boot/loader.conf 中的设置上。一开始安装 FreeBSD 的时候,顺手复制了之前一份优化过的 loader.conf 配置的一部分,里面有一个参数 kern.ipc.nmbclusters="0",本来只是想将 nmbclusters 设置成无限制,但问题就出在只复制了一部分:因为在 kern.ipc.nmbclusters 被设置成 0 的情况下,net.inet.tcp.reass.maxsegments 参数也跟着一同被设置成 0 了。net.inet.tcp.reass.maxsegments 被设置成 0 之后,在有大量 TCP out-of-order 数据包的网络情况下,FreeBSD 的性能将会变得极差,而且整个系统会非常脆弱。在出现问题的时候,用 netstat 查看连接信息,可以发现 packets discarded due to memory problems 的计数相当多,而 TCP out-of-order 的计数永远为 0。

解决方法:

  1. net.inet.tcp.reass.maxsegments 设置成默认值 1600;
  2. 设置 kern.ipc.nmbclusters 为一个非 0 的数值,例如我将 kern.ipc.nmbclusters="102400" 添加到了 /boot/loader.conf 文件中。

修改成功后重启 FreeBSD,至少目前没有再出现过系统毫无征兆的所有 phpcgi 进程突然卡死的情况了……


在漫长的排查过程中,又发现了一个有趣的情况:记得之前 FreeBSD 在 ESXi 下时间会走慢的时候,是通过向 loader.conf 文件添加 hint.apic.0.disabled="1" 以关闭中断和 kern.hz = 100 调整刷新率来修正时间问题。这次尝试着将 kern.hz 调成 10 重启之后,发现在 ESXi 中的 FreeBSD 8 性能变得出奇地好……不过问题是 FreeBSD 8 中的时间大概是真实时间的 2~4 倍。最终将 kern.hz 调成了 50,时间不再跑偏,而且性能和响应速度相对于之前要好很多。看起来好像 kern.hz 在多用户多进程的情况下调低更好,桌面系统单用户的情况下调高更好。

关于 kern.hz 在 FreeBSD 的论坛上有这么一段话供参考:

这是一个已知的性能问题。虚拟机的中断是经过虚拟化软件来进行处理的,而不是直接的硬件中断;当 guest OS 定时器精度较高时,如 1000 Hz (这是新版内核的默认情况,早期内核的精度是 100 Hz 甚至 10 Hz),直接在硬件上运行操作系统通常是没有问题的,但虚拟机将花费较多的 host CPU 时间来处理定时器对应的系统中断,因此用户会发现 CPU 占用变高,甚至在“空闲”时也能达到 50% ~ 100%;解决的办法是降低 guest OS 定时器的精度,以牺牲精度来换取性能。如果您的 host CPU 支持硬件虚拟化技术(Intel VT 或 AMD-V),您还可以试着打开 VirtualBox 的 hardware virtualization,这应该可以继续改善虚拟机的性能。

参考文章

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »