一致性哈希算法测试(C#)

10个Memcached节点,填充100000数据的测试结果如下:

 

192.168.1.199:11211 => 13046
192.168.1.191:11211 => 18230
192.168.1.197:11211 => 6382
192.168.1.194:11211 => 5242
192.168.1.193:11211 => 25554
192.168.1.190:11211 => 1124
192.168.1.196:11211 => 4074
192.168.1.198:11211 => 466
192.168.1.192:11211 => 24652
192.168.1.195:11211 => 1230


Add Server => 192.168.1.200:11211

192.168.1.199:11211 => 13046
192.168.1.191:11211 => 18230
192.168.1.197:11211 => 6382
192.168.1.194:11211 => 5242
192.168.1.193:11211 => 25554
192.168.1.190:11211 => 1124
192.168.1.196:11211 => 4074
192.168.1.198:11211 => 466
192.168.1.200:11211 => 273
192.168.1.192:11211 => 24379
192.168.1.195:11211 => 1230


Delete Server => 192.168.1.193:11211

192.168.1.199:11211 => 13046
192.168.1.191:11211 => 18230
192.168.1.197:11211 => 6382
192.168.1.194:11211 => 5242
192.168.1.190:11211 => 1124
192.168.1.196:11211 => 4074
192.168.1.198:11211 => 466
192.168.1.200:11211 => 273
192.168.1.192:11211 => 24379
192.168.1.195:11211 => 26784

 

单独Memcached节点不要存放太多的数据,一旦出现问题,会出现太多的缓存失效,所以如果发现某个Memcached节点存放了太多的数据,也许应该考虑将数据平衡到其它Memcached节点。

 

//程序代码如下:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
using System.Security.Cryptography;

namespace ConsoleApplication1
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Hashtable htServers = new Hashtable();

            htServers.Add("192.168.1.190:11211", 0);
            htServers.Add("192.168.1.191:11211", 0);
            htServers.Add("192.168.1.192:11211", 0);
            htServers.Add("192.168.1.193:11211", 0);
            htServers.Add("192.168.1.194:11211", 0);
            htServers.Add("192.168.1.195:11211", 0);
            htServers.Add("192.168.1.196:11211", 0);
            htServers.Add("192.168.1.197:11211", 0);
            htServers.Add("192.168.1.198:11211", 0);
            htServers.Add("192.168.1.199:11211", 0);

            ConsistentHashing ch = new ConsistentHashing(htServers);

            for (int i = 0; i < 100000; ++i)//填充数据
            {
                KeyValuePair<uint, string> Temp = ch.Locate(i.ToString());
                int iCounter = Convert.ToInt32(htServers[Temp.Value]);
                htServers[Temp.Value] = iCounter + 1;//计数器
            }

            IDictionaryEnumerator Iterator0 = htServers.GetEnumerator();
            while (Iterator0.MoveNext())
            {
                Console.WriteLine("{0} => {1}", Iterator0.Key, Iterator0.Value);
            }

            string strAddServer = "192.168.1.200:11211";

            htServers.Add(strAddServer, 0);
            ch.AddServer(strAddServer);

            Console.WriteLine("");
            Console.WriteLine("Add Server => " + strAddServer);
            Console.ReadLine();

            htServers["192.168.1.190:11211"] = 0;
            htServers["192.168.1.191:11211"] = 0;
            htServers["192.168.1.192:11211"] = 0;
            htServers["192.168.1.193:11211"] = 0;
            htServers["192.168.1.194:11211"] = 0;
            htServers["192.168.1.195:11211"] = 0;
            htServers["192.168.1.196:11211"] = 0;
            htServers["192.168.1.197:11211"] = 0;
            htServers["192.168.1.198:11211"] = 0;
            htServers["192.168.1.199:11211"] = 0;
            htServers[strAddServer] = 0;

             for (int i = 0; i < 100000; ++i)
            {
                KeyValuePair<uint, string> Temp = ch.Locate(i.ToString());
                int iCounter = Convert.ToInt32(htServers[Temp.Value]);
                htServers[Temp.Value] = iCounter + 1;
            }

            IDictionaryEnumerator Iterator1 = htServers.GetEnumerator();
            while (Iterator1.MoveNext())
            {
                Console.WriteLine("{0} => {1}", Iterator1.Key, Iterator1.Value);
            }

            string strDeleteServer = "192.168.1.193:11211";

            htServers.Remove(strDeleteServer);
            ch.DeleteServer(strDeleteServer);

            Console.WriteLine("");
            Console.WriteLine("Delete Server => " + strDeleteServer);
            Console.ReadLine();

            htServers["192.168.1.190:11211"] = 0;
            htServers["192.168.1.191:11211"] = 0;
            htServers["192.168.1.192:11211"] = 0;
            //htServers["192.168.1.193:11211"] = 0;
            htServers["192.168.1.194:11211"] = 0;
            htServers["192.168.1.195:11211"] = 0;
            htServers["192.168.1.196:11211"] = 0;
            htServers["192.168.1.197:11211"] = 0;
            htServers["192.168.1.198:11211"] = 0;
            htServers["192.168.1.199:11211"] = 0;
            htServers[strAddServer] = 0;

            for (int i = 0; i < 100000; ++i)
            {
                KeyValuePair<uint, string> Temp = ch.Locate(i.ToString());
                int iCounter = Convert.ToInt32(htServers[Temp.Value]);
                htServers[Temp.Value] = iCounter + 1;
            }

            IDictionaryEnumerator Iterator2 = htServers.GetEnumerator();
            while (Iterator2.MoveNext())
            {
                Console.WriteLine("{0} => {1}", Iterator2.Key, Iterator2.Value);
            }

            Console.ReadLine();
        }
    }

    /// <summary>
    /// 一致性 Hash 算法
    /// </summary>
    class ConsistentHashing
    {
        List<KeyValuePair<uint, string>> _serList = new List<KeyValuePair<uint, string>>();

        public ConsistentHashing(string[] serList)
        {
            if (serList == null || serList.Length == 0)
                return;

            foreach (var ser in serList)
            {
                uint uiKey = Hash(ser);
                _serList.Add(new KeyValuePair<uint, string>(uiKey, ser));
            }
            _serList.Sort((x, y) => x.Key > y.Key ? 1 : (x.Key == y.Key ? 0 : -1));
        }

        public ConsistentHashing(Hashtable htServers)
        {
            IDictionaryEnumerator Iterator = htServers.GetEnumerator();
            while (Iterator.MoveNext())
            {
                uint uiKey = Hash(Iterator.Key.ToString());
                _serList.Add(new KeyValuePair<uint, string>(uiKey, Iterator.Key.ToString()));
            }
            _serList.Sort((x, y) => x.Key > y.Key ? 1 : (x.Key == y.Key ? 0 : -1));
        }

        public void AddServer(string strServer)
        {
            uint uiKey = Hash(strServer);
            _serList.Add(new KeyValuePair<uint, string>(uiKey, strServer));
            _serList.Sort((x, y) => x.Key > y.Key ? 1 : (x.Key == y.Key ? 0 : -1));
        }

        public void DeleteServer(string strServer)
        {
            uint uiKey = Hash(strServer);
            _serList.Remove(new KeyValuePair<uint, string>(uiKey, strServer));
            _serList.Sort((x, y) => x.Key > y.Key ? 1 : (x.Key == y.Key ? 0 : -1));
        }

        /// <summary>
        /// Hash 具体的节点
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public KeyValuePair<uint, string> Locate(string key)
        {
            if (string.IsNullOrEmpty(key))
                return _serList[0];

            var hash = Hash(key);
            var index = _serList.BinarySearch(new KeyValuePair<uint, string>(hash, null), new KeyValuePairComparer());
            if (index >= 0)
                return _serList[index];
            else
            {
                var nIndex = ~index;
                if (nIndex >= _serList.Count)
                    return _serList[0];
                else
                    return _serList[nIndex];
            }
        }
        /// <summary>
        /// 得到字符串的HASH
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private static uint Hash(string key)
        {
            return BitConverter.ToUInt32(new ModifiedFNV1_32().ComputeHash(Encoding.UTF8.GetBytes(key)), 0);
        }

        /// <summary>
        /// KeyValuePair 比较器实现
        /// 只比对 Key 部分大小
        /// </summary>
        class KeyValuePairComparer
            : IComparer<KeyValuePair<uint, string>>
        {

            #region IComparer<KeyValuePair<uint,string>> 成员
            public int Compare(KeyValuePair<uint, string> x, KeyValuePair<uint, string> y)
            {
                int i = x.Key > y.Key ? 1 : (x.Key == y.Key ? 0 : -1);
                return i;
            }
            #endregion
        }
        #region HASH函数相关
        /// <summary>
        /// 修改版FNV1_32 哈希函数
        /// </summary>
        /// <remarks>
        /// FNV1_32 哈希函数
        /// Fowler-Noll-Vo hash, variant 1, 32-bit version.
        /// http://www.isthe.com/chongo/tech/comp/fnv/
        /// 修改版FNV1_32 哈希函数
        /// Modified Fowler-Noll-Vo hash, 32-bit version.
        /// http://home.comcast.net/~bretm/hash/6.html
        /// </remarks>
        class ModifiedFNV1_32 : HashAlgorithm
        {
            private static readonly uint FNV_prime = 16777619;
            private static readonly uint offset_basis = 2166136261;

            protected uint hash;

            public ModifiedFNV1_32()
            {
                HashSizeValue = 32;
            }

            public override void Initialize()
            {
                hash = offset_basis;
            }

            protected override void HashCore(byte[] array, int ibStart, int cbSize)
            {
                int length = ibStart + cbSize;
                for (int i = ibStart; i < length; i++)
                {
                    hash = (hash * FNV_prime) ^ array[i];
                }
            }

            protected override byte[] HashFinal()
            {
                hash += hash << 13;
                hash ^= hash >> 7;
                hash += hash << 3;
                hash ^= hash >> 17;
                hash += hash << 5;
                return BitConverter.GetBytes(hash);
            }
        }
        #endregion
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值