一致性hash算法

参考帖

https://www.cnblogs.com/mushroom/p/4472369.html

hash一致性算法hash函数的一种,他的目的在于实现负载均衡,并且每次访问的目标具有一致性,举个例子来说,根据客户端请求ip,经过hash一致性算法,每次计算出来的一致性hash值都是相同的因此每次

请求的目标主机将是一致的,这种算法广泛使用在负载均衡,数据库水平分表,他的本质在于通过算法的方式计算出key的一致性和唯一性,均衡性

而一致性hash算法的核心在于增加了虚拟节点来尽可能的达到key值投射到目的主机尽量均衡

java实现代码:

http://blog.csdn.net/jerome_s/article/details/52492862

c#实现代码

  1 public class ConsistencyHash
  2     {
  3 
  4         // 环的所有节点
  5         private SortedList<long, Object> allNodes = null;
  6         // 真实服务器节点
  7         private List<Object> realNodes = new List<object>();
  8         // 设置虚拟节点数目
  9         // 太多会影响性能,太少又会导致负载不均衡,一般说来,经验值是150,
 10         // 当然根据集群规模和负载均衡的精度需求,这个值应该根据具体情况具体对待。
 11         private int VIRTUAL_NODE_COUNT = 150;
 12 
 13         /**
 14          * 初始化一致环
 15          */
 16 
 17         public void init()
 18         {
 19 
 20             // 加入五台真实服务器
 21             realNodes.Add("192.168.0.0-服务器0");
 22             realNodes.Add("192.168.0.1-服务器1");
 23             realNodes.Add("192.168.0.2-服务器2");
 24             realNodes.Add("192.168.0.3-服务器3");
 25             realNodes.Add("192.168.0.4-服务器4");
 26 
 27             // 构造每台真实服务器的虚拟节点
 28             allNodes = new SortedList<long, object>();
 29             for (int i = 0; i < realNodes.Count(); i++)
 30             {
 31                 Object nodeInfo = realNodes[i];
 32                 for (int j = 0; j < VIRTUAL_NODE_COUNT; j++)
 33                 {
 34                     var cpm = "NODE-" + i + "-VIRTUAL-" + j;
 35                     var md5 = computeMd5(cpm);
 36                     var hashVal = hash(md5, 0);
 37                     allNodes.Add(hashVal, nodeInfo);
 38 
 39                     Console.WriteLine(string.Format("{0}	{1}", cpm,hashVal));
 40                 }
 41             }
 42         }
 43 
 44         /**
 45          * 计算MD5值
 46          */
 47 
 48         public byte[] computeMd5(String k)
 49         {
 50 
 51             MD5 md5 = new MD5CryptoServiceProvider();
 52 
 53             byte[] keyBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(k));
 54             md5.Clear();
 55             //md5.update(keyBytes);
 56             //return md5.digest();
 57             return keyBytes;
 58         }
 59 
 60         /**
 61          * 根据2^32把节点分布到环上面
 62          *
 63          * @param digest
 64          * @param nTime
 65          * @return
 66          */
 67 
 68         public long hash(byte[] digest, int nTime)
 69         {
 70             long rv = ((long) (digest[3 + nTime*4] & 0xFF) << 24)
 71                       | ((long) (digest[2 + nTime*4] & 0xFF) << 16)
 72                       | ((long) (digest[1 + nTime*4] & 0xFF) << 8)
 73                       | (digest[0 + nTime*4] & 0xFF);
 74 
 75             return rv & 0xffffffffL; /* Truncate to 32-bits */
 76         }
 77 
 78 
 79         /**
 80          * 根据key的hash值取得服务器节点信息
 81          *
 82          * @param hash
 83          * @return
 84          */
 85 
 86         public Object getNodeInfo(long hash)
 87         {
 88 
 89             string rv;
 90             long key = hash;
 91             //如果找到这个节点,直接取节点,返回   
 92             if (!allNodes.ContainsKey(key))
 93             {
 94                 //得到大于当前key的那个子Map,然后从中取出第一个key,就是大于且离它最近的那个key 说明详见: http://www.javaeye.com/topic/684087
 95                 var tailMap = from coll in allNodes
 96                     where coll.Key > hash
 97                     select new {coll.Key};
 98                 if (tailMap == null || tailMap.Count() == 0)
 99                     key = allNodes.FirstOrDefault().Key;
100                 else
101                     key = tailMap.FirstOrDefault().Key;
102             }
103             return allNodes[key];
104         }
105 
106     }

示例使用代码

 1 static void Main(string[] args)
 2         {
 3             ConsistencyHash consistencyHash = new ConsistencyHash();
 4             consistencyHash.init();
 5 
 6             int _0 = 0;
 7             int _1 = 0;
 8             int _2 = 0;
 9             int _3 = 0;
10             int _4 = 0;
11 
12             Random ran = new Random();
13             for (int i = 0; i < 50000; i++)
14             {
15                 // 随便取一个数的md5
16                 byte[] ranNum = consistencyHash.computeMd5(i.ToString());
17 
18                 // 分配到随即的hash环上面
19                 long key = consistencyHash.hash(ranNum, 2);
20                 // long key = consistencyHash.hash(ranNum, ran.nextInt(consistencyHash.VIRTUAL_NODE_COUNT));
21 
22                 // 获取他所属服务器的信息
23                 // System.out.println(consistencyHash.getNodeInfo(key));
24                 if (consistencyHash.getNodeInfo(key).Equals("192.168.0.0-服务器0"))
25                 {
26                     _0++;
27                 }
28                 else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.1-服务器1"))
29                 {
30                     _1++;
31                 }
32                 else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.2-服务器2"))
33                 {
34                     _2++;
35                 }
36                 else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.3-服务器3"))
37                 {
38                     _3++;
39                 }
40                 else if (consistencyHash.getNodeInfo(key).Equals("192.168.0.4-服务器4"))
41                 {
42                     _4++;
43                 }
44                 else
45                 {
46                     Console.WriteLine("error");
47                 }
48             }
49 
50             // 输出每台服务器负载情况
51             Console.WriteLine("_0 = " + _0);
52             Console.WriteLine("_1 = " + _1);
53             Console.WriteLine("_2 = " + _2);
54             Console.WriteLine("_3 = " + _3);
55             Console.WriteLine("_4 = " + _4);
56 
57             Console.Read();
58 
59         }

 运行结果

原文地址:https://www.cnblogs.com/rjjs/p/8024609.html