Linux SO_REUSEPORT与SO_REUSEADDR

SO_REUSEADDR

一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。
SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。
TCP先调用close()的一方会进入TIME_WAIT状态。

SO_REUSEADDR提供如下四个功能:
1) 允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
2) 允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
3) 允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
4) 允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)

SO_REUSEPORT

Linux Kernel 3.9引入了最新的SO_REUSEPORT选项,
此选项允许完全重复捆绑,但仅在想捆绑相同IP地址和端口的套接口都指定了此套接口选项才行,如果被捆绑的IP地址是一个多播地址,则SO_REUSEADDR和SO_REUSEPORT等效。
使得多进程或者多线程创建多个绑定同一个ip:port的监听socket,提高服务器的接收链接的并发能力,程序的扩展性更好,此时需要设置SO_REUSEPORT(注意所有进程都要设置才生效)。

reuseport的原理
在3.9内核以前,为了支持多进程模型像haproxy,nginx等,大家不约而同的采用的fork的做法,即在父进程里,监听一个IP+port。
然后fork出N个子进程,子进程天然继承了父进程的listen socket的句柄,即可以执行accept操作了。

 

但因为是fork出来的,所以在kernel里,仍然是一个句柄,多个进程执行accept还是有竞争关系,所以nginx需要配置accept_mutex这样的开关,当开启reuseport后,每个监听地址将会有多个句柄,具体来说是一个worker一个,这样每个worker关心的listen socket就独立开了,自己搞定自己的事,避免了多进程的竞争。

注意点:如果使用了SO_REUSEPORT创建了多个监听套接字,那么Linux内核会将accept连接以哈希的方法负载均衡(chash算法)给每个监听套接字,无论你是否去监听

 

posted on 2023-03-02 21:48  寒魔影  阅读(349)  评论(0编辑  收藏  举报

导航