7788msc.com:nginx-rtmp-module失去响应的问题排查

版权声明:本文为博主原创文章,未经博主允许不得转载。 http://www.309.ib776.com/wangjingkaibear/article/details/89450994

本文地址:http://www.309.ib776.com/wangjingkaibear/article/details/89450994
文章摘要:7788msc.com,你到底和什么敌人在交战有保护着自己就一定会安全"处女星号幸运28官方网"入口眉头愈发。

一直在使用nginx+nginx-rtmp-module做直播和mp4点播(rtmp直播和rtmp点播)

但是最近有一个项目,不定时的就无法点播,重启nginx可以解决,开始几次没在意,后来反复出现,所以开始排查。

出现问题时,nginx是在运行的,但是nginx的Welcome页面打不开,也无法往nginx推流,access和error日志不再写入。使用top命令,发现nginx的work?processCPU占用一直是100%。

后来想是不是这个nginx-rtmp-module有Bug,遂重新编译了nginx+nginx-http-flv(这个模块基于nginx-rtmp-module),都使用了最新版,希望能解决,没想到第二天又再次出现同样的问题。

一番谷歌之后,发现还有一个perf命令

#原来不是内置的程序,之前有安装过,使用yum安装
yum -y install perf
#使用方法
perf top -p "nginx work process的pid"

使用命令之后看到主要有两个函数占用了CPU

76.06%  nginx     [.] ngx_rtmp_mp4_parse
23.70%  nginx     [.] ngx_rtmp_mp4_parse_trak

看起来应该是点播导致的问题,感觉可能是死循环之类的。遂向http-flv模块作者提了个issue,答曰点播这块没改过,所以去请教arut(nginx-rtmp-module作者),提了个issue(issue #1405)。同时研究了一下 ngx_rtmp_mp4_module.c 里的代码,找到上面两个函数,发现代码里有ngx_log_debug2这样的函数,大概就是写debug日志吧。了解到nginx可以打开debug日志,不过需要重新编译,所以又编译了一个开启debug的nginx,并且配置了相关配置文件。希望通过对应的日志,找到问题是出在哪个位置。

蓝鹅,开启debug后,nginx跑了一天有多,居然还没出问题。arut现在不怎么管这个项目了,issue里只有一个波兰老哥跟我交流,提了一些猜测,没有实质性的意义。

周六到公司加(蹭)班(饭)的时候再上去看,问题终于又出现了,此时产生了47GB的日志(┬_┬),怎么查看又成了问题,tailf?tail?cat等都要处理半天,能打印的都是无限循环的:

2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'

我想看出现这个日志之前的日志,百度找了一下,找到了一个UVviewsoft LogViewer,很好,日志下载到Windows机子上,能很快打开,只是滚滚动条也颇费一番力气。最后找到的日志是这样,并且通过再往前的日志找到了触发此问题的视频文件,使用ffmpeg查看这个视频文件,发现此文件只有一个Stream,只有视频流,没有音频流。

2019/04/20 15:18:07 [debug] 21771#0: *74 read: 10, 00007FFDDD60C5D0, 8, 32
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: found moov box
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box unhandled 'mvhd'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: trying track 0
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: too small box: size=-8
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'
2019/04/20 15:18:07 [debug] 21771#0: *74 mp4: box 'trak'

?mp4: box 'trak'日志来源于ngx_rtmp_mp4_parse函数

代码如下:

ngx_rtmp_mp4_parse(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
{
    uint32_t                   *hdr, tag;
    size_t                      size, nboxes;
    ngx_uint_t                  n;
    ngx_rtmp_mp4_box_t         *b;

    while (pos != last) {
        if (pos + 8 > last) {
            ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "mp4: too small box: size=%i", last - pos);
            return NGX_ERROR;
        }

        hdr = (uint32_t *) pos;
        size = ngx_rtmp_r32(hdr[0]);
        tag  = hdr[1];

        if (pos + size > last) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                          "mp4: too big box '%*s': size=%uz",
                          4, &tag, size);
            return NGX_ERROR;
        }

        b = ngx_rtmp_mp4_boxes;
        nboxes = sizeof(ngx_rtmp_mp4_boxes) / sizeof(ngx_rtmp_mp4_boxes[0]);

        for (n = 0; n < nboxes && b->tag != tag; ++n, ++b);

        if (n == nboxes) {
            ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "mp4: box unhandled '%*s'", 4, &tag);
        } else {
            ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "mp4: box '%*s'", 4, &tag);
            b->handler(s, pos + 8, pos + size);
        }

        pos += size;
    }

    return NGX_OK;
}

拉上搞音视频编码的同事分析,认为size不应该等于0,这里应该加个判断,死循环应该出在while这个循环这里。

遂修改如下:

ngx_rtmp_mp4_parse(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
{
    uint32_t                   *hdr, tag;
    size_t                      size, nboxes;
    ngx_uint_t                  n;
    ngx_rtmp_mp4_box_t         *b;

    while (pos != last) {
        if (pos + 8 > last) {
            ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "mp4: too small box: size=%i", last - pos);
            return NGX_ERROR;
        }

        hdr = (uint32_t *) pos;
        size = ngx_rtmp_r32(hdr[0]);

        //这里加个判断*****************************
        if(0 == size) return NGX_ERROR; //********
        //这里加个判断*****************************

        tag  = hdr[1];

        if (pos + size > last) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                          "mp4: too big box '%*s': size=%uz",
                          4, &tag, size);
            return NGX_ERROR;
        }

        b = ngx_rtmp_mp4_boxes;
        nboxes = sizeof(ngx_rtmp_mp4_boxes) / sizeof(ngx_rtmp_mp4_boxes[0]);

        for (n = 0; n < nboxes && b->tag != tag; ++n, ++b);

        if (n == nboxes) {
            ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "mp4: box unhandled '%*s'", 4, &tag);
        } else {
            ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "mp4: box '%*s'", 4, &tag);
            b->handler(s, pos + 8, pos + size);
        }

        pos += size;
    }

    return NGX_OK;
}

重新编译,再次点播有问题的视频文件,点播失败,但是不会导致nginx卡死。先这样吧

展开阅读全文

没有更多推荐了,首页

新世纪湖南快乐十分走势图 汇丰时时彩软件 99彩票平台直营网 太阳城官方唯一正网游戏下载登入 申博太阳城亚洲微信充值网上娱乐场
海立方申博馆时时彩计划软件 正大国际快3时时彩计划软件 神话吉林快3彩票 奥斯卡天津快乐十分计划群大全 澳门赌场江西11选5彩票官网
加拿大28计划 新葡京娱乐场玩法 澳门新葡京吉林快3开奖结果 金沙游戏登入 阿玛尼幸运农场时时彩开奖记录
mg地穴的远征登入 时时彩技巧想输都难 申博官网下载登入 正大国际VR彩票百家乐最牛攻略 亚洲国际北京赛车官网