一期二班 - 吴水金 - 第五课作业
发布于: 2020 年 11 月 04 日
一致性 hash 算法 C#实现
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Hash
{
class Program
{
static void Main(string[] args)
{
ConsistencyHash consistencyHash = new ConsistencyHash();
consistencyHash.init();
int _0 = 0;
int _1 = 0;
int _2 = 0;
int _3 = 0;
int _4 = 0;
int _5 = 0;
int _6 = 0;
int _7 = 0;
int _8 = 0;
int _9 = 0;
Random ran = new Random();
long startTicks = DateTime.Now.Ticks;
for (int i = 0; i < 1000000; i++)
{
// 随便取一个数的md5
byte[] ranNum = consistencyHash.computeMd5(i.ToString());
// 分配到随即的hash环上面
long key = consistencyHash.hash(ranNum, 2);
if (consistencyHash.getNodeInfo(key).Equals("192.168.0.0-服务器0"))
{
_0++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.1-服务器1"))
{
_1++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.2-服务器2"))
{
_2++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.3-服务器3"))
{
_3++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.4-服务器4"))
{
_4++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.5-服务器5"))
{
_5++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.6-服务器6"))
{
_6++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.7-服务器7"))
{
_7++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.8-服务器8"))
{
_8++;
}
else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.9-服务器9"))
{
_9++;
}
else
{
Console.WriteLine("error");
}
}
// 输出每台服务器负载情况
Console.WriteLine("server_0 = " + _0);
Console.WriteLine("server_1 = " + _1);
Console.WriteLine("server_2 = " + _2);
Console.WriteLine("server_3 = " + _3);
Console.WriteLine("server_4 = " + _4);
Console.WriteLine("server_5 = " + _5);
Console.WriteLine("server_6 = " + _6);
Console.WriteLine("server_7 = " + _7);
Console.WriteLine("server_8 = " + _8);
Console.WriteLine("server_9 = " + _9);
Console.WriteLine("时长:{0}ms", DateTime.Now.Ticks - startTicks);
Console.Read();
}
}
public class ConsistencyHash
{
// 环的所有节点
private SortedList<long, object> allNodes = null;
// 真实服务器节点
private List<Object> realNodes = new List<object>();
// 设置虚拟节点数目
// 太多会影响性能,太少又会导致负载不均衡,一般说来,经验值是150,
// 当然根据集群规模和负载均衡的精度需求,这个值应该根据具体情况具体对待。
private int VIRTUAL_NODE_COUNT = 150;
public void init()
{
// 加入10台真实服务器
realNodes.Add("192.168.0.0-服务器0");
realNodes.Add("192.168.0.1-服务器1");
realNodes.Add("192.168.0.2-服务器2");
realNodes.Add("192.168.0.3-服务器3");
realNodes.Add("192.168.0.4-服务器4");
realNodes.Add("192.168.0.5-服务器5");
realNodes.Add("192.168.0.6-服务器6");
realNodes.Add("192.168.0.7-服务器7");
realNodes.Add("192.168.0.8-服务器8");
realNodes.Add("192.168.0.9-服务器9");
// 构造每台真实服务器的虚拟节点
allNodes = new SortedList<long, object>();
for(int i = 0; i < realNodes.Count; i++)
{
object node = realNodes[i];
for(int j = 0; j < VIRTUAL_NODE_COUNT; j++)
{
var cpm = "NODE-" + i + "-VIRTUAL-" + j;
var md5 = computeMd5(cpm);
var hashVal = hash(md5, 0);//使用MD5值计算hash值
allNodes.Add(hashVal, node);
//Console.WriteLine(string.Format("{0}\t{1}", cpm, hashVal));
}
}
}
/**
* 计算MD5值
*/
public byte[] computeMd5(String k)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] keyBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(k));
md5.Clear();
//md5.update(keyBytes);
//return md5.digest();
return keyBytes;
}
/**
* 根据2^32把节点分布到环上面
*
* @param digest
* @param nTime
* @return
*/
public long hash(byte[] digest, int nTime)
{
long rv = ((long)(digest[3 + nTime * 4] & 0xFF) << 24)
| ((long)(digest[2 + nTime * 4] & 0xFF) << 16)
| ((long)(digest[1 + nTime * 4] & 0xFF) << 8)
| (digest[0 + nTime * 4] & 0xFF);
return rv & 0xffffffffL; /* Truncate to 32-bits */
}
/**
* 根据key的hash值取得服务器节点信息
*
* @param hash
* @return
*/
public Object getNodeInfo(long hash)
{
string rv;
long key = hash;
//如果找到这个节点,直接取节点,返回
if (!allNodes.ContainsKey(key))
{
//得到大于当前key的那个子Map,然后从中取出第一个key,就是大于且离它最近的那个key
var tailMap = from coll in allNodes
where coll.Key > hash
select new {coll.Key};
if (tailMap == null || tailMap.Count() == 0)
key = allNodes.FirstOrDefault().Key;
else
key = tailMap.FirstOrDefault().Key;
}
return allNodes[key];
}
}
}
复制代码
10 台服务器 100 万 KV 数据的节点分布情况:
server_0 = 100547
server_1 = 105269
server_2 = 105279
server_3 = 107685
server_4 = 88297
server_5 = 93284
server_6 = 104584
server_7 = 110483
server_8 = 101650
server_9 = 82922
耗时:2333570000 毫秒
划线
评论
复制
发布于: 2020 年 11 月 04 日阅读数: 29
版权声明: 本文为 InfoQ 作者【吴水金】的原创文章。
原文链接:【http://xie.infoq.cn/article/7e2eab5bc30bca34130cf0476】。文章转载请联系作者。
吴水金
关注
初级架构师 2019.12.01 加入
热情开朗,乐于分享。
评论