深入剖析nginx时间缓存
本文适合对nginx实现原理比较感兴趣的同学阅读,需要具有肯定的服务端编程知识。
一、背景
在服务器开发领域,时间的精确度关系到系统可以否正常运行,尤其是当系统中存在超时事件需要解决时。但是系统时间的获取需要一次昂贵的系统调使用,作为一款成熟的服务器软件,Nginx是如何优化这部分的性可以开销?
二、时间缓存
接触过系统设计的同学都知道,对于频繁的数据获取,在数据未变化的情形下,能通过添加缓存来优化性可以,由于缓存的访问速度远高于源数据的访问速度。这样的例子有很多,比方CPU设计有二级缓存,在传统的database基础上有了我们今天的redis、memcache等nosql。对于系统时间也一样,既然获取系统时间开销较大,能尝试着将获取到的时间缓存起来,需要时直接从缓存中取即可以了。但与此同时,也引入了缓存时间与实际时间不一致的可可以,下面看看Nginx是如何处理这一问题。
三、设计与实现
Nginx时间缓存设计
如上图所示,Nginx时间缓存包括时间读取和时间写入者,当需要升级时间时,nginx调使用gettimeofday系统调使用获取时间,而后升级缓存。需要获取时间的代码直接从time cache中取出就可。
这里又产生了新的问题,具体包括:
读写并发,即读和写同时操作时间缓存会造成获取的时间混乱。
多写并发,多个执行体同时升级时间缓存,同样造成时间混乱。
而常见的处理互斥的方案包括:
加锁保证数据串行化
无锁化设计
像Nginx这样对于性可以有着极致追求的server来说,自然不会用系统自带的锁机制。其实现的ngx_lock和ngx_unlock的背后都是无锁化的原子操作。
对于多写并发,nginx在ngx_time_update函数中通过全局的ngx_time_lock进行互斥,确保同一时刻只会存在一个执行体升级时间缓存。
对于读写并发,nginx设计了NGX_TIME_SLOTS个slot,使用于隔离读写操作的时间缓存。同时引入时间缓存指针,原子地升级当前缓存的指向位置。
Nginx时间缓存实现
下面看具体实现代码(以nginx-1.13.1为例src/core/ngx_times.c):
void ngx_time_update(void)
ngx_time_update的流程图为:
值得一提的是,这里采使用了ngx_memory_barrier来避免指令重排,这样能尽可可以地保证ngx_cached_time、ngx_cached_http_time.data、ngx_cached_err_log_time.data、ngx_cached_http_log_time.data、ngx_cached_http_log_iso8601.data、ngx_cached_syslog_time.data中存储的时间数据一致。
slot设计
上面谈到了nginx采使用slot来从空间上避免读写执行体同时操作时间缓存,slot的设计规则为:
获取时间的执行体采使用ngx_timeofday获取了当前ngx_cached_time的快照,随后读取对应的slot中数据,包括sec和msec。
升级时间的执行体通过ngx_time_update原子升级ngx_cached_time指向,这样升级之后的时间读取就是新的slot中的时间数据。
这里,nginx利使用了修改指针的原子性,确保读写不会造成时间数据混乱。而时间数据本身包括sec和msec,无法完成修改的原子性,这种将非原子性修改操作转换为原子性修改操作的手法,值得借鉴。
原PO主:亘井/软件编程之路
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 深入剖析nginx时间缓存