我正在阅读 Node.js 中集群模块的文档:
http://nodejs.org/api/cluster.html
它声明如下:
When multiple processes are all
accept()
ing on the same underlying resource, the operating system load-balances across them very efficiently.
这听起来很合理,但即使经过几个小时的谷歌搜索,我也没有找到任何文章或任何东西来证实它,或者解释这种负载平衡逻辑在操作系统中是如何工作的。
另外,哪些操作系统正在执行这种有效的负载平衡?
最佳答案
“负载平衡”这个词的选择可能有点糟糕,本质上它只是操作系统如何选择唤醒和/或接下来运行哪个进程的问题。通常,进程调度程序会尝试根据以下标准选择要运行的进程,例如为具有相同优先级的进程提供相等的 cpu 时间份额、cpu/内存位置(不要在 cpu 周围反弹进程)等。无论如何,通过谷歌搜索您会发现很多关于进程调度算法和实现的资料。
现在,对于 accept() 的特殊情况,这还取决于操作系统如何实现唤醒等待 accept() 的进程。
一个简单的实现是唤醒阻塞在 accept() 调用上的每个进程,然后让调度程序选择它们运行的顺序。
上面很简单,但会导致“雷群”问题,因为只有第一个进程成功接受连接,其他进程又回到阻塞状态。一种更复杂的方法是操作系统只唤醒一个进程;这里可以通过询问调度程序来选择唤醒哪个进程,或者例如只需选择 blocked-on-accept()-for-this-socket 列表中的第一个进程。后者是 Linux 十年或更长时间以来所做的,基于 link。其他人已发布。
请注意,这仅适用于阻止 accept();对于非阻塞 accept()(我确定 node.js 正在做的事情),问题就变成了 select()/poll()/无论将事件传递给哪个进程阻塞。 poll()/select() 的语义实际上要求它们全部被唤醒,所以你又遇到了雷鸣般的群体问题。对于 Linux,并且可能以类似的方式其他具有系统特定的高性能轮询接口(interface)的系统,可以通过使用单个共享的 epoll fd 和边缘触发事件来避免惊群。在这种情况下,事件将仅传递给被 epoll_wait() 阻塞的进程之一。我认为,与阻塞 accept() 类似,选择将事件传递到的进程只是为特定 epoll fd 选择在 epoll_wait() 上阻塞的进程列表中的第一个进程。
<
所以至少对于 Linux,对于阻塞 accept() 和非阻塞 accept() 以及边缘触发的 epoll,在选择唤醒哪个进程时本身没有调度。但是 OTOH,无论如何,进程之间的工作负载可能会相当均衡,因为本质上系统将按照进程完成当前工作的顺序轮询进程,然后返回阻塞 epoll_wait()。
关于sockets - 操作系统如何在接受同一个套接字的多个进程之间进行负载平衡?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12494914/