Linux 3.2内核与2.6内核相比,套接字接受不平衡的问题

26

我正在运行一个相当大规模的Node.js 0.8.8应用,使用 Cluster 在一台有超线程(32个逻辑核心)的16核处理器上运行着16个工作进程。我们发现自从升级到 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 测试,但需要注意的是,这是在一个有超线程(24个逻辑核心)的12核处理器上以 12 个工作进程接受套接字,与我们生产环境的 16 核不同。

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

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

除了内核版本是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

2
你尝试过创建16个服务器(作为单独的进程),并在前面放置(例如)haproxy吗?这是一个很好的代理软件。此外,您将需要代理以进行进一步扩展。 - freakish
1
没错!本地HAProxy在进程之间进行完美的轮询,如果我们无法解决这个问题,那么它可能是我们将要使用的。然而,避免添加额外的服务(更不用说如果进程崩溃或变得无响应时需要来回传递的额外负担)似乎更可取,因此我们正在探索这条路。 - Brett
2
这个看起来值得在Linux内核邮件列表上发布。网络/负载均衡算法经常会发生变化,因此最好找到最初“搞砸”这个的原始人... - s-m-e
我同意;我们使用构建的3.7内核看到了类似于2.6内核的结果,因此当我们对导致问题的内核版本和/或构建配置有更清晰的了解时,我们可能会向内核邮件列表提出问题。 - Brett
3.6.10内核在裸机上的表现还可以,但在亚马逊网络服务上的HVM AMI上,情况仍然非常不平衡,因此我们认为目前3.2内核存在一些问题,并且Xen也存在另一个问题,可能是导致这里出现问题的原因:http://serverfault.com/questions/272483/why-is-tcp-accept-performance-so-bad-under-xen - Brett
只是出于好奇,新内核在这方面的表现如何?有任何改进吗? - Venemo
1个回答

7
不要依赖操作系统的套接字多路复用来平衡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套接字接受方面的问题:https://serverfault.com/questions/272483/why-is-tcp-accept-performance-so-bad-under-xen。您可以在我们在github上与优秀的Node.js团队对应使用的问题上详细查看我们的测试,从这里开始:https://github.com/joyent/node/issues/3241#issuecomment-11145233。该对话结束时,Node.js团队表示他们正在严肃考虑在Cluster中实现显式轮询,并开始了一个相应的问题:https://github.com/joyent/node/issues/4435,而Trello团队(也就是我们)则采用了备选方案,即在每台服务器上使用本地的HAProxy进程代理16个端口,并在每个端口上运行2个工作进程的Cluster实例(以便在进程崩溃或挂起时快速故障转移)。这个计划运行得非常好,请求延迟的变化大大降低,平均延迟也降低了。这里还有很多要说的,但我并没有向Linux内核邮件列表发送电子邮件,因为不清楚这是否真的是Xen或Linux内核问题,或者只是我们对多接受行为的错误期望。我希望能从多路复用专家那里得到答案,但我们回到了我们更好地理解的组件构建的方式。如果有人发布了更好的答案,我将很高兴接受它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接