SO_REUSEPORT 是什么
SO_REUSEPORT 允许组内多个进程或线程各自绑定同一个地址端口,内核按连接的四元组哈希把新连接分给其中一个监听者。这样就不需要所有工作进程抢同一个监听套接字,accept 阶段的锁竞争与惊群问题随之消失,多核利用率提升。关键约束是组内每个套接字在 bind 之前都要设置该选项,否则后绑定的会直接失败。
基本信息
| 选项名 | SO_REUSEPORT,必须在 bind 之前设置 |
|---|---|
| 分流依据 | 连接四元组哈希,同一条流始终落到同一个监听者 |
| 对比 SO_REUSEADDR | 后者解决地址重用与 TIME_WAIT 占位问题,不负责分流 |
| 配套参数 | net.ipv4.tcp_migrate_req 可在队列将满时迁移新请求 |
| 验证方式 | ss -lntp 查看同一端口上的多个监听进程 |
典型使用场景
- 多进程 HTTP 服务:每个工作进程独立监听同一端口,避免集中 accept
- UDP 服务扩容:多个进程分担同一端口的收包处理
- 零停机重启:新旧进程短暂共存于同一端口,交接流量
- 多核压榨:让监听与处理都随 CPU 核数扩展
- 与容器配合:同一宿主上多实例竞争同一端口的场景需要谨慎设计
C 用例与验证
C 用例与验证
int one = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); // 必须在 bind 之前设置
bind(fd, addr, addrlen);
listen(fd, backlog);
/* 验证:ss -lntp 应看到同一端口上出现多个监听进程 */与相邻选项的区别
| 选项 | 解决的问题 | 是否负责分流 |
|---|---|---|
| SO_REUSEPORT | 多个套接字绑定同一端口 | 是,按四元组哈希分流 |
| SO_REUSEADDR | 地址重用与 TIME_WAIT 占位 | 否 |
| tcp_migrate_req | 监听队列将满时迁移新请求 | 间接影响,仅在 REUSEPORT 组内有效 |
使用注意
- 组内成员必须全部设置该选项,漏一个就会绑定失败
- 进程退出需优雅处理:先停止接受新连接再关闭套接字
- UDP 场景要评估哈希在负载变化后是否失衡
- 与 CPU 亲和、负载均衡策略一并规划,避免流量集中
进程重启窗口期是这类架构最容易出问题的地方:内核哈希会继续把新连接分配给已退出进程的队列,必须设计优雅退出,先摘除监听再关闭进程。
UDP 场景下哈希按四元组分流,客户端数量少或端口固定的业务可能出现严重失衡,需要实测后再决定是否使用该机制。