nginx的时间管理

Nginx时间缓存机制

  nginx出于性能考虑采用类似lib_event的方式,自己对时间进行了cache,用来减少对gettimeofday()的调用,因为一般来说服务器对时间的精度要求不是特别的高,不过如果需要比较精确的timer,nginx还提供了一个timer_resolution指令用来设置时间精度,具体的机制再后面会做介绍。在ngx_times.c中提供了ngx_time_update()函数来更新时间缓存,另外还有一个在信号处理中用来更新cached_err_log_time的ngx_time_sigsafe_update()函数,其他地方都是从时间缓存中取得时间。

   由于nginx采用的是master-workers多进程的方式,每个一进程都会自己维护一个时间缓存。那么在nginx中什么时候会更新时间缓存呢?上面说到nginx采用了2种方式来维护时间,首先 来介绍没有用timer_resolution指令设置时间精度的情况,也就是ngx_timer_resolution为0的情况,实际上只要找一下ngx_time_update()和ngx_time_sigsafe_update()这两个函数被调用的位置就知道。首先来说一下ngx_time_sigsafe_update(),它比较简单只是更新了ngx_cached_err_log_time,它会在每次执行信号处理函数的时候被调用,也就是在ngx_signal_handler()函数中。ngx_time_update()函数在master进程中的ngx_master_process_cycle()主循环中被调用,具体位置为sigsuspend()函数之后,也就是说master进程捕捉到并处理完一个信号返回的时候会更新时间缓存;在worker进程中,ngx_time_update函数的调用链为ngx_worker_process_cycle() -> ngx_process_events_and_timers() -> ngx_process_events() -> ngx_time_update(), 其中ngx_process_events()实际上一个宏,nginx中定义如下:

#define ngx_process_events   ngx_event_actions.process_events

而ngx_event_actions为nginx的I/O模型接口函数结构体,封装如epoll, kqueue,select,poll等这些提供的接口,这里仅对epoll进行分析,其他类似,于是ngx_event_actions.process_events 对应ngx_epoll_module.c文件中的 ngx_epoll_process_events()函数,在这个函数中执行epoll_wait()返回后会调用ngx_time_update()更新时间缓存,也就是当epoll通知有事件到达或者epoll超时返回后会更新一次时间;最后在cache_manager的进程也调用ngx_time_update()维护自己的时间缓存,这里不做介绍。

第二种方式 ,ngx_timer_resolution被设置为大于0,也就是说,此时nginx的时间缓存精确到ngx_timer_resolution毫秒,具体的实现方法是在event模块的初始化函数ngx_event_process_init()中调用了setitimer()函数,它每隔ngx_timer_resolution毫秒会产生一个SIGALRM信号,这个信号的处理函数为ngx_timer_signal_handler(),定义如下:

 

ngx_timer_signal_handler(int signo)
{
    ngx_event_timer_alarm = 1;

#if 1
    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer signal");
#endif
}

它非常简单,只是将ngx_event_timer_alarm设置为1,用来记录有SIGALRM信号发生了,这时在来看ngx_epoll_process_events()函数,epoll_wait()的timeout被设置为-1,如果epoll_wait()是被SIGALRM信号唤醒,则调用ngx_time_update()更新时间缓存,否则继续使用之前的时间缓存,因为setitimer()每隔ngx_timer_resolution毫秒总会产生一次SIGALRM信号,这样就保证了时间缓存的精度为ngx_timer_resolution毫秒。这里只介绍了worker进程的情况,其他进程类似。

 

