1.前言
在处理与交换机MAC学习相关的问题时,留意到Marvell芯片在MAC学习过程中使用的Hash算法是Cuckoo Hash,而哈希冲突也是可能影响MAC学习正确率的因素之一。
对于数据中心交换机,需要满足高速流量下的转发和二层学习,维护大规格的MAC表,而哈希算法不计其数,为什么选布谷鸟?

2.布谷鸟哈希
布谷鸟哈希最早由Rasmus Pagh和Flemming Friche Rodler在2001年一个会议提出的。
https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf
2.1 什么是布谷鸟哈希
布谷鸟哈希(Cuckoo Hashing)是一种哈希表的实现方式,它使用两个互相独立的哈希函数,初始时将所有数据随机地插入两个哈希表中的一个。当插入新数据时,先根据两个哈希函数找到在哪个表中存储该数据,如果该位置已有数据,则将原来的数据插入另一个哈希表中,直到能够成功地插入数据为止。
布谷鸟哈希中的概念:
- 桶:对应一个数组,每个桶可以存储多个key
- 桶数组:对应多个桶,可以理解为一个存key的二维数组
2.1.1 Why cuckoo?
布谷鸟(Cuckoo)以其独特的行为而闻名:它们不自己筑巢,而是将蛋产在其他鸟类的巢中,并且布谷鸟的雏鸟通常会比寄主鸟的雏鸟更早孵化。一旦孵化,布谷鸟的雏鸟会将其他未孵化的蛋推出巢外,从而确保自己能独占养父母的食物供应。
这种行为启发了布谷鸟散列(Cuckoo Hashing)的设计理念。在布谷鸟哈希中,当新元素尝试插入时,如果该位置已被占用,则会"踢走"原有元素,并将新元素放置于此。被踢走的元素会被移动到其备用位置,如果备用位置也被占用,则继续这一过程,直到找到空闲位置为止。如果连续"踢走"元素的次数达到了某个预设的上限,就认为散列表已满,并触发rehashing的过程。
这种机制保证了每个元素都有两个可能的位置,从而有效地解决了冲突问题,并且提供了较好的性能表现。
2.1.2 Why choose cuckoo hash?
1.如果使用适当的哈希函数和装载因子,布谷鸟哈希的查找、插入和删除操作都可以在常数时间内完成,可以提供非常高效的性能。此外,布谷鸟哈希需要的空间不比标准哈希表多很多,因为它可以使用更紧凑的存储结构来存储数据。
2.布谷鸟哈希在处理哈希冲突时具有鲁棒性,因为它可以通过插入和重新哈希等简单的操作来解决冲突。这意味着即使在负载非常高的情况下,布谷鸟哈希也可以提供稳定的性能。
3.单桶多函数的布谷鸟哈希,使用开放式地址法处理冲突,不是通过线性寻找新的位置,而是使用额外哈希函数来寻找。
2.2 布谷鸟哈希基础

一个基本的布谷鸟哈希表由一个桶数组组成,每个插入项都有由哈希函数h1(x)和h2(x)确定的两个候选桶。
查找过程会检查两个桶是否任意一个桶包含此项。图(a)将元素 x 插入到一个8个桶的哈希表中的示例,其中 x 可以放置在桶2或6中。如果x的两个桶中的任何一个是空的,则算法将x插入到该空桶中,插入完成。如果两个桶都没有空间,如例所示,项会选择一个候选桶 (例如桶 6), 踢出去现有的项 (在本例中为"a") 并将此被踢出项重新插入到它的备用位置。
在我们的例子中,重新放置"a"触发了另一个重置,将现有的项"c"从桶4踢到桶1。这个过程可能会重复,直到找到一个空桶,如图(b)所示或直到达到最大位移次数(例如在我们的实现中为500次)。如果没有找到空桶则认为此哈希表太满,无法插入。虽然布谷鸟哈希可能执行一系列重置,但其均摊插入时间为O(1)。
3.布谷鸟过滤器算法
当需要检查元素是否存在于集合中时,比如缓存穿透、爬虫重复 URL 检测、唯一昵称判断等。
如果对时间和空间效率的要求不是非常高,可以选择以下方法:
- 构建数据库表,并使用唯一索引来防止重复插入。
- 利用Redis中的
Set或类似Hash的数据结构。
面对海量数据且能够接受一定比例的误报(误阳)时,可以采用如下方案:
- 使用布隆过滤器进行高效的成员资格测试。需要注意的是,传统布隆过滤器不支持从集合中删除元素。
- 采用改进型布隆过滤器,如Counting Bloom Filter,它支持元素删除,但会增加大约三到四倍的空间开销。
除此之外,还可以考虑使用布谷鸟过滤器,它不仅适用于大规模数据的查重需求,还支持从过滤器中删除元素。
3.1 布隆过滤器
在介绍布谷鸟过滤器前,不得不花些篇幅先介绍一下经典的布隆过滤器。
在许多网络系统中,布隆过滤器被用于高速的集合成员测试。它们允许一小部分误报结果,但具有非常好的空间效率。
布隆过滤器在缓存穿透中的应用:把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端
布隆过滤器举例
bitmap原始数值全都是0,当一个数据存进来的时候,用三个Hash函数分别计算三次Hash值,并且将bitmap对应的位置设置为1。
如下图中,如果一个数据请求过来,用三个Hash函数计算Hash值,如果是同一个数据的话,就会映射到相同的索引,那么就可以判断这个数据之前存储过;如果新的数据映射的三个位置,有一个匹配不上,假如映射到1,3,7位,由于7位是0,也就是这个数据之前并没有加入进数据库,所以直接返回。
根据定义,布隆过滤器可以检查值是 "可能在集合中" 还是 "绝对不在集合中"。"可能" 表示有一定的概率,也就是说可能存在一定为误判率,布隆过滤器可能误判。

