多个进程的一个侦听套接字

One listen socket for many processes

我有一个非常简单的问题,我想创建 20 个 children 进程,每个进程都有相同的侦听套接字,有 2 种方法,我只想知道两者之间有什么区别:

module(sup). 
.....
start() ->
supervisor:start_link({local,?MODULE},?MODULE,[]).
%%%%%%%%%%%%%%%%%%

--------第一种方法--------

init([]) ->
Listen=gen_tcp:listen(....),
spawn(fun() ->start_children(20) end), 
{ok,{{simple_one_for_one,5,1},[{child,{ChildModule,start,[Listen]},....}]}}.
%%%%%%%%%%%%%%%%%
start_children(N) ->
[supervisor:start_child(?MODULE, [])||_ <-lists:seq[1,N]], 
ok. 

这是一棵 simple_one_for_one 树,我只是创建了一个监听套接字并将其设置为每个启动进程的参数,稍后将处理它,我生成了一个新进程 运行 start_children/1 因为这个函数调用主管,稍后在它的 init/1 函数中它不能在它自己启动之前启动 children 所以进程将等待 sup 的启动来调用它,让我们看看第二种方法: --------第二种方法--------

init([]) ->
ChildSpecs=[{Id,{ChildModule,start,[fun createListenSocket/0]},....}||Id <-lists:seq[1,20]] 
{ok,{{one_for_one,5,1},ChildSpecs}}.
%%%%%%%%%%%%%%%%%%%%
createListenSocket() ->
gen_tcp:listen(....).

这是一棵 one_for_one 树,sup 在开始时为每个 child 创建了 20 children 和 20 sockets:one 套接字,所以问题是:这两个方法相同还是不同?如果我们认为它们是相同的,那意味着监听套接字只是一个变量,套接字中的特殊事物(监听传入连接)从我们 运行 gen_tcp:accept/1 开始。 因为如果不是,我们会遇到第一种方法中 20 个进程共享同一个监听套接字的情况。

编辑:

好的,我认为 José 已经回答了我的问题,但他的回答给我带来了另一个问题:如何在 Erlang 中创建多个具有相同端口和 IP 地址的套接字?因为如果我希望每个节点有 运行 20 个套接字,则 ip 是本地 ip 地址并且所有套接字都相同,并且在我只需要一个指定端口用于应用程序的情况下,端口也相同?有一个选项 {reuseaddr, true} 作为 gen_tcp:listen 的参数,但是当我们对不同的 ip 地址使用相同的端口并且在 Erlang 中没有 reuseport 时它可以被使用所以要做什么那?

免责声明:此答案是关于 Linux。

不,这两种方法不一样,监听套接字是OS结构。一个创建一个侦听套接字,另一个创建 20 个侦听套接字(或至少尝试这样做,因为最后 19 个将失败,除非您启用端口重用。您在 this question 中对此选项有很好的解释)。

您可以使用 sudo ss -punta | grep LISTEN

检查监听套接字

在具有多个侦听套接字的 OS 级别,连接的负载平衡由内核执行,忽略兄弟套接字是否有任何 OS 线程等待 accept。因此,当您拥有一个监听套接字时,您可能会在接受队列中遇到争用,而拥有多个监听套接字时,您可能会看到延迟差异,因为一个 OS-thread 有更多负载。 (在this cloudflare blog entry中有详细解释)

编辑:

reuseport 仅适用于 newish low-level socket interface,如果您使用 gen_tcp,则仅 reuseaddr 可用。

话虽这么说,请记住,当你在 erlang 中时,你是在上面的一层:阻塞 gen_tcp:accept 不需要(而且很可能不是 *)一个 OS-level blocking accept。同样,我之前提到的 OS-thread 不是 erlang 线程,而是 BEAM 调度程序。在大多数情况下,只有一个监听套接字就可以了。

*由于调度器数量有限(OS-线程)和依赖于 erlang 代码的任意数量的套接字,使用 blocking accept 将是一场噩梦epoll.