ngx_time_update()和ngx_time_sigsafe_update()这两个函数的实现比较简单,但是还是有几个值得注意的地方,首先由于时间可能在信号处理中被更新,另外多线程的时候也可能同时更新时间(nginx现在虽然没有开放多线程,但是代码中有考虑),nginx使用了原子变量ngx_time_lock来对时间变量进行写加锁,而且nginx考虑到读时间的操作比较多,出于性能的原因没有对读进行加锁,而是采用维护多个时间slot的方式来尽量减少读访问冲突,基本原理就是,当读操作和写操作同时发生时(1,多线程时可能发生;2,当进程正在读时间缓存时,被一信号中断去执行信号处理函数,信号处理函数中会更新时间缓存),也就是读操作正在进行时(比如刚拷贝完ngx_cached_time->sec,或者拷贝ngx_cached_http_time.data进行到一半时),如果写操作改变了读操作的时间,读操作最终得到的时间就变混乱了。nginx这里采用了64个slot时间,也就是每次更新时间的时候都是更新下一个slot,如果读操作同时进行,读到的还是之前的slot,并没有被改变,当然这里只能是尽量减少了时间混乱的几率,因为slot的个数不是无限的,slot是循环的,写操作总有几率会写到读操作的slot上。不过nginx现在实际上并没有采用多线程的方式,而且在信号处理中只是更新cached_err_log_time,所以对其他时间变量的读访问是不会发生混乱的。 另一个地方是两个函数中都调用了 ngx_memory_barrier() ,实际上这个也是一个宏,它的具体定义和编译器及体系结构有关,gcc和x86环境下,定义如下:

#define ngx_memory_barrier()    __asm__ volatile ("" ::: "memory")

它的作用实际上还是和防止读操作混乱有关,它告诉编译器不要将其后面的语句进行优化,不要打乱其执行顺序,具体还是来看一下 ngx_time_update函数:

ngx_time_update()

{

  ...

 

  if (!ngx_trylock(&ngx_time_lock)) {
        return;
    }

   ...

    tp = &cached_time[slot];

    tp->sec = sec;
    tp->msec = msec;


    ngx_gmtime(sec, &gmt);


    p0 = &cached_http_time[slot][0];

    (void) ngx_sprintf (p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
                       week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
                       months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
                       gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);

#if (NGX_HAVE_GETTIMEZONE)

    tp->gmtoff = ngx_gettimezone();
    ngx_gmtime(sec + tp->gmtoff * 60, &tm);

#elif (NGX_HAVE_GMTOFF)

    ngx_localtime(sec, &tm);
    cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
    tp->gmtoff = cached_gmtoff;

#else

    ngx_localtime(sec, &tm);
    cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
    tp->gmtoff = cached_gmtoff;

#endif


    p1 = &cached_err_log_time[slot][0];

    (void) ngx_sprintf (p1, "%4d/%02d/%02d %02d:%02d:%02d",
                       tm.ngx_tm_year, tm.ngx_tm_mon,
                       tm.ngx_tm_mday, tm.ngx_tm_hour,
                       tm.ngx_tm_min, tm.ngx_tm_sec);


    p2 = &cached_http_log_time[slot][0];

    (void) ngx_sprintf (p2, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
                       tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
                       tm.ngx_tm_year, tm.ngx_tm_hour,
                       tm.ngx_tm_min, tm.ngx_tm_sec,
                       tp->gmtoff < 0 ? '-' : '+',
                       ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));


    ngx_memory_barrier();

    ngx_cached_time = tp;
    ngx_cached_http_time.data = p0;
    ngx_cached_err_log_time.data = p1;
    ngx_cached_http_log_time.data = p2;


    ngx_unlock(&ngx_time_lock);

}

可以看到ngx_memory_barrier()之后是四条赋值语句,如果没有 ngx_memory_barrier()编译器可能会将 ngx_cached_time = tp ,ngx_cached_http_time.data = p0,ngx_cached_err_log_time.data = p1, ngx_cached_http_log_time.data = p2 分别和之前的 tp = &cached_time[slot] , p0 = &cached_http_time[slot][0] , p1 = &cached_err_log_time[slot][0] , p2 = &cached_http_log_time[slot][0] 合并优化掉,这样的后果是 ngx_cached_time,ngx_cached_http_time,ngx_cached_err_log_time, ngx_cached_http_log_time这四个时间缓存的不一致性时长增大了,因为 在最后一个ngx_sprintf执行完后这四个时间缓存才一致,在这之前如果有其他地方正在读时间缓存就可能导致读到的时间不正确或者不一致,而采用ngx_memory_barrier() 后,时间缓存更新到一致的 状态只需要几个时钟周期,因为只有四条赋值指令,显然在这么短的时间内发生读时间缓存的概率会小的多了。从这里可以看出Igor考虑是非常细致的。

 

