nginx源码阅读(十二).定时器及超时事件的管理

本文深入探讨nginx的定时器实现,基于红黑树的超时事件管理,以及时间缓存的更新策略。分析了如何处理长时间未更新缓存导致的超时延迟,介绍了关键函数如ngx_update_time、ngx_event_timer_init等,为理解nginx内部机制提供参考。
摘要由CSDN通过智能技术生成

前言

本小节将分析nginx定时器以及时间管理部分的知识,当事件超时时,会触发nginx中的超时机制进行处理。nginx的定时器的底层实现是使用的红黑树,这里就不去讲解红黑树了,网上有很多资料。

时间缓存

nginx为了性能方面的考虑,并不是每次需要获取时间时都调用gettimeofday函数,而是将时间缓存下来存在全局变量中(core/ngx_times.c)。

/* 格林威治时间,1970年1月1日0点0分0秒到当前时间的毫秒数 */
volatile ngx_msec_t      ngx_current_msec;  
/* 以ngx_time_t结构体缓存的时间 */
volatile ngx_time_t     *ngx_cached_time;
/* 记录error_log的当前时间的字符串 */
volatile ngx_str_t       ngx_cached_err_log_time;
/* 记录HTTP相关的当前时间的字符串 */
volatile ngx_str_t       ngx_cached_http_time;
/* 记录HTTP日志的当前时间的字符串 */
volatile ngx_str_t       ngx_cached_http_log_time;
/* 以ISO 8601标准格式记录下的字符串形式的当前时间 */
volatile ngx_str_t       ngx_cached_http_log_iso8601;

关于管理时间缓存的结构体,这里就不列出了,因为也没什么太大的必要,就是存一些秒、分、年、时区等。

既然有了时间缓存,那么何时更新这个缓存就成了我们需要关注的问题了

该工作主要由ngx_time_update函数完成,它内部会调用gettimeofday函数来更新当前缓存的时间,上面列出的全局变量也都会得到更新,具体的代码在core/ngx_times.c中实现,感兴趣可以看看。

缓存时间的精度

由于时间是缓存下来的,因此如果长时间没有调用gettimeofday函数更新缓存,则可能会导致有些超时事件得不到及时的处理。

关于这个问题,nginx的做法其实我们前面都已经展示过了,其实就是使用配置文件中设置的ngx_timer_resolution作为更新的频率,设置setitimer函数每过ngx_timer_resolution毫秒调用ngx_timer_signal_handler,而ngx_timer_signal_handler函数的作用就只是将ngx_event_timer_alarm标志位置为1,这样在ngx_epoll_process_events函数中借助该标志位就可以调用ngx_time_update函数更新时间缓存。
关于设置setitimer函数的代码在ngx_event_process_init中实现如下:

/* nginx中采用了时间缓存,并不是需要获取时间时就调用gettimeofday来获取
 * 因此精度方面可能需要进行控制
 * 而ngx_timer_resolution(通过核心模块的配置项获取,默认是0)表示时间的精度
 * 而NGX_USE_TIMER_EVENT在epoll中并没有使用
 * 因此只要设置了控制时间的精度
 * 就会定期进行更新
 */
if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
    /* 设置SIGALRM捕捉之后的处理函数
     * ngx_timer_signal_handler
     */
    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) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigaction(SIGALRM) failed");
        return NGX_ERROR;
    }

    /* 根据ngx_timer_resolution设置定时时间
     * it_interval成员指定间隔的时间
     * it_value成员指定初始定时时间
     */
    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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值