源地址哈希算法

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

原文地址:https://www.cnblogs.com/liuxiaoji/p/10309710.html