调整 Linux IP 路由参数——secret_interval 和 tcp_mem

Jef*_*ood 33 linux tcpip routing

今天,我们的一个 HAProxy 虚拟机出现了一个小故障转移问题。当我们深入研究时,我们发现:

Jan 26 07:41:45 haproxy2 内核:[226818.070059] __ratelimit:10 个回调被抑制
Jan 26 07:41:45 haproxy2 内核:[226818.070064] 内存不足
Jan 26 07:41:47 haproxy2 内核:[226819.560048] 套接字内存不足
Jan 26 07:41:49 haproxy2 内核:[226822.030044] 套接字内存不足

其中,根据此链接,显然与net.ipv4.tcp_mem. 所以我们将它们从默认值增加了 4 倍(这是 Ubuntu Server,不确定 Linux 风格是否重要):

当前值为:45984 61312 91968
新值是:183936 245248 367872

之后,我们开始看到一条奇怪的错误消息:

Jan 26 08:18:49 haproxy1 内核:[2291.579726] 路由哈希链太长!
Jan 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 实例,谁能建议最好调整哪些路由参数?

Wil*_*eau 28

我从来没有遇到过这个问题。但是,您可能应该增加哈希表的宽度以减少其深度。使用“dmesg”,您将看到当前有多少条目:

$ dmesg | grep '^IP route'
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)
Run Code Online (Sandbox Code Playgroud)

您可以使用内核引导命令行参数更改此值rhash_entries。首先手动尝试,然后将其添加到您的lilo.confgrub.conf.

例如: kernel vmlinux rhash_entries=131072

您的哈希表可能非常有限,因为您为 HAProxy VM 分配的内存很少(路由哈希大小根据总 RAM 进行调整)。

关于tcp_mem,要小心。您的初始设置让我认为您运行的是 1 GB 的 RAM,其中 1/3 可以分配给 TCP 套接字。现在您已经为 TCP 套接字分配了 367872 * 4096 字节 = 1.5 GB 的 RAM。您应该非常小心,以免内存不足。经验法则是将 1/3 的内存分配给 HAProxy,另外 1/3 分配给 TCP 堆栈,最后 1/3 分配给系统的其余部分。

我怀疑你的“出槽存储”的消息来自于默认设置tcp_rmemtcp_wmem。默认情况下,每个套接字的输出分配为 64 kB,输入分配为 87 kB。这意味着代理连接总共有 300 kB,仅用于套接字缓冲区。再加上 HAProxy 的 16 或 32 kB,您会看到 1 GB 的 RAM 将仅支持 3000 个连接。

通过更改tcp_rmemtcp_wmem(中间参数)的默认设置,您可以减少很多内存。我得到了很好的结果,写缓冲区的值低至 4096,7300 或 16060 in tcp_rmem(5 或 11 个 TCP 段)。您无需重新启动即可更改这些设置,但它们仅适用于新连接。

如果你不喜欢触摸你的sysctl太多,最新的HAProxy的,1.4 DEV8,允许你从全局配置调整这些参数,每方(客户端或服务器)。

我希望这会有所帮助!


小智 8

Out of socket memory error往往是误导。在大多数情况下,在互联网上面向服务器,它并没有指出涉及到内存中运行的任何问题。正如我在博客文章中更详细地解释的那样,最常见的原因是孤立套接字的数量。孤立套接字是与文件描述符无关的套接字。在某些情况下,Out of socket memory error即使您距离限制 ( /proc/sys/net/ipv4/tcp_max_orphans) 2 倍或 4 倍,内核也会发出。这在面向 Internet 的服务中经常发生,并且是完全正常的。在这种情况下,正确的做法是调整tcp_max_orphans到至少是您通常在高峰流量时看到的孤儿数量的 4 倍。

不要听那个建议调整任何意见tcp_memtcp_rmem或者tcp_wmem,除非你真的知道自己在做什么。那些给出这些建议的人通常不会。他们的巫术通常是错误的或不适合您的环境,并且不会解决您的问题。它甚至可能会使情况变得更糟。