日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入剖析nginx时间缓存

發布時間:2024/2/28 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入剖析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_lock用于互斥,避免同時更新時間if (!ngx_trylock(&ngx_time_lock)) {return;} //獲取當前時間ngx_gettimeofday(&tv);sec = tv.tv_sec;msec = tv.tv_usec / 1000;ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;tp = &cached_time[slot];//秒值一致則只需要更新當前slot的msecif (tp->sec == sec) {tp->msec = msec;ngx_unlock(&ngx_time_lock);return;} //獲取下一slotif (slot == NGX_TIME_SLOTS - 1) {slot = 0;} else {slot++;}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);...//類似更新ngx_cached_err_log_time.data等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_cached_http_log_iso8601.data = p3;ngx_cached_syslog_time.data = p4;ngx_unlock(&ngx_time_lock); }

    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,無法完成修改的原子性,這種將非原子性修改操作轉換為原子性修改操作的手法,值得借鑒。

    想要獲取最新技術文章?歡迎訂閱微信公眾號----軟件編程之路

    總結

    以上是生活随笔為你收集整理的深入剖析nginx时间缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。