循环哈希算法在给定静态目标集的情况下提供一致性。例如:
A
,B
和C
。x
hash(key, targets)
hash(x, [A,B,C])
时,x
总是哈希到A
似乎显而易见。我总是得到A
x
这一事实代表了我在使用循环哈希时所期望的一致性。但是,我们现在考虑如果我添加一个新的会发生什么
节点D
:
A
,B
,C
和D
x
重新应用到hash(x, [A,B,C,D])
A
我错过了什么,或者我只是运气不好?当您开始重新排序节点(例如hash(x, [B,A,D,C])
)或者在现有节点列表(例如hash(x, [A,AA,B,C,D])
)的中间插入新节点时,问题会进一步加剧。我看了一下圆形散列的学术方面,这种“缩放一致性”似乎并不是它的主要关注点之一。也许我只是使用错误类型的散列算法?
答案 0 :(得分:1)
您的问题有一个非常简单的解决方案。这是一个如何工作的例子。
让我们假设您有3个真实目标(即物理机器):A,B,C。然后你引入9个虚拟目标:1,2,3,4,5,6,7,8,9并建立静态映射从虚拟目标到真实目标,如下所示:
1, 2, 3 -> A
4, 5, 6 -> B
7, 8, 9 -> C
当您需要读取/写入某个键的值时,首先使用哈希函数将键映射到虚拟目标,然后使用上面显示的静态映射将虚拟目标映射到实际目标。一旦某个真实目标服务于多个虚拟目标,它应该将它们存储在单独的哈希映射中,因此真实目标B有三个单独的哈希映射,用于它所服务的三个虚拟目标。
现在我们要添加新的真实目标:D。我们首先重新平衡我们的静态映射,例如:像这样:
1, 2, 3 -> A
4, 5 -> B
7, 8 -> C
6, 9 -> D
然后,我们将虚拟目标6
的哈希地图从真实目标B
转移到新的真实目标D
。我们还将地图服务虚拟目标9
从C
转移到D
。此操作具有复杂性O(n)
,其中n
是传输的值的数量,因为每个真实目标在单独的哈希映射中为每个虚拟目标服务。
要实现良好的负载平衡,虚拟目标的数量应比估计最大可能的实际目标数量多几倍(例如10倍)。
换句话说,该解决方案的主要思想是使用散列函数将键映射到虚拟目标,其中虚拟目标的数量不会改变。然后使用静态映射将虚拟目标映射到真实目标,并且当添加或移除真实目标时,此静态映射会发生变化。
答案 1 :(得分:0)
当您扩展散列函数的允许输出范围时,可以理解某些输入将散列到不同的输出(否则没有扩展范围的点)。唯一的方法是,如果散列函数存储所有先前的结果(或者压缩的,可能有损的形式,如Bloom过滤器),那么它可以记住使用“旧”结果输入它之前见过。
答案 2 :(得分:0)
我无法以一致的方式解释您的整个问题,因此我会猜测您真正想要提出的问题并在此基础上回答。
假设问题:您有一堆对象(例如字符串)并且您拥有一堆计算机,并且您希望将每个对象分配给一台计算机,以便在计算机之间分配工作负载。当机器加入或离开机器池时,您不希望重新调整太多的对象到机器分配(“缩放一致性”)。
我认为你误解了你在哪里散列对象x
以映射池[A,B,C]
中的机器。我的理解是涉及三个中间步骤。
计算每个对象的哈希值。假设哈希输出空间像0到2 32 - 1的所有整数一样大。
为每台机器分配一个值(在相同的数字空间中),它在其生命周期内保持不变。您可能希望随机传播这些数字。
现在,我们将每个对象分配给最近的向上机器。这意味着如果对象的散列是x,那么它属于机器M,使得M的值是大于x的最小数。
示例:
我们有4个字符串对象,它们各自的哈希值在0到999范围内:abc = 314,def = 125,ghi = 802,jkl = 001。
我们有3台机器,有这些数字:X = 010,Y = 357,Z = 768。
对象abc = 314属于哪台机器?向上计数,最近的机器是Y = 357 对象ghi = 802属于哪台机器?向上计数,最近的机器是X = 010。
答案 3 :(得分:0)
好的,我想我明白了。
我最终保持哈希算法简单,并使用“校验和”(各种类型)来确保x始终键入同一目标。当添加新目标并且系统重新平衡时,我只是通知所有现有目标有关重新平衡的信息。这样,如果x哈希到目标它不再哈希,那么目标就可以委托给正确的目标。
感谢您的所有回复,如果不是因为您提供的清晰度,我可能没有找到这个解决方案。
干杯,
乔恩