亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

一致性Hash算法在Memcached中的應用

2019-11-14 13:32:11
字體:
來源:轉載
供稿:網友

前言

  大家應該都知道Memcached要想實現分布式只能在客戶端來完成,目前比較流行的是通過一致性hash算法來實現.常規的方法是將server的hash值與server的總臺數進行求余,即hash%N,這種方法的弊端是當增減服務器時,將會有較多的緩存需要被重新分配且會造成緩存分配不均勻的情況(有可能某一臺服務器分配的很多,其它的卻很少).

   今天分享一種叫做”ketama”的一致性hash算法,它通過虛擬節點的概念和不同的緩存分配規則有效的抑制了緩存分布不均勻,并最大限度地減少服務器增減時緩存的重新分布。 

實現思路

  假設我們現在有N臺Memcached的Server,如果我們用統一的規則對memcached進行Set,Get操作. 使具有不同key的object很均衡的分散存儲在這些Server上,Get操作時也是按同樣規則去對應的Server上取出object,這樣各個Server之間不就是一個整體了嗎?

那到底是一個什么樣的規則?

  如下圖所示,我們現在有5臺(A,B,C,D,E)Memcached的Server,我們將其串聯起來形成一個環形,每一臺Server都代表圓環上的一個點,每一個點都具有唯一的Hash值,這個圓環上一共有2^32個點.

       那么該如何確定每臺Server具體分布在哪個點上? 這里我們通過”Ketama”的Hash算法來計算出每臺Server的Hash值,拿到Hash值后就可以對應到圓環上點了.(可以用Server的ip地址作為Hash算法的Key.)

  這樣做的好處是,如下圖當我新增Server  F時,那么我只需要將hash值落在C和F之間的object從原本的D上重新分配到F上就可以了,其它的server上的緩存不需要重新分配,并且新增的Server也能及時幫忙緩沖其它Server的壓力.

  到此我們已經解決了增減服務器時大量緩存需要被重新分配的弊端.那該如何解決緩存分配不均勻的問題呢?因為現在我們的server只占據圓環上的6個點,而圓環上總共有2^32個點,這極其容易導致某一臺server上熱點非常多,某一臺上熱點很少的情況.

  ”虛擬節點”的概念很好的解決了這種負載不均衡的問題.通過將每臺物理存在的Server分割成N個虛擬的Server節點(N通常根據物理Server個數來定,這里有個比較好的閾值為250).這樣每個物理Server實際上對應了N個虛擬的節點. 存儲點多了,各個Server的負載自然要均衡一些.就像地鐵站出口一樣,出口越多,每個出口出現擁擠的情況就會越少.

   代碼實現:

復制代碼
//保存所有虛擬節點信息, key : 虛擬節點的hash key, value: 虛擬節點對應的真實server        PRivate Dictionary<uint, string> hostDictionary = new Dictionary<uint, string>();        //保存所有虛擬節點的hash key, 已按升序排序        private uint[] ketamaHashKeys = new uint[] { };        //保存真實server主機地址        private string[] realHostArr = new string[] { };        //每臺真實server對應虛擬節點個數        private int VirtualNodeNum = 250;        public KetamaVirtualNodeInit(string[] hostArr)        {            this.realHostArr = hostArr;            this.InitVirtualNodes();        }        /// <summary>        /// 初始化虛擬節點        /// </summary>        private void InitVirtualNodes()        {            hostDictionary = new Dictionary<uint, string>();            List<uint> hostKeys = new List<uint>();            if (realHostArr == null || realHostArr.Length == 0)            {                throw new Exception("不能傳入空的Server集合");            }            for (int i = 0; i < realHostArr.Length; i++)            {                for (int j = 0; j < VirtualNodeNum; j++)                {                    byte[] nameBytes = Encoding.UTF8.GetBytes(string.Format("{0}-node{1}", realHostArr[i], j));                    //調用Ketama hash算法獲取hash key                    uint hashKey = BitConverter.ToUInt32(new KetamaHash().ComputeHash(nameBytes), 0);                    hostKeys.Add(hashKey);                    if (hostDictionary.ContainsKey(hashKey))                    {                        throw new Exception("創建虛擬節點時發現相同hash key,請檢查是否傳入了相同Server");                    }                    hostDictionary.Add(hashKey, realHostArr[i]);                }            }            hostKeys.Sort();            ketamaHashKeys = hostKeys.ToArray();        }
復制代碼

 

