4

在过去的几天里,我一直在研究 PHP 的一致哈希算法。我希望更好地了解一致性哈希实际上是如何工作的,这样我就可以在一些即将到来的项目中使用它。在我看来,Flexihash确实是唯一一个易于理解的纯 PHP 实现,所以我从中做了一些笔记。

我创建了一个自己的小算法,试图了解它是如何工作的,以及如何让它尽可能快地工作。我对我的算法与 Flexihash 相比的速度感到惊讶,这让我怀疑我的实现是否在某些方面存在缺陷,或者我可能没有掌握整个概念的关键部分。

下面列出了在 100 万个顺序键(0 到 1,000,000)的迭代中的速度差异。显示每个节点以显示实际散列到该特定节点的键的数量。

Flexihash:
 Time: 269 seconds
Speed: 3714 hashes/sec

 node1: 80729
 node2: 88390
 node3: 103623
 node4: 112338
 node5: 79893
 node6: 85377
 node7: 80966
 node8: 134462
 node9: 117046
node10: 117176

My implementation:
 Time: 3 seconds
Speed: 265589 hashes/sec

 node1: 100152
 node2: 100018
 node3: 99884
 node4: 99889
 node5: 100057
 node6: 100030
 node7: 99948
 node8: 99918
 node9: 100011
node10: 100093

这是我当前的哈希算法实现。

class Base_Hasher_Consistent
{
    protected $_nodes;

    public function __construct($nodes=NULL)
    {
        $this->_nodes = array();

        $node_count = count($nodes);
        $hashes_per_node = (int)(PHP_INT_MAX / $node_count);

        $old_hash_count = 0;

        foreach($nodes as $node){
            if(!($node == $nodes[$node_count-1])){
                $this->_nodes[] = array(
                    'name' => $node,
                    'begin' => $old_hash_count,
                    'end' => $old_hash_count + $hashes_per_node - 1
                );

                $old_hash_count += $hashes_per_node;
            }else{
                $this->_nodes[] = array(
                    'name' => $node,
                    'begin' => $old_hash_count,
                    'end' => PHP_INT_MAX
                );
            }
        }
    }

    public function hashToNode($data_key,$count=0)
    {
        $hash_code = (int)abs(crc32($data_key));

        foreach($this->_nodes as $node){
            if($hash_code >= $node['begin']){
                if($hash_code <= $node['end']){
                    return($node['name']);
                }
            }
        }
    }
}

我错过了什么,还是算法真的比 Flexihash 快?另外,我知道 Flexihash 支持查找多个节点,所以我不确定这是否与它有关。

我只是想要一些保证,我了解一致性哈希的工作原理,或者可能链接到一些真正解释它的文章。

谢谢!

4

2 回答 2

1

那么您想知道 crc32 是如何工作的,还是只是想知道如何编写一个好的“桶”实现?

您的存储桶实现看起来不错。如果你这样做,你可能会做得更快:

$bucket_index = floor($hash_code / $hashes_per_node);
return $this->_nodes[$bucket_index]['name'];

你写的“算法”只是制作了一些桶,并计算出 a应该$nodes放在哪些桶中。$data_key您使用的实际哈希算法是 crc32,如果您正在使用存储桶,它可能不是一个理想的算法。

如果你想知道 crc32 是如何工作的以及为什么哈希是一致的.. 在维基百科或其他东西上查找它。据我所知,不存在不一致的散列,因此所有散列算法在定义上都是一致的。

散列算法的一个特点是它可以为相似的 data_keys 生成非常不同的散列。crc32 也是如此,因为 crc32 旨在检测微小的变化。但它不能保证生成的哈希值“很好地传播”。由于您正在使用存储桶,因此您需要一种具有特定属性的散列算法,它可以在整个频谱范围内生成散列。对于 crc32,它可能只是巧合地工作得很好。我只会使用md5。

于 2011-06-11T13:13:20.280 回答
1

埃斯特尔 说:

我只是想要一些保证,我了解一致性哈希的工作原理,或者可能链接到一些真正解释它的文章。

这是让我编写 Flexihash 的优秀文章: http ://www.tomkleinpeter.com/2008/03/17/programmers-toolbox-part-3-consistent-hashing/

我已经很长时间没有看代码了——你的代码很可能要快得多。速度从来都不是我关心的问题。但也有可能你正在做一些完全不同的事情:)

另请参阅rs 在 GitHub 上的此提交,该提交声称通过使用二进制搜索将速度提高了 70 倍。如果有人能确认它是货物,我会合并它。

干杯! 保罗

于 2011-06-18T07:49:25.693 回答