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

标签 sockets node.js networking concurrency

我正在阅读 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/

相关文章:

c# - 来自 Xamarin 应用程序的第二次 api 调用失败(第一次调用总是返回正常)

c - 当ACK丢失时,发送方和接收方都停止?

sockets - 到本地代理的 TCP 套接字连接

node.js - 不同文件中定义的对象的 JSdoc

java - 如何在 Kryonet 中注册 Enum 类?

c - 在 Unix 上使用 C 从文件描述符读取/写入 N 个字节

javascript - node.js module.exports 返回未定义

node.js - Node 类型脚本应用docker命令错误

ubuntu - 带有 LXD 的 Ubuntu 16.04 中的自定义桥接器

linux - 使用 Linux 查找所有本地网络中端口是否打开的快速方法