一致性hash算法的分配規則

  到此我們已經知道了所有虛擬節點的Hash值, 現在讓我們來看下當我們拿到一個對象時如何存入Server, 或是拿到一個對象的Key時該如何取出對象. 

       Set一個對象時,先將對象的Key作為”Ketama”算法的Key,計算出Hash值后我們需要做下面幾個步驟.

       1:首先檢查虛擬節點當中是否有與當前對象Hash值相等的,如有則直接將對象存入那個Hash值相等的節點,后面的步驟就不繼續了.

       2:如沒有,則找出第一個比當前對象Hash值要大的節點,(節點的Hash值按升序進行排序,圓環上對應按照順時針來排列),即離對象最近的節點,然后將對象存入該節點.

       3:如果沒有找到Hash值比對象要大的Server,證明對象的Hash值是介于最后一個節點和第一個節點之間的,也就是圓環上的E和A之間.這種情況就直接將對象存入第一個節點,即A.

  代碼實現:  

復制代碼
     /// <summary>        /// 根據hash key 獲取對應的真實Server        /// </summary>        /// <param name="hash"></param>        /// <returns></returns>        public string GetHostByHashKey(string key)        {            byte[] bytes = Encoding.UTF8.GetBytes(key);            uint hash = BitConverter.ToUInt32(new KetamaHash().ComputeHash(bytes), 0);            //尋找與當前hash值相等的Server.             int i = Array.BinarySearch(ketamaHashKeys, hash);            //如果i小于零則表示沒有hash值相等的虛擬節點            if (i < 0)            {                //將i繼續按位求補,得到數組中第一個大于當前hash值的虛擬節點                i = ~i;                //如果按位求補后的i大于等于數組的大小,則表示數組中沒有大于當前hash值的虛擬節點                //此時直接取第一個server                if (i >= ketamaHashKeys.Length)                {                    i = 0;                }            }            //根據虛擬節點的hash key 返回對應的真實server host地址            return hostDictionary[ketamaHashKeys[i]];        }
復制代碼

 

Get一個對象,同樣也是通過”Ketama”算法計算出Hash值,然后與Set過程一樣尋找節點,找到之后直接取出對象即可.

那么這個”Ketama”到底長什么樣呢,讓我們來看看代碼實現.

復制代碼
    /// <summary>    ///  Ketama hash加密算法    ///  關于HashAlgorithm參見MSDN鏈接    ///  http://msdn.microsoft.com/zh-cn/library/system.security.cryptography.hashalgorithm%28v=vs.110%29.aspx    /// </summary>    public class KetamaHash : HashAlgorithm    {        private static readonly uint FNV_prime = 16777619;        private static readonly uint offset_basis = 2166136261;        protected uint hash;        public KetamaHash()        {            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);        }    }
復制代碼

測試性能

最后我把自己參考BeitMemcached寫的算法與老代(Discuz!代震軍)參考SPYMemcached寫的做了一下對比.

源碼在后面有下載.

結果:查找5W個key的時間比老代的版本快了100多倍,但在負載均衡方面差了一些. 

測試數據:

   1:真實Server都是5臺

       2:隨機生成5W個字符串key(生成方法直接拿老代的)

       3:虛擬節點都是250個 

       我的版本:

