using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Console
{
class Program
{
static void Main(string[] args)
{
var ketAmaNodeLocator = new KetAmaHashingNodeLocator(new List<string> { "192.168.100.124:1442", "192.168.100.124:4555", "192.168.100.125:4444", "192.168.100.124:4477" });
for (var i = 0; i < 100; i++)
{
System.Console.WriteLine(ketAmaNodeLocator.GetPrimary($"154.244.100.{i}"));
}
System.Console.ReadLine();
}
/// <summary>
/// KetAmaHashingNodeLocator
/// </summary>
public class KetAmaHashingNodeLocator
{
/// <summary>
/// _ketAmaNodes
/// </summary>
private readonly SortedList<long, string> _ketAmaNodes;
/// <summary>
/// numReps
/// </summary>
private readonly int _numReps = 160;
/// <summary>
/// KetAmaHashingNodeLocator
/// </summary>
/// <param name="nodes">nodes</param>
public KetAmaHashingNodeLocator(IEnumerable<string> nodes/*,int nodeCopies*/)
{
_ketAmaNodes = new SortedList<long, string>();
//numReps = nodeCopies;
//对所有节点,生成nCopies个虚拟结点
foreach (var node in nodes)
{
//每四个虚拟结点为一组
for (var i = 0; i < _numReps / 4; i++)
{
//getKeyForNode方法为这组虚拟结点得到惟一名称
var digest = HashAlgorithm.ComputeMd5(node + i);
/** Md5是一个16字节长度的数组,将16字节的数组每四个字节一组,分别对应一个虚拟结点,这就是为什么上面把虚拟结点四个划分一组的原因*/
for (var h = 0; h < 4; h++)
{
var m = HashAlgorithm.Hash(digest, h);
_ketAmaNodes[m] = node;
}
}
}
}
/// <summary>
/// GetPrimary
/// </summary>
/// <param name="k">k</param>
/// <returns>string</returns>
public string GetPrimary(string k)
{
var digest = HashAlgorithm.ComputeMd5(k);
var rv = GetNodeForKey(HashAlgorithm.Hash(digest, 0));
return rv;
}
/// <summary>
/// GetNodeForKey
/// </summary>
/// <param name="hash">hash</param>
/// <returns>string</returns>
private string GetNodeForKey(long hash)
{
var key = hash;
//如果找到这个节点,直接取节点,返回
if (!_ketAmaNodes.ContainsKey(key))
{
var tailMap = (from coll in _ketAmaNodes
where coll.Key > hash
select new { coll.Key }).ToList();
key = !tailMap.Any() ? _ketAmaNodes.FirstOrDefault().Key : tailMap.First().Key;
}
var rv = _ketAmaNodes[key];
return rv;
}
}
/// <summary>
/// HashAlgorithm
/// </summary>
public class HashAlgorithm
{
/// <summary>
/// Hash
/// </summary>
/// <param name="digest">digest</param>
/// <param name="nTime">nTime</param>
/// <returns>long</returns>
public static long Hash(byte[] digest, int nTime)
{
var rv = ((long)(digest[3 + nTime * 4] & 0xFF) << 24)
| ((long)(digest[2 + nTime * 4] & 0xFF) << 16)
| ((long)(digest[1 + nTime * 4] & 0xFF) << 8)
| ((long)digest[0 + nTime * 4] & 0xFF);
return rv & 0xffffffffL; /* Truncate to 32-bits */
}
/// <summary>
/// Get the md5 of the given key.
/// </summary>
/// <param name="k">key</param>
/// <returns>keyBytes</returns>
public static byte[] ComputeMd5(string k)
{
MD5 md5 = new MD5CryptoServiceProvider();
var keyBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(k));
md5.Clear();
//md5.update(keyBytes);
//return md5.digest();
return keyBytes;
}
}
}
}
参考github:https://github.com/jinyuttt/LoadBalanceHash