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的对齐问题;