26

我正在运行一个相当大规模的 Node.js 0.8.8 应用程序,它使用具有 16 个工作进程的集群,在具有超线程的 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 测试,但请注意,这是在具有超线程(即 24 个逻辑内核)的 12 核机器上运行 12 个 proc,并且在套接字上接受 12 个工作进程,而不是我们的 16 个生产中的过程。

HTTP Siege 在 Debian Squeeze 上使用 Node 0.9.3,在裸机上使用 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

除了 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
4

1 回答 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

您可以在我们用来与优秀的 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-worker-process 集群实例(用于在接受级别进行快速故障转移在进程崩溃或挂起的情况下)。该计划运行良好,请求延迟的变化大大减少,平均延迟也更低。

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

我很想看到关于多重接受的专家的回答,但我们将回到使用我们更好理解的组件可以构建的内容。如果有人发布更好的答案,我会很高兴接受它而不是我的。

于 2012-12-19T14:40:55.097 回答