Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1502020
  • 博文数量: 228
  • 博客积分: 1698
  • 博客等级: 上尉
  • 技术积分: 3241
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-24 21:49
个人简介

Linux

文章分类

全部博文(228)

文章存档

2017年(1)

2016年(43)

2015年(102)

2014年(44)

2013年(5)

2012年(30)

2011年(3)

分类: LINUX

2015-11-11 16:30:46

转自:http://blog.csdn.net/spch2008/article/details/29803719

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

但缓存时间,又必须要及时更新时间,否则时间将不准确。所以, NGINX配套了一系列的措施,减少误差。
点击(此处)折叠或打开

  1. void
  2. ngx_process_events_and_timers(ngx_cycle_t *cycle)
  3. {
  4.     ngx_uint_t flags;
  5.     ngx_msec_t timer, delta;
  6.   
  7.     if (ngx_timer_resolution) {
  8.         timer = NGX_TIMER_INFINITE; //-1
  9.         flags = 0;
  10.   
  11.     } else {
  12.         timer = ngx_event_find_timer();
  13.         flags = NGX_UPDATE_TIME;
  14.     }
  15.   
  16.     (void) ngx_process_events(cycle, timer, flags);
  17. }
暂时不去理会ngx_timer_resolution,只关注else部分,timer = ngx_event_find_timer(),
该函数返回距离第一个超时事件还有多久时间,可能为-1,即目前没有注册超时事件。而同时,flags 标记为NGX_UPDATE_TIME,即更新缓存时间。
ngx_process_events对应于具体的事件处理函数,本文以epoll为例,因而对应于如下代码:
点击(此处)折叠或打开
  1. static ngx_int_t
  2. ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
  3. {
  4.     events = epoll_wait(ep, event_list, (int) nevents, timer);
  5.       
  6.     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
  7.         ngx_time_update();
  8.     }
  9. }
timer为epoll_wait等待的最大时间,即epoll_wait返回后,由于flags被设置为NGX_UPDATE_TIME,
因而,调用ngx_time_update进行缓存时间的更新。

上面带来了一个新问题,如果,timer 为-1或者过大,而epoll_wait又没有获得可用套接字,那么,此时,时间很久得不到更新,导致误差过大。
因而,nginx引入了一个强制更新的策略。
点击(此处)折叠或打开

  1. if (ngx_timer_resolution) {
  2.     timer = NGX_TIMER_INFINITE; //-1
  3.     flags = 0;
  4. }
ngx_timer_resolution 为用户配置的参数值,即ngx_timer_resolution时间过后,必须进行时间的更新,
这样防止时间长时间的不到更新。
timer = -1, 这样,epoll_wait 会无穷阻塞。

点击(此处)折叠或打开

  1. static ngx_int_t
  2. ngx_event_process_init(ngx_cycle_t *cycle)
  3. {
  4.     if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
  5.         struct sigaction sa;
  6.         struct itimerval itv;
  7.   
  8.         sa.sa_handler = ngx_timer_signal_handler;
  9.         if (sigaction(SIGALRM, &sa, NULL) == -1) {}
  10.   
  11.         if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {}
  12.     }
  13. }
首先注册一个信号(SIGALRM)处理函数,然后设定一个计时器setitimer, 在(timer_resoluiton)时间超时后,发送SIGALRM事件,那么事件处理函数究竟完成了一个什么样的功能?
点击(此处)折叠或打开
  1. void
  2. ngx_timer_signal_handler(int signo)
  3. {
  4.     ngx_event_timer_alarm = 1;
  5. }
仅仅将ngx_event_timer_alarm置1。有一个知识点:信号中断系统调用。
因而,SIGALRM会中断epoll_wait的调用,epoll_wait返回后,errno设置为EINTR。
点击(此处)折叠或打开
  1. events = epoll_wait(ep, event_list, (int) nevents, timer);
  2.       
  3. if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
  4.     ngx_time_update();
  5. }
这里,ngx_event_timer_alarm已经在信号处理函数中被设置为1, 因此,会执行时间更新。
既然有强制刷新策略,为嘛还要第一种策略呢?我觉得是这样,首先这算是一个优化措施,而nginx要保证最少配置即可使用,所以,此配置项可以不用进行配置。不同场景有不同的配置,频繁访问的网站,不需要timer_resolution,epoll_wait会迅速返回,时间可以及时更新。

阅读(1278) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~