问题来由:
在ngx_rtmp_relay_module模块当中有个static预拉流的事件,感觉这个设计有点小巧妙且匪夷所思。试想一下,如果是自己设计会怎么做?为啥不直接弄一个定时器事件?
问题分析:
先说说 ngx_rtmp_init_queue 这个队列,nginx自身定义了ngx_posted_accept_events和ngx_posted_events俩类事件队列这是一个post事件队列,主要用来处理rtmp相关
的事件,在rtmp模块当中主要是relay和exec模块引用了这个变量。
先来分析整个事件队列的初始化,事件注册以及事件在哪调用执行。
ngx_rtmp_init_queue队列初始化
ngx_rtmp_init_queue变量在ngx_rtmp.h当中定义,在ngx_rtmp_init_process函数初始化,也就是ngx_rtmp核心module进程启动的时候初始化,nginx两个事件队列变量是在
ngx_event_proccess_init的时候初始化的。
static ngx_int_t
ngx_rtmp_init_process(ngx_cycle_t *cycle)
{
#if (nginx_version >= 1007005)
ngx_queue_init(&ngx_rtmp_init_queue);
#endif
return NGX_OK;
}
ngx_rtmp_init_queue注册事件
有两个地方注册了ngx_rtmp_init_queue事件:
* relay模块注册预拉流pull事件
* exec模块注册执行外部程序的exec_static事件
这类事件都是需要再进程启动的时候注册然后执行,
ngx_rtmp_init_queue执行
ngx_rtmp_init_queue事件队列的执行是在worker进程stat模块初始化的时候,调用的。ngx_event_process_posted函数是用来执行post队列事件的
ngx_rtmp_stat_module其实是一个NGX_HTTP_MODULE的一个模块。
static ngx_int_t
ngx_rtmp_stat_init_process(ngx_cycle_t *cycle)
{
/*
* HTTP process initializer is called
* after event module initializer
* so we can run posted events here
*/
ngx_event_process_posted(cycle, &ngx_rtmp_init_queue);
return NGX_OK;
}
从ngx_rtmp_init_queue事件初始化,注册都是在NGX_RTMP_MODULE模块当中的,而事件队列的执行却是在NGX_HTTP_MODULE中的。
为啥要在一个http模块当中执行rtmp的队列事件?
问题原因剖析
后来仔细分析加验证你会发现,问题出在了config配置文件设置了rtmp模块是在event模块之前导致的, 打开ngx_module.c文件看下就发现
由于定时器事件和队列事件的初始化都是在 ngx_event_process_init 当中的, 所以你在worker启动初始化这rtmp模块加定时器,后面event又给覆盖初始化了,所以导致无效
static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
······
ngx_queue_init(&ngx_posted_accept_events);
ngx_queue_init(&ngx_posted_events);
ngx_queue_init(&ngx_posted_delayed_events);
if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
return NGX_ERROR;
}
······
}
而http模块是在event模块后面执行的,所以在http模块当中去执行ngx_rtmp_init_queue事件就不会重新给初始化了。 这样ngx_rtmp_init_queue事件执行完之后再在事件的
handler里面加的定时器这样定时器就不会失效了。这也是作者为啥这么干的原因