操作系统如何在接受同一套接字的多个进程之间进行负载平衡?

时间:2012-09-19 12:41:41

标签: sockets node.js networking concurrency

我正在阅读Node.js中集群模块的文档:
http://nodejs.org/api/cluster.html

它声称如下:

  

当多个进程都accept()在同一个底层上时   资源,操作系统非常负载均衡   有效。

这听起来很合理,但即使经过几个小时的谷歌搜索,我也没有找到任何可以确认它的文章或任何内容,或解释这种负载平衡逻辑如何在操作系统中运行。

此外,哪些操作系统正在进行这种有效的负载平衡?

1 个答案:

答案 0 :(得分:9)

“负载均衡”可能是一个不太好的选择,实质上它只是一个问题,即OS如何选择唤醒和/或下一个运行的进程。通常,进程调度程序尝试根据标准选择要运行的进程,例如给予相同优先级的进程cpu / memory位置相等的cpu /内存(不要在cpu周围跳过进程),等等。无论如何,通过谷歌搜索你会发现很多关于流程调度算法和实现的东西。

现在,对于accept()的特殊情况,这也取决于操作系统如何实现唤醒正在等待accept()的进程。

  • 一个简单的实现就是唤醒在accept()调用中阻塞的每个进程,然后让调度程序选择它们运行的​​顺序。

  • 以上很简单,但会导致“雷鸣般的群体”问题,因为只有第一个流程成功接受连接,其他流程才会回到阻塞状态。更复杂的方法是操作系统只唤醒一个进程;这里可以通过询问调度程序来选择唤醒哪个进程,例如只需在blocked-on-accept() - for-socket-list列表中选择第一个进程。后者是Linux自十年或更久以来所做的事情,基于其他人发布的link

  • 请注意,这仅适用于阻止accept();对于非阻塞的accept()(我确定是node.js正在做什么),问题变成了select()/ poll()/将事件传递给哪个进程阻塞。 poll()/ select()的语义实际上要求它们全部被唤醒,所以你再次遇到雷鸣般的群体问题。对于Linux,并且可能以类似的方式使用具有系统特定高性能轮询接口的其他系统,可以通过使用单个共享epoll fd和边缘触发事件来避免雷鸣般的群体。在这种情况下,事件将仅传递给epoll_wait()上阻止的其中一个进程。我认为,类似于阻止accept(),选择将事件传递给的进程,只是选择在epoll_wait()上为该特定epoll fd阻塞的进程列表中的第一个。

所以至少对于Linux来说,阻塞的accept()和带有边缘触发的epoll的非阻塞的accept(),在选择要唤醒的进程时都没有调度本身。但OTOH,无论如何,工作流程之间的工作量可能会非常均衡,因为系统基本上会按照他们完成当前工作的顺序对流程进行循环,然后再回到epoll_wait()上的阻塞。