Linux 3.2内核与2.6内核接受不良平衡的套接字

Bre*_*ett 26 linux kernel epoll http node.js

我正在运行一个相当大规模的Node.js 0.8.8应用程序,使用带有16个工作进程的Cluster,在具有超线程的16处理器盒子上(所以32个逻辑核心).我们发现自从迁移到Linux 3.2.0内核(从2.6.32开始)以来,工作者子进程之间的传入请求的平衡似乎被大量加权到5个左右的进程,而其他11个进程根本没有做太多工作.这可能对吞吐量更有效,但似乎增加了请求延迟并且对我们来说不是最佳的,因为其中许多是长期的websocket连接,可以同时开始工作.

子进程都在套接字上接受(使用epoll),虽然这个问题在Node 0.9(https://github.com/bnoordhuis/libuv/commit/be2a2176ce25d6a4190b10acd1de9fd53f7a6275)中有一个修复,但该修复似乎没有帮助我们的测试.是否有人知道内核调优参数或构建选项可能有所帮助,或者我们最好使用不同的方法回到2.6内核或跨工作进程进行负载平衡?

我们将其归结为一个简单的HTTP Siege测试,但请注意,这是在带有超线程的12核盒子上进行12次触发(因此有24个逻辑核心),并且有12个工作进程在套接字上接受,而不是我们的16在生产过程中.

在Debian Squeeze上使用Node 0.9.3进行HTTP Siege,在裸机上使用2.6.32内核:

reqs pid
146  2818
139  2820
211  2821
306  2823
129  2825
166  2827
138  2829
134  2831
227  2833
134  2835
129  2837
138  2838
Run Code Online (Sandbox Code Playgroud)

除了3.2.0内核以外的一切:

reqs pid
99   3207
186  3209
42   3210
131  3212
34   3214
53   3216
39   3218
54   3220
33   3222
931  3224
345  3226
312  3228
Run Code Online (Sandbox Code Playgroud)

Bre*_*ett 7

不要依赖OS的套接字多次接受来平衡Web服务器进程的负载.

Linux内核的行为在版本与版本之间有所不同,我们看到3.2内核的行为特别不平衡,在以后的版本中似乎更加平衡.例如3.6.

我们的运作假设应该有一种方法可以让Linux做类似于循环法的事情,但是存在各种各样的问题,包括:

  • Linux内核2.6显示出类似于裸机上的循环行为(不平衡大约为3比1),Linux内核3.2没有(10比1不平衡),内核3.6.10似乎再次正常.我们没有试图将实际变化分成两部分.
  • 无论使用何种内核版本或构建选项,我们在Amazon Web服务上的32位逻辑核心HVM实例上看到的行为都严重地针对单个流程进行了加权; Xen socket接受可能存在问题:https://serverfault.com/questions/272483/why-is-tcp-accept-performance-so-bad-under-xen

您可以在我们用来与优秀的Node.js团队对应的github问题上详细查看我们的测试,从这里开始:https://github.com/joyent/node/issues/3241#issuecomment-11145233

该对话以Node.js团队结束,表明他们正在认真考虑在Cluster中实现显式循环,并为此开始一个问题:https://github.com/joyent/node/issues/4435,以及Trello团队(那是我们)进入我们的后备计划,即使用本地HAProxy进程在每台服务器计算机上的16个端口上进行代理,每个端口上运行一个2工作进程集群实例(用于接受级别的快速故障转移)在进程崩溃或挂起的情况下).该计划运行良好,请求延迟的变化大大减少,平均延迟也较低.

这里有很多内容要说,我没有采取邮寄Linux内核邮件列表的步骤,因为不清楚这是真的是Xen还是Linux内核问题,或者实际上只是对多重接受的错误期望我们的行为.

我很乐意看到一位专家对多重接受的答案,但我们将回到我们可以使用我们更了解的组件构建的内容.如果有人发布更好的答案,我会很高兴接受它而不是我的.