- 惊群效应的概念
- 惊群效应的危害
- 惊群效应的解决方法
- 在accept之前加锁
- SO_REUSEPORT
惊群现象就是多进程(多线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他就会唤醒等待的所有进程(或者线程),但是最终却只可能有一个进程(线程)获得这个时间的“控制权”,对该事件进行处理,而其他进程(线程)获取“控制权”失败,只能重新进入休眠状态,这种现象和性能浪费就叫做惊群。
惊群效应的危害- 系统对用户进程/线程频繁地做无效的调度,上下文切换系统性能大打折扣。
- 为了确保只有一个线程得到资源,用户必须对资源操作进行加锁保护,进一步加大了系统开销。
lock; accept(); unlock;SO_REUSEPORT
在使用SO_REUSEPORT后,多个进程的套接字可以同时监听同一个IP:端口,然后由内核决定将新链接发送给哪个进程,显然会降低每个进程接收新链接时锁竞争:
下面我们就来看看SO_REUSEPORT解决了什么问题:
- 允许多个套接字bind()/listen()同一个tcp/udp端口。每一个线程拥有自己的服务器套接字,在服务器套接字上没有锁的竞争。
- 内核层面实现负载均衡。
- 安全层面,监听同一个端口的套接字只能位于同一个用户下面。
- 处理新建连接时,查找listener的时候,能够支持在监听相同IP和端口的多个sock之间均衡选择。
当一个连接到来的时候,系统到底是怎么决定那个套接字来处理它?对于不同内核,存在两种模式,这两种模式并不共存,一种叫做热备份模式,另一种叫做负载均衡模式。
- 热备份模式:一般而言,会将所有的reuseport同一个IP地址/端口的套接字挂在一个链表上,取第一个即可,工作的只有一个,其他的作为备份存在,如果该套接字挂了,它会被从链表删除,然后第二个便会成为第一个。
- 负载均衡模式:和热备份模式一样,所有reuseport同一个IP地址/端口的套接字会挂在一个链表上,你也可以认为是一个数组,这样会更加方便,当有连接到来时,用数据包的源IP/源端口作为一个HASH函数的输入,将结果对reuseport套接字数量取模,得到一个索引,该索引指示的数组位置对应的套接字便是工作套接字。这样就可以达到负载均衡的目的,从而降低某个服务的压力。



