Nginx 惊群的原因和解决方案

Nginx 惊群的原因和解决方案

这是我的公众号原文链接,如果对你有帮助,欢迎前往关注,更加方便快捷的接收最新优质文章

Nginx 惊群的原因

所谓惊群现象,简单的来说就是当多个进程或线程在同时阻塞等待同一个事件时,如果该事件发生,会唤醒在等待的所有的进程/线程,但最终只可能有一个进程/线程对该事件进行处理,其他进程/线程会在失败后重新休眠,唤醒多个进程/线程这种不必要的行为会造成系统资源的浪费(涉及到进程的上下文切换)。而常见的惊群问题有accept惊群、epoll惊群。

accept 导致的惊群问题

当多个进程/线程调用accept监听同一个socket上时,一个新连接的到来就会导致所有阻塞在该socket上的进程/线程都被唤醒,但是最后只有一个进程/线程可以accept成功,其余的又会重新休眠,这样就产生了惊群现象。

这个问题其实在linux2.6内核版本就已经解决了,它维护了一个等待队列(队列的元素为进程),并且使用了WQ_FLAG_EXCLUSIVE标志位(互斥标志位),非exclusive元素会加在等待队列的前面,而exclusive元素会加在等待队列的末尾,当有新连接到来时,会遍历等待队列,并且只唤醒第一个exclusive进程(非互斥的进程由于排在队列前面也会被唤醒)就退出遍历。

阻塞在accept上的进程都是互斥的(也就是WQ_FLAG_EXCLUSIVE标志位会被置位),因此现在的linux内核调用accept时,多个进程/线程只有一个会被唤醒并建立新连接。

而nginx中处理的主要是另外一种,epoll导致的惊群问题(确切的来说,是解决多个epfd(epfd是指调用epoll_create获取的描述符)共同监听同一个socket造成的惊群问题)。

epoll 导致的惊群问题

虽然accept上已经不存在惊群问题了,但是以目前的服务器架构,都不会简单的使用accept阻塞等待新的连接了,而是使用epoll等I/O多路复用机制。早期的linux,调用epoll_wait后,当有读/写事件发生时,会唤醒阻塞在epoll_wait上的所有进程/线程,造成惊群现象。不过这个问题已经被修复了,使用类似于处理accpet导致的惊群问题的方法,当有事件发生时,只会唤醒等待队列中的第一个exclusive进程来处理。不过随后就可以看到,这种方法并不能完全解决惊群问题。

这里需要区分一下两种不同的情况(这两种情况,目前linux内核都有处理的办法)。

  1. 多个进程/线程使用同一个epfd然后调用epoll_wait
  2. 多个进程/线程有自己的epfd,然后监听同一个socket

其实也就是epoll_create和fork这两个函数调用的先后顺序问题(下面都以进程为例)。第一种情况,先调用epoll_create获取epfd,再使用fork,各进程共用同一个epfd;第二种情况,先fork,再调用epoll_create,各进程独享自己的epfd。

而nginx面对的是第二种情况,这点需要分清楚(网上有很多用第一种情况来引入nginx处理惊群问题的方法,不要被混淆了)。因为nginx的每个worker进程相互独立,拥有自己的epfd,不过根据配置文件中的listen指令都监听了同一个端口,调用epoll_wait时,若共同监听的套接字有事件发生,就会造成每个worker进程都被唤醒。

Nginx 惊群问题的解决方法

Nginx 目前有几种方法解决惊群问题:

  • accept_mutex

    • 如果开启了accept_mutex 锁,每个 worker 都会先去抢自旋锁,只有抢占成功了,才把 socket 加入到 epoll 中,accept 请求,然后释放锁。accept_mutex 锁也有负载均衡的作用。
  • EPOLLEXCLUSIVE

    • EPOLLEXCLUSIVE 是 Linux 4.5+ 内核新添加的一个 epoll 的标识,Nginx 在 1.11.3 之后添加了 NGX_EXCLUSIVE_EVENT。EPOLLEXCLUSIVE 标识会保证一个事件发生时候只有一个线程会被唤醒,以避免多个进程监听下的“惊群”问题。不过任一时候只能有一个工作线程调用 accept,限制了真正并行的吞吐量。
  • SO_REUSEPORT

    • SO_REUSEPORT 是惊群最好的解决方法,Nginx 在 1.9.1 中加入了这个选项,每个 worker 进程都有自己的 socket,这些 socket 都 bind 同一个端口。当新请求到来时,内核根据四元组信息进行负载均衡,非常高效。

最后

这是我的公众号原文链接,如果对你有帮助,欢迎前往关注,更加方便快捷的接收最新优质文章

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值