<think>好的,我现在要帮用户查找关于Nginx UI管理的工具或仪表盘的信息。首先,我需要理解用户的需求。用户提到了“Nginx UI management dashboard or tool”,所以他们可能是在寻找一个图形化界面来管理Nginx配置,而不需要手动编辑配置文件。这通常对不熟悉命令行或者希望提高效率的用户很有帮助。 接下来,我应该回忆一下常见的Nginx管理工具。之前了解过的一些开源项目可能符合要求。比如Nginx Proxy Manager,这个工具提供了用户友好的界面,支持SSL证书管理和反向代理配置。另外,还有Nginx GUI,可能也是一个选项,但需要确认其功能和维护状态。 然后,我需要考虑用户可能的部署方式。用户之前引用了使用Docker部署WebVirtMgr的内容,所以可能对Docker比较熟悉。因此,推荐支持Docker部署的工具会更合适。比如Nginx Proxy Manager和NginxUI都支持Docker,这会方便用户快速搭建。 另外,用户提到的参考引用中有Flask和Django的管理面板,虽然这些是Python框架的仪表盘,但可能用户对Web界面比较感兴趣。因此,推荐的Nginx工具也应该有类似的Web界面,易于使用。 还要检查这些工具的活跃度。查看它们的GitHub仓库是否还在维护,是否有最近的更新,这可以确保工具的可靠性和安全性。比如Nginx Proxy Manager的GitHub仓库star数较多,可能更受欢迎。 用户可能需要的功能包括SSL管理、反向代理、负载均衡等。需要确认推荐的工具是否支持这些功能。例如,Nginx Proxy Manager支持Let's Encrypt集成,自动申请SSL证书,这对用户来说可能非常有用。 另外,还要考虑安装和配置的难易程度。提供Docker-compose文件的工具可以简化部署步骤,用户只需几条命令就能启动服务,这会节省他们的时间。 可能还需要区分不同工具的特点。比如,NginxUI可能更注重配置文件的直接编辑,而Nginx Proxy Manager则更多面向代理和SSL管理。用户的需求如果是简单的配置管理,可能需要不同的工具。 最后,生成相关问题时要覆盖用户可能感兴趣的方面,比如如何选择工具、安装教程、功能对比以及安全性问题。这些问题可以帮助用户进一步探索和解决实际使用中可能遇到的挑战。 总结一下,我需要列出几个符合要求的工具,简要介绍它们的特点,并提供部署方式,特别是Docker相关的步骤。同时,确保回答结构清晰,引用正确,并生成相关问题供用户参考。</think>以下是关于Nginx UI管理工具的相关信息及推荐方案: --- ### 推荐工具及特点 1. **Nginx Proxy Manager** - **功能**:提供可视化界面管理反向代理、SSL证书(支持Let's Encrypt自动续签)、HTTP/HTTPS转发等。 - **部署方式**:支持Docker一键部署,适合快速搭建[^1]。 - **代码示例(Docker部署)**: ```bash docker run -d \ --name nginx-proxy-manager \ -p 80:80 -p 443:443 -p 81:81 \ -v /path/to/data:/data \ -v /path/to/letsencrypt:/etc/letsencrypt \ jc21/nginx-proxy-manager:latest ``` 2. **NginxUI** - **功能**:开源Web界面,支持配置文件编辑、站点管理、SSL证书配置、负载均衡等。 - **特点**:基于Go语言开发,轻量且跨平台,支持API操作[^2]。 - **部署方式**:提供Docker镜像及二进制文件: ```bash docker run -d \ --name nginx-ui \ -p 8000:8000 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf \ -v /var/run/docker.sock:/var/run/docker.sock \ chenquincy/nginx-ui:latest ``` 3. **Webmin/Virtualmin** - **功能**:通用服务器管理工具,包含Nginx配置模块,适合复杂场景。 - **集成性**:支持多服务管理(如DNS、数据库),需安装Nginx模块扩展功能。 --- ### 如何选择工具? - **轻量化需求**:优先选择Nginx Proxy Manager或NginxUI,部署简单。 - **高级配置**:若需直接编辑配置文件,NginxUI更灵活。 - **企业级管理**:Webmin/Virtualmin适合综合运维场景。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值