ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

【Linux】一个epoll惊群导致的性能问题

2021-02-27 16:59:20  阅读:261  来源: 互联网

标签:epoll accept 9484480 Linux 惊群 EAGAIN 500 wait


linux服务器开发相关视频解析:

从nginx“惊群”问题来看高并发锁的方案
程序性能优化 — 异步帮你解决80%的问题

c/c++ linux服务器开发免费学习地址:c/c++ linux后台服务器高级架构师

在我们内部的系统中,有一个tcp的代理服务,用户所有的网络相关的请求,比如访问外网,或者访问在内网的某些服务,都需要通过这个服务,一方面是实现对外网访问的计费,另外也通过白名单机制,对应用的内网访问进行相应的限制。
随着业务量的增加,发现提供服务的机器负载逐渐变高,当流量高峰的时候,经常出现客户端无法连接的情况,本来这个服务也是一个无状态的服务,可以很方便的水平扩容,在添加机器的同时,也尝试去分析一下程序本身的瓶颈,看能否提升一下程序本身的处理能力,通过分析和优化,还是在一定程度上提升了处理能力

首先还是在线上使用perf工具生成了一下火焰图:在这里插入图片描述

火焰图

第一次看到这个火焰图感觉很奇怪,主要的问题集中在为什么__accept_nocancel也就是accept的调用会如此频繁,首先想到的就是惊群效应了,但是应该在Linux内核2.6.18的时候,accept的惊群问题在内核中就已经解决了,我们线上用的CentOS 6.5内核版本已经到了2.6.32,理论上不应该会有类似的问题。
于是还是到线上尝试strace看一下程序的系统调用:

epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(7, {{EPOLLIN, {u32=9484480, u64=9484480}}}, 1024, 500) = 1
accept(6, 0x7fff90830890, [128]) = -1 EAGAIN (Resource temporarily unavailable)

绝大部分都是epoll_wait返回,尝试accept,但是accept返回EAGAIN,这应该就是火焰图中那么多accept调用的原因。又查找了一下资料,发现在epoll编程模型中是不会处理惊群的,当一个socket有事件,内核会唤醒所有监听的epoll_wait调用,从而导致这个问题。
我们先分析一下程序,目前程序的工作流程是:

  1. master进程启动,bind并监听一系列fd;
  2. fork n个worker进程;
  3. 在worker进程中,获取master进程监听的fd,调用epoll_create创建epoll instance,并监听listen
    fd的事件;
  4. 如果有新连接,直接accept,然后进入代理流程;
  5. 重复执行第4步。

由于线上机器是24核,所以线上运行的时候,会fork 24个worker进程,其实,当worker进程数比较少的时候,这个现象体现的不是很明显,但是当worker进程比较多的时候,惊群产生的而外的损耗,看起来已经无法忽略了。
对于这个问题,nginx的解决办法是,创建一个全局的锁,只有拿到这个锁的woker进程,才会去监听listen fd的事件进行accept,当某些条件满足,worker会放弃该锁,并停止监听listen fd事件,由其他woker得到锁后继续监听listen fd事件。
在nginx 1.9.1版本中,支持了一个新的特性reuseport,在Linux 3.9或更新内核中,可以开启SO_REUSEPORT选项,通过操作系统实现类似之前accept的隔离,来避免惊群现象,同时,能更好的利用多核,提升系统性能。

由于类似nginx的accpet锁实现比较复杂,刚好在我们线上系统CentOS 6.5中,SO_REUSEPORT这个特性已经被redhat backport回来了,也就说在CentOS 6.5的2.6.32内核中,也能开启SO_REUSEPORT这个选项,因此就修改了一下proxy的代码,尝试开启SO_REUSEPORT:

  1. master进程启动;
  2. fork n个worker进程;
  3. 在worker进程中,bind并监听一系列fd,在bind之前设置SO_REUSEPORT选项,调用epoll_create创建epoll
    instance,并监听listen fd的事件;
  4. 如果有新连接,直接accept,然后进入代理流程;
  5. 重复执行第4步。

修改后,同样进行strace,当有新连接的时候,只会有一个worker进程被唤醒进行accept,大大提升了效率,再看一眼火焰图:在这里插入图片描述

火焰图

可以看到已经看不到accept的调用了,取代的是recv和send以及connect,对于一个tcp代理来说,实现消耗在网络上,是比较正常的,epoll_wait的调用依然偏多,仍然有优化空间。

通过一个简单的测试,500个线程,50000个请求,在相同机器和配置的情况下,总体时间从约14.38秒减少到约10.27秒,性能大约提升了30%。

PS:在Linux 4.5内核中,引入了EPOLLEXCLUSIVE选项,同样可以解决epoll的惊群问题。

标签:epoll,accept,9484480,Linux,惊群,EAGAIN,500,wait
来源: https://blog.csdn.net/qq_40989769/article/details/114179500

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有