1.Nginx中的容器
1.数组
2.链表
3.队列
4.哈希表
5.红黑树
6.基数树
2.数组
确切来说是“动态数组”
多块连续内存,每块连续内存中可以存放许多元素.
/home/muten/module/nginx-1.13.7/src/core/ngx_array.h
typedef struct {
void *elts;
ngx_uint_t nelts;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_array_t;
3.链表
确切来说是“动态单向链表”
/home/muten/module/nginx-1.13.7/src/core/ngx_list.h
typedef struct {
ngx_list_part_t *last;
ngx_list_part_t part;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_list_t;
4.队列
确切来说是“双向链表”
名字很有误导性哈~~~这其实是一个双向链表,不知道为啥起queue这个名字!!非常不准确!misleading!!!
如果我能给一个名字的话,我会改成double_linked_list_t,一看便知!
/home/muten/module/nginx-1.13.7/src/core/ngx_queue.h
typedef struct ngx_queue_s ngx_queue_t;
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
5.哈希表
/home/muten/module/nginx-1.13.7/src/core/ngx_hash.h
typedef struct {
void *value;
u_short len;
u_char name[1];
} ngx_hash_elt_t;
typedef struct {
ngx_hash_elt_t **buckets;
ngx_uint_t size;
} ngx_hash_t;
(1)ngx中的hash表与平常我们知道的哈希表的不同(应用场景不同):
ngx_hash通常用于静态不变的内容,在运行的过程中,ngx_hash一般不会出现插入或者删除;
一般nginx刚启动的时候就能确定这个容器里共有多少个元素,所以一般使用ngx_hash的模块
一般会暴露出bucket_size和max_size两个参数,
max_size仅仅控制了最大的bucket_size的个数,而不是实际上bucket_size的个数,
比如说max_size可能配置了100,但实际上只有10个元素使用了hash表,这个max_size
的意义是限制最大化的使用(限制内存的占用量).
(2)ngx中使用哈希表模块的特点
variables(stream/http):变量在模块编译的时候就已经定义清楚了;
map(stream/http):map在模块编译的时候就已经定义清楚了;
反向代理中需要对许多定义好的header做哈希,提升访问性能;
refer,ssi,srcache_filter也是一样的道理,对它们做哈希,可以提升访问性能,访问复杂度是O(1);
(3)哈希表中的bucket size
在bucket size往往有默认值,在我们的Nginx配置文档中的cache line会和这个值关联,
这个实际上影响了如何配置这个bucket_size,现在主流的CPU实际上是由L1,L2,L3缓存的,
实际上去主存(内存)的数据的时候并不是像大家想象的那样按照64位或者32位那样去取,现在主流CPU
一次性从主存中取的字节数是一个cpu cache line,现在是64字节,为什么哈希表要向64字节对齐呢?
因为假设每一个hash表的bucket是59字节,如果我们是紧密地排列在一起的,取第一个哈希表元素只需要
访问一次,还多取了一个字节,但是取第二个元素的时候,就需要访问主存两次,包括第一个64字节中的
最后一个字节和第二个64字节中的58个字节,为了避免这种取两次的问题,Nginx在代码中自动向上对齐,
所以在配置bucket_size的时候要注意两个问题:
一.如果我们配置的不是cpu cache line,如果配置70字节,Nginx会自动向上给我们对齐,给每个元素
分配128字节;
二.如果有可能的话,尽量不要超过64字节,以减少CPU访问每个哈希表元素的次数.
使用Nginx中的ngx_hash_t的时候要注意两点:
(1)ngx_hash_t只为静态的不变的内容服务;
(2)ngx_hash_t的bucket size需要考虑cpu cache line对齐问题.

6.红黑树
/home/muten/module/nginx-1.13.7/src/core/ngx_rbtree.h
struct ngx_rbtree_node_s {
ngx_rbtree_key_t key;
ngx_rbtree_node_t *left;
ngx_rbtree_node_t *right;
ngx_rbtree_node_t *parent;
u_char color;
u_char data;
};
typedef struct ngx_rbtree_s ngx_rbtree_t;
struct ngx_rbtree_s {
ngx_rbtree_node_t *root; // 根节点
ngx_rbtree_node_t *sentinel; // 哨兵节点
ngx_rbtree_insert_pt insert;
};
红黑树:
(1)是个查找二叉树(有序的);
(2)高度差不会太大.
红黑树的特点:
(1)高度不会超过2log(n);
(2)增删改查的算法复杂度O(log(n));
(3)遍历复杂度O(n);
Nginx中使用红黑树的模块或功能点:

7.基数树
/home/muten/module/nginx-1.13.7/src/core/ngx_radix_tree.h
struct ngx_radix_node_s {
ngx_radix_node_t *right;
ngx_radix_node_t *left;
ngx_radix_node_t *parent;
uintptr_t value;
};
typedef struct {
ngx_radix_node_t *root;
ngx_pool_t *pool;
ngx_radix_node_t *free;
char *start;
size_t size;
} ngx_radix_tree_t;
是自平衡排序二叉树的一种,只不过key只能是整型,geo模块在使用基数树,其他模块使用的并不多.
基数树对比红黑树:
基数树不需要管是否平衡,插入删除效率远高于红黑树.
本文介绍了Nginx中使用的多种数据结构,包括动态数组、动态单向链表、双向链表(队列)、哈希表、红黑树及基数树等,并详细探讨了这些数据结构的应用场景与特点。
235

被折叠的 条评论
为什么被折叠?



