Nginx容器是許多nginx高級功能的實現基礎,即使我們不需要編輯第三方模塊或者查看nginx的源代碼;但我們需要變更我們的nginx配置文件,以達到最大化的性能;
我們也需要了解Nginx容器是怎么樣使用的;下面我們來看下nginx最主要的內部容器;
(1):首先就是數組,也就是ngx_array_t;這里的數組和我們平常所理解的數組還是有所不同的;它是多塊連續內存,其中每一塊連續內存中可以存放很多元素;
(2):而鏈表就是ngx_list_t;
(3):對列是ngx_queue_t;
這些結構體它們所實現的功能是類似的;只不過它們的操作方法會有所不同;
而nginx中最重要的兩個數據結構一個是哈希表,一個是紅黑樹;基數數是自平衡排序二叉樹中的一種;只不過它的key只能是整型;像geo等模塊在使用基數數;其它使用基數數的場景並不多;
(4):哈希表
我們先重點來看下哈希表使用的時候有哪些注意事項;
那么nginx的哈希表跟我們正常所見到的哈希表還是有所不同的;
我們只是從它的實現層面來看;和正常的哈希表是相似的;就是每一個元素會順序的放到一塊連續的內存當中;每一個元素它的key同樣是通過哈希函數來映射的;
如下:
這是一段存放哈希表內容的連續內存;那么如下的一個結構體就是哈希表的描述;
每一段大小的內容如下:
它的name就是它的key;它的value是一個指針;指向我們實際的內容:
一個key和另外一個key是連續放在一起的;這和大部分的哈希表是一樣的;
完整圖示如下:
哈希表與通常的哈希表有哪里不同尼?
它的應用場景不同,它僅僅應用於靜態不變的內容,也就是說我們在運行過程中,這個哈希表通常是不會出現插入和刪除的;
也就是說我們nginx剛啟動的時候,就可以已經確定這個哈希表中一共有多少個元素,所以當使用哈希表的這些模塊,通常會暴漏出來一個叫max_size和bucket size的參數 ,這兩個參數給我們的時候,我們的max_size僅僅控制了最大的哈希表bucket的個數;而不是實際上bucket的個數;比如說我們的max size配置可能是100;但是實際上只有十個元素使用了哈希表;這個實際上它與實際的bucket size 是不符的;但max size這個意義在於我可以限制最大快的使用;因為這里消耗了我們的內存;
我們再來看一看所有使用哈希表的模塊,有些什么樣的特點?
比如說在http和stream的核心模塊里,它們所有的變量使用了哈希表,因為變量在我們模塊編譯的時候就已經定義清楚了;
還有像map,還有像反向代理;因為反向代理中我們需要對很多header在配置文件中定義好header做哈希來提升它的訪問性能;
referer和ssi也是同樣的道理;因為哈希表在訪問的時候它是一個O(1)的復雜度,速度非常的快;
而哈希表中我們會發現有一個叫bucket size;這個bucket size往往會有些默認值;這個默認值有時我們會發現nginx的配置文檔中說是cpu_cache_line會對齊到這樣一個值;這是什么意思尼?這實際上是影響了我們怎么樣去配置bucket size;也就是說現在的主流的CPU,它實際上是有了L1,L2,L3緩存的;它在取我們內存上的數據時,並不是按照大家所想象的那樣,按照所有的64位,或者32位這樣去取,現在主流的CPU一次從內存上取數據的字節數就是cpu_cache_line,現在是64字節的;
而為什么哈希表要向64字節對齊尼?假設我們現在每一個哈希表的bucket是59字節,如果我們是緊密的排列在一起的;那么你取第一個哈希表元素;只需要訪問一次,還多取了一個字節,但你取第二個元素的時候,你實際上需要訪問組成兩次;包括第一個64字節當中的最后一個字節,以及第二個單元里面的58個字節;所以為了避免這種取兩次的問題,nginx在它的代碼中自動的向上對齊了,所以我們在配置bucket size的時候,需要注意兩個問題,如果我們配置的不是cpu_cache_line;而是70字節;它就會向上給我們分配每個元素是128字節;如果有可能的話,盡量不要超過64字節,以減少CPU來訪問我們哈希表的次數;
總結:以上我們介紹了哈希表的使用,實際上還有更多的第三方模塊都在使用哈希表,注意:哈希表只為靜態的不變的內容服務,哈希表的bucket size需要考慮cpu_cache_line的對齊問題;