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

我们今天的HAProxy虚拟机有一个小小的故障转移问题。 当我们挖掘它时,我们发现这一点:

 Jan 26 07:41:45 haproxy2内核:[226818.070059] __ratelimit:10个callback被抑制
 1月26日07:41:45 haproxy2内核:[226818.070064] Out of socket内存
 1月26日07:41:47 haproxy2内核:[226819.560048] Out of socket内存
 1月26日07:41:49 haproxy2内核:[226822.030044] Out of socket内存

其中,通过这个链接 ,显然与net.ipv4.tcp_mem低默认设置有关。 所以我们将它们的默认值增加了4倍(这是Ubuntu服务器,不确定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,并控制周期性的刷新路由caching

secret_interval指示内核多频繁地吹走所有路由哈希条目,而不pipe它们是多么新/旧。 在我们的环境中这通常是不好的。 每当清除caching时,CPU将忙于重build每秒数千条logging。 然而,我们设置这个每天运行一次,以防止内存泄漏(虽然我们从来没有)。

虽然我们很乐意减less这种情况, 但build议您定期删除整个路由caching ,而不是简单地将旧值从路由caching中移出的速度更快。

经过一番调查,我们发现/proc/sys/net/ipv4/route/gc_elasticity这似乎是保持路由表大小的更好的select:

gc_elasticity可以最好地描述为内核在开始使路由哈希条目过期之前将接受的平均存储桶深度。 这将有助于维持活跃路线的上限。

我们将弹性从8调整到4,希望路由caching修剪更加积极。 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路由变得更糟 ,所以我们有点害怕把这些设置搞乱。

任何人都可以build议哪个路由参数最适合高stream量的HAProxy实例?

    我从未遇到过这个问题。 但是,你可能应该增加你的哈希表的宽度,以减less其深度。 使用“dmesg”,你会看到你有多less条目:

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

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

    例如: kernel vmlinux rhash_entries=131072

    有可能你有一个非常有限的散列表,因为你已经为HAProxy虚拟机分配了很less的内存(路由散列大小根据总RAM来调整)。

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

    我怀疑你的“out of socket memory”消息来自于tcp_rmemtcp_wmem默认设置。 默认情况下,每个套接字的输出分配有64kB,input分配87kB。 这意味着代理连接的总数为300 kB,仅用于套接字缓冲区。 添加到16或32 kB的HAProxy,你看到1 GB的RAM只能支持3000个连接。

    通过改变tcp_rmemtcp_wmem (中间参数)的默认设置,内存可以降低很多。 我得到了很好的结果,写入缓冲区的值低至4096, tcp_rmem (5或11个TCP段)的值为7300或16060。 您可以在不重新启动的情况下更改这些设置,但是这些设置仅适用于新的连接。

    如果您不想过多地使用您的sysctl ,最新的HAProxy 1.4-dev8允许您从全局configuration和每端(客户端或服务器)调整这些参数。

    我希望这有助于!

    Out of socket memory error往往是误导性的。 在大多数情况下,在面向Internet的服务器上,并不表示任何与内存不足有关的问题。 正如我在博客文章中详细解释的 ,最常见的原因是孤儿套接字的数量。 孤儿套接字是一个没有关联到文件描述符的套接字。 在某些情况下,即使距离极限( /proc/sys/net/ipv4/tcp_max_orphans )为2倍或4倍,内核也会发出“ Out of socket memory error 。 这种情况在面向Internet的服务中经常发生,这是非常正常的。 在这种情况下,正确的做法是调整tcp_max_orphans ,使其至less是通常在高峰stream量中看到的孤儿数的4倍。

    不要听任何build议调整tcp_memtcp_rmemtcp_wmem除非你真的知道你在做什么。 那些提供这些build议的人通常不会。 他们的巫术往往是错误的或不适合你的环境,并不能解决你的问题。 它甚至可能使情况变得更糟。

    我们定期调整其中一些参数。 我们的高吞吐量,低延迟交易平台的标准是:

     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
     net.core.wmem_max = 16777216
     net.core.netdev_max_backlog = 30000
     net.core.netdev_max_backlog = 30000