using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace KetamaHash
{
public class KetamaNodeLocator
{
private SortedList<long, string> ketamaNodes = new SortedList<long, string>();
/// <summary>
/// 一致性哈希的实现
/// </summary>
/// <param name="nodes">实际节点</param>
/// <param name="nodeCopies">虚拟节点的个数</param>
public KetamaNodeLocator(List<string> nodes, int nodeCopies)
{
//对所有节点,生成nCopies个虚拟结点
foreach (string node in nodes)
{
//每四个虚拟结点为一组
for (int i = 0; i < nodeCopies / 4; i++)
{
//getKeyForNode方法为这组虚拟结点得到惟一名称
byte[] digest = HashAlgorithm.computeMd5(node + i);
//Md5是一个16字节长度的数组,将16字节的数组每四个字节一组,分别对应一个虚拟结点,这就是为什么上面把虚拟结点四个划分一组的原因
for (int h = 0; h < 4; h++)
{
long m = HashAlgorithm.hash(digest, h);
ketamaNodes[m] = node;
}
}
}
}
/// <summary>
/// 一致性哈希的实现
/// </summary>
/// <param name="nodes">实际节点</param>
public KetamaNodeLocator(List<string> nodes)
: this(nodes, 10)
{
}
/// <summary>
/// 查找Key值所在的节点
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string getNodes(string key)
{
byte[] digest = HashAlgorithm.computeMd5(key);
string rv = GetNodeForKey(HashAlgorithm.hash(digest, 0));
return rv;
}
/// <summary>
/// 通过Key值获取节点
/// </summary>
/// <param name="hash"></param>
private string GetNodeForKey(long hash)
{
string rv;
long key = hash;
//如果找到这个节点,直接取节点,返回
if (!ketamaNodes.ContainsKey(key))
{
//得到大于当前key的那个子Map,然后从中取出第一个key,就是大于且离它最近的那个key 说明详见: http://www.javaeye.com/topic/684087
var tailMap = from coll in ketamaNodes
where coll.Key > hash
select new { coll.Key };
if (tailMap == null || tailMap.Count() == 0)
key = ketamaNodes.FirstOrDefault().Key;
else
key = tailMap.FirstOrDefault().Key;
}
rv = ketamaNodes[key];
return rv;
}
}
}
一致性哈希算法
最新推荐文章于 2024-07-10 16:47:58 发布