NGINX 时间管理机制

         nginx 自己维护了一个时间,用户向用户提供时间,它使用缓存时间的机制,这样避免了频繁的系统调用(gettimeofday),加快处理速度。

但缓存时间,又必须要及时更新时间,否则时间将不准确。所以, NGINX配套了一系列的措施,减少误差。

void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
    ngx_uint_t  flags;
    ngx_msec_t  timer, delta;

    if (ngx_timer_resolution) {
        timer = NGX_TIMER_INFINITE;   //-1
        flags = 0;

    } else {
        timer = ngx_event_find_timer();
        flags = NGX_UPDATE_TIME;
    }

    (void) ngx_process_events(cycle, timer, flags);
}
先暂时不去理会ngx_timer_resolution,只关注else部分,timer = ngx_event_find_timer(),

该函数返回距离第一个超时事件还有多久时间,可能为-1,即目前没有注册超时事件。

而同时,flags 标记为NGX_UPDATE_TIME,即更新缓存时间。


ngx_process_events对应于具体的事件处理函数,本文以epoll为例,因而对应于如下代码:

static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    events = epoll_wait(ep, event_list, (int) nevents, timer);
    
    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }
}
timer为epoll_wait等待的最大时间,即epoll_wait返回后,由于flags被设置为NGX_UPDATE_TIME,

因而,调用ngx_time_update进行缓存时间的更新。


上面带来了一个新问题,如果,timer 为-1或者过大,而epoll_wait又没有获得可用套接字,那么,此时,

时间很久得不到更新,导致误差过大。因而,nginx引入了一个强制更新的策略。

if (ngx_timer_resolution) {
    timer = NGX_TIMER_INFINITE;  //-1
    flags = 0;
}
ngx_timer_resolution 为用户配置的参数值,即ngx_timer_resolution时间过后,必须进行时间的更新,

这样防止时间长时间的不到更新。timer = -1, 这样,epoll_wait 会无穷阻塞。


static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
    if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
        struct sigaction  sa;
        struct itimerval  itv;

        sa.sa_handler = ngx_timer_signal_handler;
        if (sigaction(SIGALRM, &sa, NULL) == -1) {}

        if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {}
    }
}
首先注册一个信号(SIGALRM)处理函数,然后设定一个计时器setitimer, 在(timer_resoluiton)时间超时后,

发送SIGALRM事件,那么事件处理函数究竟完成了一个什么样的功能?

void
ngx_timer_signal_handler(int signo)
{
    ngx_event_timer_alarm = 1;
}
仅仅将ngx_event_timer_alarm置1。有一个知识点:信号中断系统调用。

因而,SIGALRM会中断epoll_wait的调用,epoll_wait返回后,errno设置为EINTR。

events = epoll_wait(ep, event_list, (int) nevents, timer);
    
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
    ngx_time_update();
}
这里,ngx_event_timer_alarm已经在信号处理函数中被设置为1, 因此,会执行时间更新。


既然有强制刷新策略,为嘛还要第一种策略呢?我觉得是这样,首先这算是一个优化措施,而

nginx要保证最少配置即可使用,所以,此配置项可以不用进行配置。不同场景有不同的配置,

频繁访问的网站,不需要timer_resolution,epoll_wait会迅速返回,时间可以及时更新。

你可能感兴趣的:(NGINX 时间管理机制)