一个nginx 回源限速的bug处理过程记录

一个生产环境,nginx占用cpu很高。

top - 15:04:19 up 1 day, 14:16,  5 users,  load average: 13.26, 13.20, 13.20
Tasks: 881 total,  14 running, 865 sleeping,   0 stopped,   2 zombie
Cpu(s): 21.3%us, 18.0%sy,  0.0%ni, 57.4%id,  0.0%wa,  0.0%hi,  3.3%si,  0.0%st
Mem:    257556M total,   254371M used,     3184M free,      400M buffers
Swap:        0M total,        0M used,        0M free,   200639M cached

  PID USER      PR  NI  VIRT  RES  SHR S   %CPU %MEM    TIME+  COMMAND
32512 root      20   0 11.9g 3.3g 3.2g R    130  1.3 174:16.31 nginx
  393 root      20   0 11.9g 3.5g 3.4g R     87  1.4 285:16.87 nginx
  394 root      20   0 11.9g 3.5g 3.4g R     87  1.4 271:35.20 nginx
  395 root      20   0 11.9g 3.6g 3.5g R     87  1.4 301:12.50 nginx
  400 root      20   0 11.9g 3.5g 3.4g R     87  1.4 257:04.89 nginx
32502 root      20   0 11.9g 3.7g 3.6g R     87  1.5 396:46.03 nginx
32506 root      20   0 11.9g 3.6g 3.5g R     87  1.4 298:45.09 nginx
32642 root      20   0 11.9g 3.7g 3.6g R     87  1.5 355:42.75 nginx

top跟进去单个线程,发现是主线程很高:

top - 14:48:47 up 1 day, 14:00,  4 users,  load average: 12.79, 12.84, 13.04
Tasks:  68 total,   0 running,  68 sleeping,   0 stopped,   0 zombie
Cpu(s): 18.0%us, 21.5%sy,  0.1%ni, 54.6%id,  1.7%wa,  0.0%hi,  4.1%si,  0.0%st
Mem:    257556M total,   253504M used,     4052M free,      400M buffers
Swap:        0M total,        0M used,        0M free,   199627M cached

  PID USER      PR  NI  VIRT  RES  SHR S   %CPU %MEM    TIME+  COMMAND
32582 root      20   0 11.9g 3.4g 3.3g S      0  1.3 178:24.72 nginx
 2999 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:07.05 nginx
 3001 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:06.36 nginx
 3004 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:07.07 nginx
 3006 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:06.18 nginx
 3009 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:06.70 nginx
 3011 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:03.87 nginx
 3013 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:06.16 nginx
 3016 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:06.51 nginx
 3018 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:07.03 nginx
 3020 root      20   0 11.9g 3.4g 3.3g S      0  1.3   0:07.10 nginx

gdb跟踪一下,发现大量的epoll_wait返回,中间没有任何系统调用:

epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1
epoll_wait(283, {{EPOLLOUT, {u32=3409011729, u64=140156781814801}}}, 512, 1) = 1

查看堆栈,

epoll_wait在返回有active的fd的时候,我们并没有去调用recv或者recvfrom,走查代码:

        if ((revents & EPOLLOUT) && wev->active) {

            if (c->fd == -1 || wev->instance != instance) {

                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "epoll: stale event %p", c);
                continue;
            }

            wev->ready = 1;

            if (flags & NGX_POST_EVENTS) {
                ngx_post_event(wev, &ngx_posted_events);

            } else {
                wev->handler(wev);
            }
        }

发现 wev->active 有时候不为1,但是在epoll_wait返回的时候,大多数情况是1,为什么没有recv呢?

查看 wev->handler,在 ngx_http_upstream_process_non_buffered_request 中,有这么一个分支判断:

            if(downstream->write->delayed)
            {
                ngx_log_error(NGX_LOG_DEBUG, upstream->log, 0,
                    "[no_buffering_limite_rate] downstream->write->delayed return here. remove upstream read event");

                ngx_del_event(upstream->read, NGX_READ_EVENT, 0);
                return;
            }

在做了限速的情况下,只删除了 upstream->read 事件,没有删除 upstream->write 事件。

而我们epoll_wait返回的是 EPOLLOUT 事件。

在这种情况下,wev->handler(wev); 由于处理非常快,

ngx_process_events_and_timers(ngx_cycle_t *cycle)函数在下面这个逻辑:

    delta = ngx_current_msec;

    (void) ngx_process_events(cycle, timer, flags);

    delta = ngx_current_msec - delta;

这样delta几乎为0,使得下次循环的时候扫描的timer为红黑树的最小值,且这个值都没有超时。

 timer = ngx_event_find_timer();

所以我们也看到epoll_wai的超时值大多数时间非常小。

最后,这个问题在满足限速情况下,将NGX_WRITE_EVENT 从epoll中删除,等到了限速不满足的时候,再加入这个event。

