讨论问题:
1、hash函数与冲突处理。
2、hash表
3、布隆过滤器
4、分布式一致性hash
hash的负载因子:hash已经存储的元素的个数。
hash冲突:不同的key值利用hash函数计算出的hash值对应的容器索引。负载因子越小冲突的概率越小,负载因子越大冲突的概率越大。
hash聚集:近似的key值的hash值也近似。解决冲突的时候,可能会导致严重的hash聚集现象。
冲突解决方式:
1、链表法:
a、头插法(一般用于数据库,数据库因为认为刚刚插入的元素最近会更加容易访问到)
b、尾插法
c、当链表过长可以把链表转化成红黑树或者avl树。
2、开放地址法:
a、、、、...、等探查下去直到探查完成。
b、、、、... 等探查下去知道探查完成。
c、双重哈希(避免hash聚集现象):
数学原理:https://www.cnblogs.com/organic/p/6283476.html
布隆过滤器:
用n个哈希函数来对key做运算得到n个位置分别映射到位图上(位图是个数组,元素只有0或者1两个状态)。布隆过滤器只能判断一个key可能存在或者一定不存在。用n个哈希函数对key做运算后判断n个对应位置是否存在0状态,如果存在就是key一定不存在,否则可能存在。
如何使用布隆过滤器:
1、要预估key的数量n
2、误差概率p。
3、位图元素个数m。
4、哈希函数的个数k。
公式:
n = ceil( m / ( -k / log(1 - exp( log(p) / k ))))
p = pow(1 - exp(-k / (m/n)), k)
m = ceil((n * log(p)) / log(1 / pow(2, log(2))))
k = round((m / n) * log(2))
数学原理:http://hur.st/bloomfilter
使用布隆过滤器的时候先确认n和p然后通过上面的网址计算出合适的m和k。
哈希函数的分布性与质数相关,在17,31,101中31的分布性最好。
哈希函数:murmurhash1, murmurhash2,murmurhash3、siphash(redis6.0当中使用),cityhash。siphash主要解决字符串接近的强随机分布性。
测试地址:https://github.com/aappleby/smhasher
k个哈希函数的生成:
#define MIX_UINT64(v) ((uint32_t)((v>>32)^(v))
uint64_t hash1 = MurmurHash2_x64(key, len, seed);
uint64_t hash2 = MurmurHash2_x64(key, len, MIX_UINT64(hash1));
for(i = 0; i < k; i++)
{
Pos[i] = (hash1 + i*hash2) % m;
}
布隆过滤器主要解决的场景是可以过滤大多数不存在的访问,但是有一个可控的错误概率。可能访问1000次不同不存在的数据可能有1次的概率需要真正的访问,大概率排查不存在的数据。这个可以减少不存在数据的真正访问次数,提高效率。
分布式一致性hash:
在一个分布式数据缓存的集群中,有n个节点作为缓存服务器。用来算出n个节点的hash值cache_hash_n,它们全部落到0到的圆环中。ip是节点的ip地址,port是节点的端口号。之后用来算出需要缓存的数据的key的hash值data_hash,然后从data_hash开始找下一个最近的cache_hash_n,找到后就把数据存储到cache_hash_n对应的缓存服务器中。
分布式一致性hash主要解决分布式缓存的数据均匀分布与横向扩展集群的问题:
在最开始的分布式数据缓存集群有n个节点,通过hash来确定数据缓存在哪个节点上。随着访问的数据越来越多每个节点的压力越来越大,那么就需要扩展节点。由于hash的计算公式是,那么扩展节点后增加了k个节点,所以公式变成了这个时候hash值就乱套了。
分布式一致性hash的问题:
1、会造成部分数据存储的影响:
(通过数据迁移来解决 http://github.com/metang326/consistent_hashing_cpp)
还是上面的例子,如果有n个节点,那么增加1个节点后,新的节点的hash值new_hash会落到圆环的某个位置,假设新节点的前后节点的hash值为pre_hash和next_hash,原先落在pre_hash与next_hash之间的数都是存储到next_hash对应的节点上的,那么现在添加了new_hash后pre_hash与new_hash之间的数据就存储到new_hash上。
2、hash偏移,数据分布不均匀。(通过增加虚拟节点解决)
一上面的例子为例,由于n个节点的结点数量太少,所以在圆环上的节点分布不均匀,从而导致数据分布不均匀。那么解决的方案是,为每个节点添加虚拟节点,虚拟节点的hash值为。当节点足够多的时候,节点就能均匀分布在圆环上。