编译自:
http://nginx.org/en/docs/hash.html
nginx 为了快速处理静态数据集,比如:server names、map 指令的参数值、MIME 类型、请求首部字符串的名字等,采用了 hash 表来处理。nginx 在启动和重新加载配置时,会选择可能的最小的 hash 表大小,这是为了在存储拥有相同 hash 值的 key 的时候,使得 bucket size 不超过配置的上限值。
hash 表的大小以 bucket 来表示。在 hash 表大小超过 hash max size 参数的设置之前,bucket 能够自动调整大小。大多数 hash 值有对应的配置指令,比如对于 server name hash,对应的指令为:server_names_hash_max_size
和 server_names_hash_bucket_size
.
- server_names_hash_max_size 表示支持的 server name 总数;
- server_names_hash_bucket_size 表示 server name 的字符串长度上限值
可参考:server_names_hash_max_size
hash bucket size 的大小需要对齐 CPU 的 cache line size,它必须是 cache line size 的整数倍。这样设置,能够使现代处理器在进行 key 检索时减少内存访问次数从而提升检索速度。
如果 hash bucket size 等于 cache line size,那么在进行 key 检索时所需要的访问内存次数最多需要 2 次。第一次,是计算 bucket address;第二次,是为了在 bucket 中进行 key 检索。因此,如果 nginx 给出消息要求增加 hash max size 或者 hash bucket size 时,应该首先增加 hash max size 的值。
为理解本文,首先要理解两个概念:
- hash table
- cache line size
hash table,也叫哈希表,散列表,是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做 hash 表。
给定表 M,存在函数f(key),对任意给定的关键码值 key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表 M 为哈希(Hash)表,函数f(key)为 hash 函数。
一个L1 DATA CACHE 相当于一块小的内存,我们假设它为16K大,它会与一般物理内存交互。 它和内存交互一般一次传输16个字节(或32个字节),也就是:
CACHE 字节0-15一次写到/读取物理内存 ,字节16-31一次写到/读取物理内存..这些在 CACHE 和物理内存之间一次被传输的字节被称为 cache line size。
cache 写到物理内存的位置不是任意的,我们假定内存为64K,那么cache地址0的数值只能和物理内存的地址0、 16K、32K交互;cache地址1的数值只能和物理内存的地址1、16K+1、32K+1交互;cache地址16K-1的数值只能和物理内存的地址16K-1、16K+16K-1、32K+16K-1交互。
假设对象A的一个字段长为16个字节,如果它放在物理地址 0-15,那么 CPU 只需要 cache 的第一个 cache line 交互一次,就可以完整读取对象 A 的 16 字节长的字段,
如果放在物理地址 8-23,就必须将第一个和第二个 cache line 都读入,才能获得这个字段的信息,显然这样速度慢,所以一般字段需要 cache line 对齐,在这里就是16个字节对齐。
版权信息:
本文编译自 nginx.org 的部分,遵循其原来的 licence 声明: 2-clause BSD-like license