今天,我们的一台 HAProxy VM 出现了一点故障转移问题。深入研究后,我们发现了以下问题:
1 月 26 日 07:41:45 haproxy2 内核:[226818.070059] __ratelimit:抑制了 10 个回调 1 月 26 日 07:41:45 haproxy2 内核:[226818.070064] 套接字内存不足 1 月 26 日 07:41:47 haproxy2 内核:[226819.560048] 套接字内存不足 1 月 26 日 07:41:49 haproxy2 内核:[226822.030044] 套接字内存不足
其中,每此链接,显然与 的低默认设置有关net.ipv4.tcp_mem
。因此,我们将其默认值增加了 4 倍(这是 Ubuntu Server,不确定 Linux 版本是否重要):
当前值为:45984 61312 91968 新值为:183936 245248 367872
此后,我们开始看到一个奇怪的错误消息:
1 月 26 日 08:18:49 haproxy1 内核:[2291.579726] 路由哈希链太长! 1 月 26 日 08:18:49 haproxy1 内核:[2291.579732] 调整您的 secret_interval!
嘘。。这是个秘密!!
/proc/sys/net/ipv4/route/secret_interval
这显然与默认值 600 和控制有关定期刷新路由缓存
指示
secret_interval
内核多久清除一次所有路由哈希条目,无论它们有多新/多旧。在我们的环境中,这通常很糟糕。每次清除缓存时,CPU 都会忙于每秒重建数千个条目。但是,我们将其设置为每天运行一次,以防止内存泄漏(尽管我们从未遇到过这种情况)。
虽然我们很高兴能减少这种情况,建议定期删除整个路由缓存似乎有点奇怪,而不是简单地将旧值更快地推出路由缓存。
经过一番调查,我们发现/proc/sys/net/ipv4/route/gc_elasticity
这似乎是控制路由表大小的更好选择:
gc_elasticity
可以最好地描述为内核在开始使路由哈希条目过期之前将接受的平均桶深度。这将有助于维持活动路由的上限。
我们将弹性从 8 调整到 4,希望路由缓存能够更积极地进行自我修剪。我们觉得这secret_interval
不对。但有很多设置,不清楚哪些才是真正正确的选择。
- /proc/sys/net/ipv4/route/gc_elasticity (8)
- /proc/sys/net/ipv4/route/gc_interval (60)
- /proc/sys/net/ipv4/route/gc_min_interval (0)
- /proc/sys/net/ipv4/route/gc_timeout (300)
- /proc/sys/net/ipv4/route/secret_interval (600)
- /proc/sys/net/ipv4/route/gc_thresh (?)
- rhash_entries(内核参数,默认值未知?)
我们不想让 Linux 路由更差,所以我们有点害怕弄乱这些设置。
对于高流量的 HAProxy 实例,有人可以建议哪些路由参数最适合调整吗?
答案1
我从来没有遇到过这个问题。但是,您可能应该增加哈希表的宽度以减少其深度。使用“dmesg”,您将看到当前有多少个条目:
$ dmesg | grep '^IP route'
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)
您可以使用内核启动命令行参数更改此值rhash_entries
。首先手动尝试,然后将其添加到您的lilo.conf
或grub.conf
。
例如:kernel vmlinux rhash_entries=131072
您的哈希表可能非常有限,因为您为 HAProxy VM 分配的内存很少(路由哈希大小根据总 RAM 进行调整)。
关于tcp_mem
,请小心。您的初始设置让我认为您使用的是 1 GB 的 RAM,其中 1/3 可以分配给 TCP 套接字。现在您已将 367872 * 4096 字节 = 1.5 GB 的 RAM 分配给 TCP 套接字。您应该非常小心,不要耗尽内存。经验法则是将 1/3 的内存分配给 HAProxy,将另外 1/3 分配给 TCP 堆栈,将最后 1/3 分配给系统的其余部分。
我怀疑您的“套接字内存不足”消息来自 和 中的默认设置tcp_rmem
。tcp_wmem
默认情况下,您为每个套接字分配 64 kB 的输出空间和 87 kB 的输入空间。这意味着代理连接总共有 300 kB,仅用于套接字缓冲区。再加上 HAProxy 的 16 或 32 kB,您会发现,使用 1 GB 的 RAM 您只能支持 3000 个连接。
tcp_rmem
通过更改和(中间参数)的默认设置tcp_wmem
,您可以大大降低内存占用。我使用写入缓冲区的低至 4096 的值以及 7300 或 16060 tcp_rmem
(5 或 11 个 TCP 段)的值获得了良好的结果。您可以更改这些设置而无需重新启动,但它们仅适用于新连接。
如果你不想触摸你的系统控制寄存器太多了,最新的 HAProxy,1.4-dev8,允许您从全局配置和每一端(客户端或服务器)调整这些参数。
我希望这会有帮助!
答案2
通常Out of socket memory error
会产生误导。大多数情况下,在面向互联网的服务器上,不是指示与内存不足相关的任何问题。正如我在一篇博客文章,最常见的原因是孤立套接字的数量。孤立套接字是未与文件描述符关联的套接字。在某些情况下,Out of socket memory error
即使您距离限制还有 2 倍或 4 倍,内核也会发出/proc/sys/net/ipv4/tcp_max_orphans
。这种情况在面向 Internet 的服务中经常发生,并且完全正常。在这种情况下,正确的做法是将tcp_max_orphans
孤立套接字的数量调整为高峰流量中通常看到的至少 4 倍。
不要听取任何建议调整tcp_mem
或tcp_rmem
除非tcp_wmem
你真的知道你在做什么。那些给出这些建议的人通常不知道。他们的巫术往往是错误的或不适合你的环境,不会解决你的问题。它甚至可能使情况变得更糟。
答案3
我们会定期调整其中一些参数。我们对高吞吐量、低延迟交易平台的标准是:
net.ipv4.tcp_rmem = 4096 16777216 33554432 net.ipv4.tcp_wmem = 4096 16777216 33554432 net.ipv4.tcp_mem = 4096 16777216 33554432 net.core.rmem_default = 16777216 net.core.wmem_default = 16777216 net.core.rmem_max=16777216 净.核心.wmem_max=16777216 net.core.netdev_max_backlog = 30000 net.core.netdev_max_backlog = 30000