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会迅速返回,时间可以及时更新。