SO_REUSEPORT 使用 epoll 和多进程
SO_REUSEPORT with epoll and multiple process
简而言之,SO_REUSEPORT
套接字选项允许在 ip:port 对上创建多个套接字。例如,program1
和 program2
都可以为相同的端口和 IP 调用函数链 socket()->bind()->listen()->accept()
,内核调度程序将在这两个程序之间平均分配传入连接。
我假设使用此选项,您可以摆脱使用 fork()
来产生额外的工人,并且可以简单地 运行 新程序实例。
我写了一个简单的epoll socket server,基于这个逻辑,用weighttp测试了一下:
weighttp -n 1000000 -c 1000 -t 4 http://127.0.0.1:8080/
对于两个 运行ning 实例,结果是 ~44000 RPS,对于一个 运行ning 实例 - 接近 ~51000 RPS。我对 7000 RPS 的差异感到非常惊讶。
在这个测试之后我在 listen()
和 运行 之前添加了 fork()
一个服务器实例,所以现在它与之前的实现具有相同的逻辑 - 两个带有 epoll 循环监听套接字的进程,但是 socket()->bind()
在 fork()
之前只调用了一次,第二个进程收到它的 FD 副本以供 listen()
调用。
我运行再次测试,结果显示~50000 RPS!
所以,我的问题很简单:在这种情况下 fork()
有什么魔力,为什么它比两个独立的进程有自己的 socket()
更快?内核做同样的调度工作,我看不出有什么重要的区别。
发表此评论以将问题标记为已回答:根据我的研究,内部 OS 调度程序远非最佳并且取决于硬件。更好的是使用用户空间调度程序。
简而言之,SO_REUSEPORT
套接字选项允许在 ip:port 对上创建多个套接字。例如,program1
和 program2
都可以为相同的端口和 IP 调用函数链 socket()->bind()->listen()->accept()
,内核调度程序将在这两个程序之间平均分配传入连接。
我假设使用此选项,您可以摆脱使用 fork()
来产生额外的工人,并且可以简单地 运行 新程序实例。
我写了一个简单的epoll socket server,基于这个逻辑,用weighttp测试了一下:
weighttp -n 1000000 -c 1000 -t 4 http://127.0.0.1:8080/
对于两个 运行ning 实例,结果是 ~44000 RPS,对于一个 运行ning 实例 - 接近 ~51000 RPS。我对 7000 RPS 的差异感到非常惊讶。
在这个测试之后我在 listen()
和 运行 之前添加了 fork()
一个服务器实例,所以现在它与之前的实现具有相同的逻辑 - 两个带有 epoll 循环监听套接字的进程,但是 socket()->bind()
在 fork()
之前只调用了一次,第二个进程收到它的 FD 副本以供 listen()
调用。
我运行再次测试,结果显示~50000 RPS!
所以,我的问题很简单:在这种情况下 fork()
有什么魔力,为什么它比两个独立的进程有自己的 socket()
更快?内核做同样的调度工作,我看不出有什么重要的区别。
发表此评论以将问题标记为已回答:根据我的研究,内部 OS 调度程序远非最佳并且取决于硬件。更好的是使用用户空间调度程序。