PHP 一致性哈希环的简单实现

<?php

#inspired by 大型分布式网站设计与实践,及 https://github.com/Yikun/hashes/blob/master/virtual_consist_hash.py

/* 一致性哈希 
 * 1,哈希值应该是无符号整形,其值范围为0~2^32-1。
 * 2,哈希环节点顺时针分布。
 **/

$items = 1000000; #元素
$nodes = 5; #真实节点
$vnodes = 100; #虚拟节点

$ring = []; #哈希环节点数组
$hash2node = []; #哈希值映射到哈希环的数组

$nodes_stat = []; #哈希环分布统计数据

function _hash($value) {
	$k = md5(strval($value));
	return unpack("N", $k)[1]; // bigendian unsigned long 32bit
}

/* 返回key在哈希环中插入后的位置 */
function bisect_left($sorted_array, $key) {
	$left = 0; 
	$right = count($sorted_array) - 1;

    if ($key < $sorted_array[$left] || $key >= $sorted_array[$right]) {
    	/* 环起点位置 */
        return 0;
    } 

    while($right - $left > 1) {
        $middle = intval(($left + $right) / 2);
        if ($key <= $sorted_array[$middle]) {
            $right = $middle;
        } else {
            $left = $middle;
        }
    }

    return $right;
}

/*test bisect_left*/
//echo bisect_left([1,3,7,9,12,15], 10) , PHP_EOL;

echo "初始化哈希环",PHP_EOL;

echo sprintf("节点数 %d, 虚拟节点数 %d, 总节点数 %d, 储存键数量 %d\n", $nodes, $vnodes, $nodes*$vnodes, $items);

echo "初始化哈希节点统计数据",PHP_EOL;
for ($i = 0; $i < $nodes; $i++)
	$nodes_stat[$i] = 0;

for ($i = 0; $i < $nodes; $i++) {
	for ($j = 0; $j < $vnodes; $j++) {
		$h = _hash(strval($i) . strval($j));
		array_push($ring, $h);
		$hash2node[$h] = $i;
	}
}

echo "排序哈希环",PHP_EOL;
sort($ring);

echo "模拟键值分布",PHP_EOL;
# 模拟分布key到哈希环中
for ($k = 0; $k < $items; $k++) {
	$h = _hash($k);
	/* 找到这个键值在哈希环的节点位置 */
	$n = bisect_left($ring, $h) % ($nodes * $vnodes);
	//echo sprintf("element %d distributed at node %d with hash %d\n", $k, $n, $h);
	$nodes_stat[$hash2node[$ring[$n]]]++;
}

$avg = $items/$nodes;
$max = max($nodes_stat);
$min = min($nodes_stat);

echo "\n哈希节点统计数据\n===",PHP_EOL;

echo sprintf("avg: %d\n", $avg);
echo sprintf("max: %0.2f 最大值与平均值的差异(%0.2f%%)\n", $max, ($max-$avg)*100.0/$avg);
echo sprintf("min: %0.2f 最小值与平均值的差异(%0.2f%%)\n", $min, ($avg-$min)*100.0/$avg);

echo "节点哈希值分布情况\n===\n";
for ($i = 0; $i < $nodes; $i++)
	echo sprintf("node %d, numbers: %d\n", $i, $nodes_stat[$i]);


测试结果

初始化哈希环
节点数 5, 虚拟节点数 100, 总节点数 500, 储存键数量 1000000
初始化哈希节点统计数据
排序哈希环
模拟键值分布

哈希节点统计数据
===
avg: 200000
max: 210085.00 最大值与平均值的差异(5.04%)
min: 185845.00 最小值与平均值的差异(7.08%)
节点哈希值分布情况
===
node 0, numbers: 191739
node 1, numbers: 185845
node 2, numbers: 209369
node 3, numbers: 202962
node 4, numbers: 210085


引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值