老代的版本:

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
在线国产精品播放| 91av免费观看91av精品在线| 欧美电影院免费观看| 国产精品免费一区二区三区都可以| 日本高清+成人网在线观看| 欧美精品在线极品| 欧洲亚洲免费在线| 97视频在线观看免费高清完整版在线观看| 亚洲美女精品成人在线视频| 爱福利视频一区| 国产精品影片在线观看| 日韩黄色av网站| 久久久久这里只有精品| 亚洲人成亚洲人成在线观看| 久久国产加勒比精品无码| 日韩精品欧美国产精品忘忧草| 精品中文字幕乱| 欧美日韩福利电影| 欧美日韩中文字幕在线| 国产精品久久久久影院日本| 久久久久久久香蕉网| 色婷婷综合久久久久| 另类天堂视频在线观看| 亚洲福利在线视频| 97在线观看视频| 美女撒尿一区二区三区| 成人黄色午夜影院| 亚洲视频在线观看免费| 日韩av第一页| 欧美激情视频免费观看| 亚洲欧美国产精品久久久久久久| 91精品国产综合久久久久久蜜臀| 亚洲综合小说区| 国产亚洲美女精品久久久| 精品日韩视频在线观看| 亚洲精品中文字幕有码专区| 色777狠狠综合秋免鲁丝| 97在线观看免费高清| 亚洲性视频网址| 国内精品伊人久久| 一区三区二区视频| 91精品国产综合久久久久久蜜臀| 欧美成在线观看| 日韩精品欧美激情| 亚洲肉体裸体xxxx137| 日本久久久久久久| 综合网中文字幕| 国产精品吊钟奶在线| 日韩欧美福利视频| 国产精品狼人色视频一区| 51久久精品夜色国产麻豆| 国产成人精品日本亚洲| 久久成人一区二区| 欧美亚洲另类制服自拍| 在线视频日本亚洲性| 日韩欧美在线观看| 亚洲精品国精品久久99热一| 亚洲国产一区二区三区在线观看| 国产精品女人网站| 亚洲国产精品电影在线观看| 萌白酱国产一区二区| 日本精品久久中文字幕佐佐木| 亚洲欧美日韩中文视频| 国产精品成人va在线观看| 最近中文字幕日韩精品| 国产热re99久久6国产精品| 久久久久久久久网站| 国产精品99久久久久久www| 亚洲另类欧美自拍| 亚洲精品色婷婷福利天堂| 亚洲无限乱码一二三四麻| 国产精品成人国产乱一区| 2019国产精品自在线拍国产不卡| 一本色道久久综合狠狠躁篇怎么玩| 欧美夫妻性视频| 国产精品专区一| 国产精品老牛影院在线观看| 国产99在线|中文| 久久久国产91| 国产精品亚发布| 久久久久久免费精品| 自拍偷拍亚洲欧美| 成人国产精品一区| 欧美精品制服第一页| 麻豆一区二区在线观看| 91免费高清视频| 不用播放器成人网| 久久影视免费观看| 亚洲免费成人av电影| 91极品视频在线| 国产精品久久久久高潮| 国产精品久久久久久久av大片| 欧美大奶子在线| 青青久久av北条麻妃海外网| 91精品国产免费久久久久久| 欧美韩日一区二区| 国产欧美精品在线| 中文字幕九色91在线| 国产精品爽爽爽| 欧美性感美女h网站在线观看免费| 福利视频一区二区| 久久天天躁夜夜躁狠狠躁2022| 中文在线资源观看视频网站免费不卡| 久久中文字幕国产| 精品久久久久久中文字幕一区奶水| 8x海外华人永久免费日韩内陆视频| 性色av一区二区三区红粉影视| 亚洲va码欧洲m码| 亚洲日韩中文字幕在线播放| 一区二区三区在线播放欧美| 亚洲高清久久网| 91高清在线免费观看| 久久亚洲国产精品成人av秋霞| 亚洲色在线视频| 亚洲人永久免费| 91影院在线免费观看视频| 亚洲最大激情中文字幕| 亚洲专区在线视频| 欧美激情视频三区| 国产不卡精品视男人的天堂| 久久久久久久国产精品视频| 亚洲bt天天射| 精品久久久久久久久久久| 性欧美在线看片a免费观看| 欧美成年人视频| 成人黄色av免费在线观看| 亚洲人成在线观看网站高清| 国产在线精品播放| 亚洲人成电影在线观看天堂色| 成人免费淫片aa视频免费| 精品av在线播放| 国产精品av电影| 国产91热爆ts人妖在线| 少妇久久久久久| 亚洲毛片在线免费观看| 性色av一区二区三区免费| 久久久久久综合网天天| 精品少妇v888av| 中文字幕日韩欧美精品在线观看| 色噜噜久久综合伊人一本| 日韩精品黄色网| 久久人人爽国产| 亚洲综合小说区| 国产精品一二三在线| 亚洲精品国产拍免费91在线| 91在线免费看网站| 韩国19禁主播vip福利视频| 青青草99啪国产免费| 中文日韩电影网站| 国产91精品高潮白浆喷水| 国产91精品视频在线观看| 亚洲欧美三级在线| 欧洲s码亚洲m码精品一区| 亚洲激情视频在线观看| 亚洲精品久久视频| 欧美激情第三页| 欧美激情欧美激情| 国产精品免费久久久久影院| 亚洲精品久久久久中文字幕欢迎你| 精品久久香蕉国产线看观看亚洲| 亚洲网站在线播放| 国产精品久久网| 91精品国产高清久久久久久91| 亚洲一区二区日本|