本篇文章給大家?guī)砹岁P(guān)于Redis的相關(guān)知識,其中主要介紹了一致性hash和hash槽的相關(guān)問題,如果發(fā)生擴(kuò)容或者節(jié)點(diǎn)丟失你就會遇到大量的數(shù)據(jù)遷移問題,一致性hash和hash槽就可以避免這種問題,希望對大家有幫助。
推薦學(xué)習(xí):Redis學(xué)習(xí)教程
假如我們現(xiàn)在有x臺緩存設(shè)備,我們在決定把數(shù)據(jù)放到哪個(gè)緩存設(shè)備上的時(shí)候可以key%x,但是如果發(fā)生擴(kuò)容或者節(jié)點(diǎn)丟失你就需要key%(x±y)這樣就會遇到大量的數(shù)據(jù)遷移問題,一致性hash和hash槽就可以避免這種問題。
一致性hash原理
普通的hash是對服務(wù)器的數(shù)量取余,一致性hash是對特定的數(shù)字取余(2^32)不會因?yàn)榉?wù)器的數(shù)量變化,首先我們對服務(wù)器的ip或者其他唯一標(biāo)識取余得到一個(gè)值這個(gè)值就是服務(wù)器在hash環(huán)上的位置,然后對要放入服務(wù)器的對象進(jìn)行hash得到一個(gè)值,在hash換上找對應(yīng)的服務(wù)器如果值所在的位置沒有服務(wù)器就看下一個(gè)位置是否服務(wù)器知道找到可存儲的服務(wù)器。
1、環(huán)形空間
按照常用的hash算法來將對應(yīng)的key哈希到一個(gè)具有2的32 次方個(gè)節(jié)點(diǎn)的空間中,即0 ~ (2的32)-1的數(shù)字空間中。我們可以把這個(gè)東西想象成一個(gè)咬住尾巴的,形成了一個(gè)閉環(huán)。
2、服務(wù)器hash到環(huán)上
環(huán)有了我們現(xiàn)在需要把服務(wù)器放到環(huán)上,可以根據(jù)服務(wù)器的IP地址獲取編號等唯一標(biāo)識取hash后放到環(huán)上。
3、數(shù)據(jù)存儲和獲取
當(dāng)我們需要把一個(gè)數(shù)據(jù)放到服務(wù)器上的時(shí)候我們首先需要計(jì)算數(shù)據(jù)的hash值然后取余,如果取余后的值在環(huán)上有對應(yīng)的服務(wù)器那直接放進(jìn)去如果沒有則向后查找。
所以最后data1在redis1里面,data2在redis2里面。當(dāng)我們獲取數(shù)據(jù)的時(shí)候也是執(zhí)行相同的過程,計(jì)算key的hash值,然后根據(jù)相同的規(guī)則獲取存儲的服務(wù)器。
4、服務(wù)器的刪除和添加
如果現(xiàn)在某個(gè)redis節(jié)點(diǎn)掛掉了,那么其他節(jié)點(diǎn)里面的數(shù)據(jù)是還在的,原來節(jié)點(diǎn)里面的數(shù)據(jù)會被重新分配到下一個(gè)節(jié)點(diǎn)里面。
如果在環(huán)境中新增一臺服務(wù)器RedisNeo,通過hash算法將RedisNeo映射到環(huán)中,通過按順時(shí)針遷移的規(guī)則,那么以前hash值在Redis2和RedisNeo之間的數(shù)據(jù)遷移到RedisNeo里面(下圖中RedisNeo挨著Redis2),其它對象還保持這原有的存儲位置。通過對節(jié)點(diǎn)的添加和刪除的分析,一致性哈希算法在保持了單調(diào)性的同時(shí),還是數(shù)據(jù)的遷移達(dá)到了最小,這樣的算法對分布式集群來說是非常合適的,避免了大量數(shù)據(jù)遷移,減小了服務(wù)器的的壓力。
所以redisNeo加入后data3就到redisNeo里面去了。
5、平衡性
到目前為止一致性hash也可以算做完成了,但是有一個(gè)問題還需要解決,那就是平衡性。從下圖我們可以看出,當(dāng)服務(wù)器節(jié)點(diǎn)比較少的時(shí)候,會出現(xiàn)一個(gè)問題,就是此時(shí)必然造成大量數(shù)據(jù)集中到一個(gè)節(jié)點(diǎn)上面,例如你只有兩個(gè)節(jié)點(diǎn)一個(gè)在1另一個(gè)在10,那么很顯然1節(jié)點(diǎn)的壓力是無限大的,因?yàn)橹挥衕ash值在[2,10]之間的才會到10節(jié)點(diǎn),其他的全到1節(jié)點(diǎn)上去了,為了解決這種數(shù)據(jù)傾斜問題,一致性哈希算法引入了虛擬節(jié)點(diǎn)機(jī)制,即對每一個(gè)服務(wù)節(jié)點(diǎn)計(jì)算多個(gè)哈希,每個(gè)計(jì)算結(jié)果位置都放置一個(gè)此服務(wù)節(jié)點(diǎn),稱為虛擬節(jié)點(diǎn)。具體做法可以先確定每個(gè)物理節(jié)點(diǎn)關(guān)聯(lián)的虛擬節(jié)點(diǎn)數(shù)量,然后在ip或者主機(jī)名后面增加編號,同時(shí)數(shù)據(jù)定位算法不變,只是多了一步虛擬節(jié)點(diǎn)到實(shí)際節(jié)點(diǎn)的映射。
hash槽
哈希槽是在redis cluster集群方案中采用的,redis cluster集群沒有采用一致性哈希方案,而是采用數(shù)據(jù)分片中的哈希槽來進(jìn)行數(shù)據(jù)存儲與讀取的。redis cluster采用數(shù)據(jù)分片的哈希槽來進(jìn)行數(shù)據(jù)存儲和數(shù)據(jù)的讀取。redis cluster一共有2^14(16384)個(gè)槽,所有的master節(jié)點(diǎn)都會有一個(gè)槽區(qū)比如0~1000,槽數(shù)是可以遷移的。master節(jié)點(diǎn)的slave節(jié)點(diǎn)不分配槽,只擁有讀權(quán)限。但是注意在代碼中redis cluster執(zhí)行讀寫操作的都是master節(jié)點(diǎn),并不是你想 的讀是從節(jié)點(diǎn),寫是主節(jié)點(diǎn)。第一次新建redis cluster時(shí),16384個(gè)槽是被master節(jié)點(diǎn)均勻分布的。
和一致性哈希相比在擴(kuò)容和縮容的時(shí)候需要手動手動分配hash槽,并且在刪除master節(jié)點(diǎn)的時(shí)候要把他的從節(jié)點(diǎn)和hash槽交給其他master節(jié)點(diǎn);hash槽的是根據(jù)CRC-16(key)%16384的值來判斷屬于哪個(gè)槽區(qū)。
推薦學(xué)習(xí):Redis教程