龙空技术网

「来道题」Nginx的时间管理

初昕之旅 1151

前言:

眼前小伙伴们对“nginx管理”可能比较关注,我们都想要剖析一些“nginx管理”的相关内容。那么小编在网摘上汇集了一些有关“nginx管理””的相关文章,希望看官们能喜欢,小伙伴们一起来了解一下吧!

大家好,我是初昕之旅,您技术成长之路上的好帮手。每天一道面试题,年薪百万来找您~

Nginx的时间管理

Nginx是我们常用的负载均衡的中间件,我们定位追踪日志时经常会使用到其中的时间信息,而其实在时间这块它是有做自己单独的优化的。那么具体都实现了哪些功能呢?今天我们就来考察下Nginx的时间管理。

背景

背景

首先说下背景,我们的代码中如果需要获取时间信息,通常会调用一些库函数,比如C语言里的gettimeofday()等等,而这些函数的内部的实现最终都必须一步步地调用到一个操作系统提供的函数,来获取时间信息。因为不管我们软件层的应用程序是什么语言,时间信息是依赖硬件层提供的,我们必须通过操作系统来获取。也就是说,时间信息会存储在内核中,通过一个系统函数来对外暴露。

所以,基于以上的情况,当Nginx通过一些函数来获取时间信息时,本质上是经过了一次系统调用。而在操作系统的知识中,我们是有学习到用户态和内核态的概念的,用户态是我们应用程序所运行的空间,执行一次系统调用会触发用户态和内核态的切换,而这种切换时包含了系统中断、寄存器保存用户态的上下文、调度检查等等的步骤,这些步骤都是会增加系统的运行成本的。

因此,为了避免每次执行系统调用获取时间的系统成本,Nginx需要在自己的运行逻辑中缓存一份时间信息。那么Nginx是怎么缓存时间的呢?

时间槽

时间槽

Nginx在代码层面通过一个时间槽的概念来维护时间的缓存。时间槽是一个数组,长度有64位,也可以说是一个环形队列。时间槽是通过每个工作进程中共同维护的,所以是有可能存在在同一台机器上、不同的工作进程内的请求,对应的时间信息会有差异的情况。

那么这个时间槽是如何进行读取的呢?如图所示,首先全局有一个当前时间的变量,比如现在它指向了时间槽的第0位元素。此时,所有的读请求根据当前时间的指向,都会从第0位元素来获取时间信息。接下来,因为某种情况,时间信息需要被更新了,产生了一个写请求。由于时间信息是通过多个子变量来存储的,为了避免分裂读等问题,也就是在读取时间信息的过程中间产生了中断,正在读取的时间信息被其他写请求更新了,导致前后读取时间不一致的问题。这种问题我们在数据库中经常会遇到。

为了避免这个问题,写请求会去更新当前时间指向的下一位,也就是时间槽的第1位元素,同时未避免多个工作进程一起更新,会加一个锁。直到更新完成之后,最后将当前时间的变量的指向改到新的位置,也就是指向第1位元素,之后后续的读请求又都会从第1位元素中来获取时间信息了。

更新的时机

更新的时机

那么什么时候会触发时间信息的更新呢?也就是刚才咱们提到的写请求,什么时候会来一个写请求呢?Nginx是在每个事件处理的时候,通过一个标记位的全局变量,来判断本次事件处理开始之前,是否需要先更新一下时间。而这个全局的标记位的更新,是通过外部的SIGALRM的信号来进行赋值的。这个信号是定时产生的,通过Nginx配置文件中的timer_resolution的值来控制。

整体捋下,也就是每经过timer_resolution的时间间隔,比如1ms,产生一个外部信号,这个信号会中断Nginx当前的执行,对标记位的全局变量进行赋值,后续的事件处理时,先判断一下标记位是否是表达的需要更新时间的,如果是,则按前面讲过的流程,去更新时间槽的下一位元素;否则,则正常开始事件处理。

总结

那么以上就是今天讲的“Nginx的时间管理”的相关面试考点,我们最后再来简单回顾一下。

系统调用的成本:直接执行时间函数的获取会涉及系统调用的成本,对性能是有影响的,所以需要对时间进行缓存时间槽:Nginx实现了一个时间槽的数组,通过写新元素的方式避免分裂读的问题根据定时信号来更新:定时触发中断,进行时间槽的更新

那么等下次面试时,如果各位同学能够回答出来以上的知识点,我相信面试官一定会刮目相看的。每天一道面试题,年薪百万来找您~

附视频讲解:

视频加载中...

标签: #nginx管理