epoll 的惊群效应

一、epoll 惊群效应产生的原因

很多朋友都在 Linux 下使用 epoll 编写过 socket 的服务端程序,在多线程环境下可能会遇到 epoll 的惊群效应。

那什么是惊群效应呢?其产生的原因是什么呢?

在多线程或者多进程环境下,有些人为了提高程序的稳定性,往往会让多个线程或者多个进程同时在 epoll_wait 监听的 socket 描述符。当一个新的链接请求进来时,操作系统不知道选派那个线程或者进程处理此事件,则干脆将其中几个线程或者进程给唤醒,而实际上只有其中一个进程或者线程能够成功处理 accept 事件,其他线程都将失败,且 errno 错误码为 EAGAIN。这种现象称为惊群效应,结果是肯定的,惊群效应肯定会带来资源的消耗和性能的影响。


二、惊群问题的解决方法

1、多线程环境下解决惊群解决方法

这种情况,不建议让多个线程同时在 epoll_wait 监听的 socket,而是让其中一个线程 epoll_wait 监听的 socket,当有新的链接请求进来之后,由 epoll_wait 的线程调用 accept,建立新的连接,然后交给其他工作线程处理后续的数据读写请求,这样就可以避免了由于多线程环境下的 epoll_wait 惊群效应问题。


2、多进程下的解决方法

目前很多开源软件,如 lighttpd,nginx 等都采用 master/workers 的模式提高软件的吞吐能力及并发能力,在 nginx 中甚至还采用了负载均衡的技术,在某个子进程的处理能力达到一定负载之后,由其他负载较轻的子进程负责 epoll_wait 的调用,那么 nginx 和 Lighttpd 是如何避免 epoll_wait 的惊群效用的。

lighttpd 的解决思路是无视惊群效应,仍然采用 master/workers 模式,每个子进程仍然管自己在监听的 socket 上调用 epoll_wait,当有新的链接请求发生时,操作系统仍然只是唤醒其中部分的子进程来处理该事件,仍然只有一个子进程能够成功处理此事件,那么其他被惊醒的子进程捕获EAGAIN 错误,并无视。

nginx 的解决思路:在同一时刻,永远都只有一个子进程在监听的 socket上epoll_wait,其做法是,创建一个全局的 pthread_mutex_t,在子进程进行 epoll_wait 前,则先获取锁。代码如下:

ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
{
    if (ngx_shmtx_trylock(&ngx_accept_mutex))
    {
        if (ngx_enable_accept_events(cycle) == NGX_ERROR)
        {
            ngx_shmtx_unlock(&ngx_accept_mutex);
            return NGX_ERROR;
        }

        ngx_accept_mutex_held = 1;
        return NGX_OK;
    }

    if (ngx_accept_mutex_held)
    {
        if (ngx_disable_accept_events(cycle) == NGX_ERROR)
        {
            return NGX_ERROR;
        }

        ngx_accept_mutex_held = 0;
    }
    return NGX_OK;
}

且只有在 ngx_accept_disabled < 0 时,才会去获取全局锁,及只有在子进程的负载能力在一定的范围下才会尝试去获取锁,并进入 epoll_wait 监听的 socket。

void  ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
    if (ngx_accept_disabled > 0)
    {
        ngx_accept_disabled--;
    }

    else
    {
        if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR)
        {
            return;
        }
    }
}
ngx_accept_disabled = ngx_cycle->connection_n / 8  - ngx_cycle->free_connection_n;

表示当子进程的连接数达到连接总数的 7/8 时,是不会尝试去获取全局锁,只会专注于自己的连接事件请求。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值