布隆过滤器还有增强版(Counting Bloom Filter),这个过滤器的思路是将布隆过滤器的bitmap更换成数组,当数组某位置被映射一次时就+1,当删除时就-1,这样就避免了普通布隆过滤器删除数据后需要重新计算其余数据包Hash的问题,但是依旧没法避免误判。
3.2 布谷鸟过滤器
布谷鸟过滤器(cuckoo filter),它可以替代布隆过滤器(下一节简单介绍)进行近似集合成员测试。布谷鸟过滤器在时间和空间方面显著优于之前为支持删除操作而扩展的布隆过滤器数据结构。布谷鸟哈希会存储整个元素,而布谷鸟过滤器中只会存储元素的指纹信息
- 1.支持动态的新增和删除元素。
- 2.提供了比传统布隆过滤器更高的查找性能,即使在接近满的情况下(比如空间利用率达到 95% 的时候)。
- 3.比诸如商过滤器(quotient filter,另一种过滤器)之类的替代方案更容易实现。
- 4.如果要求错误率小于3%,那么在许多实际应用中,它比布隆过滤器占用的空间更小。
3.2.1 插入
标准的布谷鸟 hash,将新项插入到现有哈希表中需要一些方法来访问原始现有项,以便确定在需要时将它们迁移到的位置,为新项腾出空间。但布谷鸟过滤器只存储指纹,因此没有办法恢复和重新哈希原始键以找到它们的替代位置。为了突破这个限制,我们利用一种称为部分键布谷鸟哈希的方法来根据其指纹导出一个项的备用位置。
h1(x) = hash(x), h2(x) = h1(x) ⊕ hash(x's fingerprint)
h1(x)也可以通过h2(x)和同一公式中的指纹来计算。 换句话说,在桶i中迁走一个键(不管i是h1(x)或h2(x)),我们直接用当前桶的索引i和存储在桶中的指纹计算它的备用桶j:
h1(x) = h2(x) ⊕ hash(fingerprint)
h2(x) = h1(x) ⊕ hash(fingerprint)
所以踢出时只需要使用指纹和其中一个位置,就可以求到另一个位置的位置了。
java
f = fingerprint(x);
i1 = hash(x);
i2 = i1 ⊕ hash(f);
if bucket[i1] or bucket[i2] has an empty entry then
add f to that bucket;
return Done;
// must relocate existing items;
i = randomly pick i1 or i2;
for n = 0; n < MaxNumKicks; n++ do
randomly select an entry e from bucket[i];
swap f and the fingerprint stored in entry e;
i = i ⊕ hash(f);
if bucket[i] has an empty entry then
add f to bucket[i];
return Done;
// Hashtable is considered full;
return Failure;
3.2.2 查找
给定一个项x,算法首先根据公式 (1)计算x的指纹和两个候选桶。然后读取这两个桶:如果两个桶中的任何现有指纹匹配,则布谷鸟过滤器返回true,否则过滤器返回false。
c
f = fingerprint(x);
i1 = hash(x);
i2 = i1 ⊕ hash(f);
if bucket[i1] or bucket[i2] has f then
return True;
return False;
3.2.3 删除
布谷鸟过滤器的删除过程更简单。它检查给定项的两个候选桶;如果任何桶中的指纹匹配,则从该桶中删除匹配指纹的一份副本。
c
f = fingerprint(x);
i1 = hash(x);
i2 = i1 ⊕ hash(f);
if bucket[i1] or bucket[i2] has f then
remove a copy of f from this bucket;
return True;
return False;
请注意,要安全地删除项x,必须事先插入它。否则删除非插入项可能会无意中删除碰巧共享相同指纹的真实、不同的项。这一要求也适用于所有其他支持删除的过滤器。
参考资料 请解释一下什么是布谷鸟哈希,并说明在什么情况下布谷鸟哈希优于标准哈希表。 | 壹梵在线网络服务 一凡在线