原文地址:https://www.cnblogs.com/10087622blog/p/10256121.html

时间: 2024-11-06 03:30:37

一个nginx 回源限速的bug处理过程记录的相关文章

Red Hat5下源码安装mysql5.6过程记录

1.安装cmake包 [[email protected] soft]# tar -xzf cmake-3.0.0.tar.Z [[email protected] soft]# cd cmake-3.0.0 [[email protected] cmake-3.0.0]# ./configure #对包进行初始化配置 ...... -- Check size of unsigned short - done -- Using unsigned short -- Check if the sys

找bug的过程

关于昨天程序出差我找bug的过程记录 昨天才程序 https://www.cnblogs.com/pythonywy/p/11006273.html ├── xxxx │ ├── src.py │ └── fil_mode.py │ └── data_time.py │ └── loading.py │ └── data_time.py │ └── logger.py src.py与打印日志相关片段 if __name__ == '__main__': logger_start('程序主界面')

Dubbo加权轮询负载均衡的源码和Bug,了解一下?

本文是对于Dubbo负载均衡策略之一的加权随机算法的详细分析.从2.6.4版本聊起,该版本在某些情况下存在着比较严重的性能问题.由问题入手,层层深入,了解该算法在Dubbo中的演变过程,读懂它的前世今生. 之前也写了Dubbo的负载均衡策略: <一文讲透Dubbo负载均衡之最小活跃数算法> <Dubbo一致性哈希负载均衡的源码和Bug,了解一下?> 本文目录 第一节:什么是轮询? 本小节主要是介绍轮询算法和其对应的优缺点.引出加权轮询算法. 第二节:什么是加权轮询? 本小节主要是介

一个让服务器CPU飙升的BUG。找了2天才发现。

昨天升级了站点.发现一升级上去,就发现站点服务器CPU开始占用接近100%.但是数据库服务器变化不大 还原回更新之前的代码.立马CPU降低.一开始已经是增加的缓存机制有了问题,采用数据库读取,放到线上依旧. 接着以为是数据统计有问题,删除掉还是一样.最后的最后,通过看到工作线程,发现登录请求也蛮多的. 然后这个登录代码更新到旧版本.就OK了.这次版本对登录进行了重构.直接上代码 错误代码中 登录后直接是使用了user.BbbID,造成了500错误.IIS对这个500错误也会有CPU损耗.于是就飙

nginx的源码分析--间接回调机制的使用和类比

nginx使用了间接回调机制,结合upstream机制的使用来说明一下,首先明确几个事实: 1)其实ngxin和下游客户端的连接使用的是ngx_http_connection_t,每个连接对应着一个读事件.一个写事件,epoll监听队列监听的是事件(ngx_event_t),但是事件的data字段对应于这个事件所属的连接(ngx-connection_t).但是nginx和上游服务器之间的连接使用的ngx_peer_connection_t,其实ngx_peer_connection_t是ngx

Nginx的源码结构和模块初始化

前言: 上一篇(http://blog.csdn.net/xlgen157387/article/details/49781487)已经介绍了Nginx的基本功能,也介绍了在Windows下的安装和简单的实现负载均衡,下边主要学习一下Nginx的源码结构. Nginx的源码src目录结构(未进行编译安装) 环境:nginx-1.8.0+CentOS7.0 (可以使用yum install tree来安装tree命令,就可以显示出文件的树结构) [[email protected] nginx-1

CDN 二级回源实现

随着Cache节点数量的增加,大量的图片回源,导致图片源站的压力在不断增加.源站load飙高.IO飙高.由于图片源站上还有其他业务,必须使源站的压力降下来: 1.更改Cache 的回源策略(每天都有新的图片上传,也会产生大量的回源). 2.增加二级回源功能(上传的新图片,只有二级源站取一次图片就Ok了,其他Cache都去二级源站取图片,会降低回源的频率). 网络架构: > 用户首先到最近的Cache节点获取数据,如果有数据返回给用户. > 如果最近的Cache节点没有数据,去二级源站取数据,如

Android源码的BUG

在Android系统移植过程中,遇到很多源码上的BUG.但是我们看到市面上都是没有这些问题的.难道这些BUG在每个开发商都要经历一次解BUG的过程吗?Android释放的源码是否是最新的?暂时没有想法.仅在此记录我遇到的Android源码上的BUG. MTK8382/8121: 1.Launcher3无图标问题 机器(8寸)第一次烧录完成后,横放,启动,发现Launcher没有图标.竖屏没有这个问题.进一步发现对Launcher3 Clear data后也会如此.对比database,发现wor

一个python游戏源码

#finalPyPong.py import pygame,sys class MyBallClass(pygame.sprite.Sprite): def __init__(self,image_file,speed,location=[0,0]): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(image_file) self.rect = self.image.get_rect() self.rect.