nginx时间更新机制(ngx_timer_resolution)

6 篇文章 0 订阅

nginx worker进程就是在处理网络事件、定时器事件和信号,核心是处理网络事件和定时器事件。下面看一下 worker进程是如何精确处理这些核心事件的。

 

1、worker进程启动

在 worker进程处理函数中,首先进行 worker进程运行相关的配置初始化设置操作,然后进入无限循环,处理 worker进程关注的信号和定时器事件以及核心的网络事件。下面是相关代码:

static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) {
    // ... 初始化相关操作

    for ( ;; ) {
        // ... 信号处理
        
        // worker进程核心处理逻辑 处理事件和定时器
        ngx_process_events_and_timers(cycle);
    }
}

 

2、worker进程核心处理函数

在 ngx_process_events_and_timers核心处理函数中,如果配置了 ngx_timer_resolution时间,则传给 epoll_wait的超时时间为 -1,表示永久阻塞等待,如果没有网络事件发生在 ngx_timer_resolution事件后定时器超时就会触发 ALARM信号,强制 epoll_wait返回。

如果没有配置 ngx_timer_resolution时间,nginx会调用 ngx_event_find_timer函数找到最近一个定时器超时的时间,把此时间设置为 epoll_wait的超时时间,如果没有网络事件的发生,在最近的定时器超时之前 epoll_wait函数就会返回,处理对应的超时事件。

 

这里看代码时一直有一个疑问,就是在调用 ngx_event_find_timer函数的时候获取了最近定时器的超时时间,如果在 epoll_wait等待期间,又添加了新的定时器比之前获取超时时间还少怎么办?如何触发刚刚添加的定时器。其实这里最开始就思考错误了,因为 nginx每个进程都是单线程的,当前进程在 epoll_wait阻塞的时候,进程是不会有地方可以添加新的定时器的。所以 ngx_event_find_timer函数返回的就是所有定时器中的最小的超时时间。

void ngx_process_events_and_timers(ngx_cycle_t *cycle) {
    // ...
    if (ngx_timer_resolution) {
        /*
            开启了时间精度  给epoll_wait的超时参数为-1  阻塞等待
            epoll_wait返回有两种情况:
            1、有网络事件发生
            2、有信号产生 提前加好的ALARM定时器在ngx_timer_resolution时间耗尽后 触发ALARM信号
        */
        timer = NGX_TIMER_INFINITE;
        flags = 0;

    } else {
        /*
            未开启高精度时钟
            在定时器中找到最近一个超时定时器的时间 设置为epoll_wait的超时时间
            防止长时间没有网络事件发生  epoll_wait等待时间过久  导致定时器事件延迟触发

            注意:
            这里之前一直有一个疑问  就是ngx_event_find_timer返回当前所有定时器中最近一个超时时间
            如果epoll_wait在等待超时时间内  有其他的定时器事件加入并且超时在之前最近的事件超时之前  如何触发新加的最近的超时事件定时器
            其实不会出现上面那种情况  因为nginx是单进程模型  进程阻塞在epoll_wait  不可能有地方添加定时器
        */
        timer = ngx_event_find_timer();
        flags = NGX_UPDATE_TIME;
    }

    delta = ngx_current_msec;
    // 根据不同系统调用不同的网络监听接口
    (void) ngx_process_events(cycle, timer, flags);
    delta = ngx_current_msec - delta;

    /*
        ngx_process_events执行时消耗的时间delta大于0
        这可能有新的定时器事件被触发 调用ngx_event_expire_timers方法处理所有满足条件的定时器事件
    */
    if (delta) {
        ngx_event_expire_timers();
    }

    // ...
}

 

3、网络事件处理函数ngx_process_events

调用 epoll_wait在参数 timer时间内等待网络事件或者信号事件的发生。

这里 epoll_wait返回后,需要判断是否需要更新 nginx的全局系统时间,如果 flags为 NGX_UPDATE_TIME,即没有 ngx_timer_resolution配置时,这里可能是最近的定时器超时了,需要更新全局系统时间,用于后续时间等的判断;或者 ngx_event_timer_alarm标志位为1,即设置了 ngx_timer_resolution配置,如果标志为1,说明是因为系统定时器超时触发的回调函数(ngx_event_process_init函数中设置)设置的此标志位,所以是 epoll_wait超时了,需要更新全局系统时间。

