一个解决了惊群效应的高并发主动式服务模型

       网络框架,服务端必不可少的listen监听socket描述符,监听是否有新连接请求,讨论一个问题,多进程或者多线程模型中,listen到底该如何放置?以多线程为例,一般情况下分为mainThread(主线程)和workThread(工作线程),mainThread负责进程启动结束等一系列其他的主要控制流程任务,workThread负责具体业务逻辑任务。

      场景1:listen放置在mainThread中,说明此模型的基础框架为mainThread负责新连接的accept操作,建立新的连接,随后以一定的策略分配给某一个workThread,策略可以依据workThread连接数及负载程度作为依据(一种简单的策略),workThread中可独立维护一个epoll句柄,充分利用多核cpu优势,加快连接通信【高并发】,此时便明显有一种生产者消费者模型,下游workThread暂时没有太多的问题,当然这个没有问题是建立在你有一定的优化策略(比如抽离ioThread,此文重点不在此,就不赘述了),那么回过头来,可以看到,此模型中mainThread明显成为整个系统的瓶颈,它的处理速度成为了整个设计的天花板,如何优化,引入场景2。

      场景2:listen放置在workThread中,此时把建立新连接的任务下放置给workThread,mainThread得以抽身,天花板就此打破,但是,看似完美,却引来新的问题,在之前的内核中,多个线程同时accept,会引来惊群效应,即一个连接到来,内核会通知到所有监听线程,但事实是只有一个线程accept成功,其余线程失败,继续监听,造成极大的系统资源浪费,这是设计高性能服务所不愿意看到的,虽然在后来的linux版本中,已修复此问题,内核在同一时间只通知到单一线程完成accept,看似问题得以解决,但是一个workthread阻塞到监听事件中无法抽身是毫无意义的,更何况所有的workThread都做同样的事,于是乎listen理所当然的进入epoll句柄中,但是,epoll同样拥有【惊群效应】光环,而且并没有有效的内核处理方式,此问题注定需要设计人员自己解决。借鉴nginx的思想,可以设置一个监听事件锁,当系统开始工作的时候,所有的workThread(并非所有,高负载的workThread不参与,nginx为负载阀值7/8便不参与)去争抢此锁,抢到锁的workThreadA便把listen放置到自己的eopll句柄中,此时若是有新的连接到来,便优先处理新建连接,后续处理数据收发,没有抢到锁的workThreadB若果此前拥有listen描述符,便释放listen描述符,并修改缩短自身epoll_wait超时时间,以便下一次更快的去争抢监听锁。有此可以看到,此模型以epoll为轮询基础造循环。这样子就能使同一时间仅仅有一个workThread的eopll处理新连接事件,完美解决惊群效应,而且此时的workThread依据自身负载【主动】拿取新连接,主动式颠覆此前的被动式新建连接,系统也因此会更加均衡平稳细致。

      结语:网络模型千千万,优化之路无穷尽,愿你我在高并发高吞吐量高稳定性的路上愈行愈远。

      

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值