Linux 的 socket 选项SO_REUSEPORT

均衡转发

  多线程服务端编程中经常遇到的一个问题就是,如何将客户端的连接请求均衡地分发给每个线程。一种常见的做法是让多个线程同时调用accept(),在同一个socket描述符上等待连接请求,当请求到达时,内核会随机唤醒一个线程去处理这个请求。(注:Linux 2.6之后,accept()不会导致惊群。) 然而,正如这篇文章所说的,当连接请求到达时,若系统负载过高,内核就可能会以一种很不均衡地方式去唤醒线程。这就导致了有的线程处理太多请求而忙不过来,而有的线程则很空闲。
  Linux 3.9提供了SO_REUSEPORT选项,对于TCP来说,它允许多个listening socket绑定到同一个端口,也就是说,所有线程都可以创建一个listening socket绑定到同一个端口,并且可以调用accept()在这个socket上等待连接请求。使用SO_REUSEPORT的好处就是,由于内核会将客户端的连接请求均衡地分发给每个listening socket,在多线程环境中,这有利于充分利用好每个 CPU 核心。
  SO_REUSEPORT的用法很简单,只要每个listening socket在调用bind()之前设置好这个选项就可以了:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

int optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));

bind(sockfd, ...);

参考资料