static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) {
	    //调用epoll_wait获取事件 timer参数是在process_events调用时传入的
    events = epoll_wait(ep, event_list, (int) nevents, timer);
    err = (events == -1) ? ngx_errno : 0;

    /*
        Nginx对时间的缓存和管理 flags标志位指示要更新时间
        或者ngx_event_timer_alarm标志位1  即之前ngx_event_core_module模块设置的系统定时器触发 设置了标志位
    */
    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }

    if (err) {
        if (err == NGX_EINTR) {
            // 系统定时器触发的超时
            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }
            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        return NGX_ERROR;
    }
    
 	//遍历本次epoll_wait返回的所有事件
    for (i = 0; i < events; i++) {
        // ...    
    }
    // ...
}

 

4、核心事件模块初始化init_process

在核心事件模块 ngx_event_core_module的初始化函数 ngx_event_process_init中,会对定时器进行初始化。

如果配置中设置了 ngx_timer_resolution参数,则设置指定时间的定时器,保证最长 ngx_timer_resolution就会触发信号,强制让 epoll_wait函数返回,即使没有网络事件的发生。

static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) {
    // ...
    	//初始化红黑树实现的定时器
    if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
        return NGX_ERROR;
    }
    
     /*
        配置文件中设置了控制时间精度  根据配置时间设置指定时间的定时器
        这里是配合epoll_wait使用  开启了指定时间精度  epoll_wait会阻塞等待  直到有网络事件发生或者到了定时器指定的时间 发生信号导致epoll_wait返回
    */
    if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
        struct sigaction  sa;
        struct itimerval  itv;
        ngx_memzero(&sa, sizeof(struct sigaction));
        sa.sa_handler = ngx_timer_signal_handler;
        sigemptyset(&sa.sa_mask);

        if (sigaction(SIGALRM, &sa, NULL) == -1) {
            return NGX_ERROR;
        }

        itv.it_interval.tv_sec = ngx_timer_resolution / 1000;
        itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000;
        itv.it_value.tv_sec = ngx_timer_resolution / 1000;
        itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000;

        if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed");
        }
    }
	// ...
}

定时器超时后回调的函数就是 ngx_timer_signal_handler,非常简单就是设置 ngx_event_timer_alarm标志位1。这个标识会在其他地方在更新时间的时候使用到。

static void ngx_timer_signal_handler(int signo) {
    ngx_event_timer_alarm = 1;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Nginx 中安装 ngx_http_mp4_module 模块,需要按照以下步骤进行操作: 1. 确认 Nginx 是否支持 ngx_http_mp4_module 模块 首先需要确认 Nginx 是否支持 ngx_http_mp4_module 模块,可以使用以下命令查看 Nginx 是否已经编译了该模块: ``` nginx -V 2>&1 | grep -o with-http_mp4_module ``` 如果输出结果为 with-http_mp4_module,则说明 Nginx 已经编译了 ngx_http_mp4_module 模块;如果输出结果为空,则说明 Nginx 没有编译该模块。 2. 下载 ngx_http_mp4_module 模块 如果 Nginx 没有编译 ngx_http_mp4_module 模块,需要下载该模块并添加到 Nginx 中。可以从 Github 上下载该模块,链接为:https://github.com/kaltura/nginx-vod-module。 可以使用以下命令将 ngx_http_mp4_module 模块下载到 /opt 目录下: ``` cd /opt git clone https://github.com/kaltura/nginx-vod-module.git ``` 3. 编译 Nginx 并添加 ngx_http_mp4_module 模块 在编译 Nginx 时需要添加 --add-module=/opt/nginx-vod-module 参数来指定 ngx_http_mp4_module 模块所在的目录,具体命令如下: ``` ./configure --prefix=/usr/local/nginx --add-module=/opt/nginx-vod-module make make install ``` 4. 配置 NginxNginx 的配置文件中添加以下内容,即可使用 ngx_http_mp4_module 模块: ``` location /video/ { mp4; mp4_buffer_size 1m; mp4_max_buffer_size 5m; } ``` 其中,/video/ 是视频文件所在的目录。mp4 是 ngx_http_mp4_module 模块提供的指令,表示该目录下的文件都是 MP4 格式的视频文件。 mp4_buffer_size 和 mp4_max_buffer_size 是 ngx_http_mp4_module 模块提供的两个参数,用于控制视频文件的缓存大小。 5. 重启 Nginx 完成以上步骤后,需要重启 Nginx 使配置生效: ``` nginx -s reload ``` 至此,ngx_http_mp4_module 模块安装完成。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值