Erlang多进程共用监听套接字的两种实现差异及端口复用问题咨询
两种实现方案的核心差异
二者完全不等效,核心区别如下:
- 第一种方案为20个子进程共享同一个监听套接字:
Erlang的gen_tcp:listen调用成功后,端口就已经进入LISTEN状态接收入站连接,不需要等待gen_tcp:accept执行才启动监听。创建的监听套接字可以在进程间安全传递、共享使用,所有子进程都可以对同一个Listen套接字调用gen_tcp:accept,内核会自动将完成三次握手的连接调度给空闲的accept进程,不需要额外做负载均衡。
该方案是Erlang生态中TCP服务的标准实现方式,不存在端口冲突问题,子进程崩溃重启也不会影响监听套接字本身(监听套接字归属监督者进程,只要监督者正常运行就不会被释放)。 - 第二种方案默认无法正常运行:
在未开启端口重用的前提下,同一个IP+端口只能被一个监听套接字绑定,20个子进程先后调用gen_tcp:listen绑定相同端口时,除了第一个进程之外剩下的19个都会直接抛出端口占用错误,启动失败。就算开启了端口重用以成功创建20个监听套接字,逻辑也和第一种共享单套接字的实现完全不同,不属于等效方案。
单端口多监听套接字的实现方案
Erlang并非不支持reuseport:
- 从OTP 21版本开始,
gen_tcp:listen已经原生支持{reuseport, true}选项,底层会自动设置操作系统的SO_REUSEPORT参数,只要你的操作系统版本符合要求(Linux 3.9及以上、FreeBSD、macOS均原生支持),直接在listen参数中添加该选项即可实现多个套接字绑定同一个IP+端口。 - 如果使用OTP 21以下的老版本,更推荐直接使用第一种共享单个监听套接字的方案,该方案是生产环境验证过的成熟实现,性能足以支撑万级甚至十万级的并发连接需求。如果确实需要多个独立监听套接字,可以通过底层raw选项手动设置SO_REUSEPORT:先获取对应操作系统的SO_REUSEPORT常量值(Linux为15,macOS为512),再调用
inet:setopts(ListenSocket, [{raw, 1, SO_REUSEPORT_VAL, <<1:32/native>>}])手动开启端口重用。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

