Redis集群:sharding策略
為什么集群?
通常,為了提高網(wǎng)站響應(yīng)速度,總是把熱點數(shù)據(jù)保存在內(nèi)存中而不是直接從后端數(shù)據(jù)庫中讀取。Redis是一個很好的Cache工具。大型網(wǎng)站應(yīng)用,熱點數(shù)據(jù)量往往巨大,幾十G上百G是很正常的事兒,在這種情況下,如何正確架構(gòu)Redis呢?
首先,無論我們是使用自己的物理主機(jī),還是使用云服務(wù)主機(jī),內(nèi)存資源往往是有限制的,scale up不是一個好辦法,我們需要scale out橫向可伸縮擴(kuò)展,這需要由多臺主機(jī)協(xié)同提供服務(wù),即分布式多個Redis實例協(xié)同運行。
其次,目前硬件資源成本降低,多核CPU,幾十G內(nèi)存的主機(jī)很普遍,對于主進(jìn)程是單線程工作的Redis,只運行一個實例就顯得有些浪費。同時,管理一個巨大內(nèi)存不如管理相對較小的內(nèi)存高效。因此,實際使用中,通常一臺機(jī)器上同時跑多個Redis實例。
方案
1.Redis官方集群方案 Redis Cluster(服務(wù)器分片)
其理論是,客戶端隨意與集群中的任何節(jié)點通信,服務(wù)器端負(fù)責(zé)計算某個key在哪個機(jī)器上,當(dāng)客戶端訪問某臺機(jī)器時,服務(wù)器計算對應(yīng)的key應(yīng)該存儲在哪個機(jī)器,然后把結(jié)果返回給客戶端,客戶端再去對應(yīng)的節(jié)點操作key,是一個重定向的過程,此方式是redis3.0正在實現(xiàn),目前處于beta版本,?Redis3.0的集群同時支持HA功能,某個master節(jié)點掛了后,其slave會自動接管。
Redis Cluster是一種服務(wù)器Sharding技術(shù),3.0版本開始正式提供。Redis Cluster中,Sharding采用slot(槽)的概念,一共分成16384個槽,這有點兒類似前面講的pre sharding思路。對于每個進(jìn)入Redis的鍵值對,根據(jù)key進(jìn)行散列,分配到這16384個slot中的某一個中。使用的hash算法也比較簡單,就是CRC16后16384取模。Redis集群中的每個node(節(jié)點)負(fù)責(zé)分?jǐn)傔@16384個slot中的一部分,也就是說,每個slot都對應(yīng)一個node負(fù)責(zé)處理。當(dāng)動態(tài)添加或減少node節(jié)點時,需要將16384個槽做個再分配,槽中的鍵值也要遷移。當(dāng)然,這一過程,在目前實現(xiàn)中,還處于半自動狀態(tài),需要人工介入。Redis集群,要保證16384個槽對應(yīng)的node都正常工作,如果某個node發(fā)生故障,那它負(fù)責(zé)的slots也就失效,整個集群將不能工作。
為了增加集群的可訪問性,官方推薦的方案是將node配置成主從結(jié)構(gòu),即一個master主節(jié)點,掛n個slave從節(jié)點。這時,如果主節(jié)點失效,Redis Cluster會根據(jù)選舉算法從slave節(jié)點中選擇一個上升為主節(jié)點,整個集群繼續(xù)對外提供服務(wù)。
這非常類似前篇文章提到的Redis Sharding場景下服務(wù)器節(jié)點通過Sentinel監(jiān)控架構(gòu)成主從結(jié)構(gòu),只是Redis Cluster本身提供了故障轉(zhuǎn)移容錯的能力。
Redis Cluster的新節(jié)點識別能力、故障判斷及故障轉(zhuǎn)移能力是通過集群中的每個node都在和其它nodes進(jìn)行通信,這被稱為集群總線(cluster bus)。它們使用特殊的端口號,即對外服務(wù)端口號加10000。例如如果某個node的端口號是6379,那么它與其它nodes通信的端口號是16379。nodes之間的通信采用特殊的二進(jìn)制協(xié)議。
對客戶端來說,整個cluster被看做是一個整體,客戶端可以連接任意一個node進(jìn)行操作,就像操作單一Redis實例一樣,當(dāng)客戶端操作的key沒有分配到該node上時,就像操作單一Redis實例一樣,當(dāng)客戶端操作的key沒有分配到該node上時,Redis會返回轉(zhuǎn)向指令,指向正確的node,這有點兒像瀏覽器頁面的302 redirect跳轉(zhuǎn)。
Redis Cluster是Redis 3.0以后才正式推出,時間較晚,目前能證明在大規(guī)模生產(chǎn)環(huán)境下成功的案例還不是很多,需要時間檢驗。
2.Redis Sharding集群(客戶端實現(xiàn)數(shù)據(jù)分片)
即客戶端自己計算數(shù)據(jù)的key應(yīng)該在哪個機(jī)器上存儲和查找,此方法的好處是降低了服務(wù)器集群的復(fù)雜度,客戶端實現(xiàn)數(shù)據(jù)分片時,服務(wù)器是獨立的,服務(wù)器之前沒有任何關(guān)聯(lián)。多數(shù)redis客戶端庫實現(xiàn)了此功能,也叫sharding,這種方式的缺點是客戶端需要實時知道當(dāng)前集群節(jié)點的聯(lián)系信息,同時,當(dāng)添加一個新的節(jié)點時,客戶端要支持動態(tài)sharding.,多數(shù)客戶端實現(xiàn)不支持此功能,需要重啟redis。另一個弊端是redis的HA需要額外考慮。
?
多Redis實例服務(wù),比單Redis實例要復(fù)雜的多,這涉及到定位、協(xié)同、容錯、擴(kuò)容等技術(shù)難題。這里,我們介紹一種輕量級的客戶端Redis Sharding技術(shù)。
Redis Sharding可以說是Redis Cluster出來之前,業(yè)界普遍使用的多Redis實例集群方法。其主要思想是采用哈希算法將數(shù)據(jù)的key進(jìn)行散列,然后特定的key會映射到特定的Redis節(jié)點上)。這樣,客戶端就知道該向哪個Redis節(jié)點操作數(shù)據(jù)。
Sharding架構(gòu)如圖:
?
慶幸的是,java redis客戶端驅(qū)動jedis,已支持Redis Sharding功能,即ShardedJedis以及結(jié)合緩存池的ShardedJedisPool。
Jedis的Redis Sharding實現(xiàn)具有如下特點:
1、采用一致性哈希算法(consistent hashing),將key和節(jié)點name各自hashing,,然后進(jìn)行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用簡單類似哈希求模映射的主要原因是當(dāng)增加或減少節(jié)點時,不會產(chǎn)生由于重新匹配造成的rehashing。一致性哈希只影響相鄰節(jié)點key分配,影響量小。
2.為了避免一致性哈希只影響相鄰節(jié)點造成節(jié)點分配壓力,ShardedJedis會對每個Redis節(jié)點根據(jù)名字(沒有,Jedis會賦予缺省名字)會虛擬化出160個虛擬節(jié)點進(jìn)行散列。根據(jù)權(quán)重weight,也可虛擬化出160倍數(shù)的虛擬節(jié)點。用虛擬節(jié)點做映射匹配,可以在增加或減少Redis節(jié)點時,key在各Redis節(jié)點移動再分配更均勻,而不是只有相鄰節(jié)點受影響。(就比如ABC3個節(jié)點只能映射出ABC3個散列,如果每個ABC可以虛擬出多N個,即上面說的160個(即現(xiàn)在有3*160個可供給映射),那么存進(jìn)去的數(shù)據(jù)則會更加的均勻。)
3.ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,這樣通過合理命名key,可以將一組相關(guān)聯(lián)的key放入同一個Redis節(jié)點,這在避免跨節(jié)點訪問相關(guān)數(shù)據(jù)時很重要。
擴(kuò)容問題
Redis Sharding采用客戶端Sharding方式,服務(wù)端Redis還是一個個相對獨立的Redis實例節(jié)點,沒有做任何變動。同時,我們也不需要增加額外的中間處理組件,這是一種非常輕量、靈活的Redis多實例集群方法。
當(dāng)然,Redis Sharding這種輕量靈活方式必然在集群其它能力方面做出妥協(xié)。比如擴(kuò)容,當(dāng)想要增加Redis節(jié)點時,盡管采用一致性哈希,畢竟還是會有key匹配不到而丟失,這時需要鍵值遷移。
??? 作為輕量級客戶端sharding,處理Redis鍵值遷移是不現(xiàn)實的,這就要求應(yīng)用層面允許Redis中數(shù)據(jù)丟失或從后端數(shù)據(jù)庫重新加載數(shù)據(jù)。但有些時候,擊穿緩存層,直接訪問數(shù)據(jù)庫層,會對系統(tǒng)訪問造成很大壓力。有沒有其它手段改善這種情況?
??? Redis作者給出了一個比較討巧的辦法–presharding,即預(yù)先根據(jù)系統(tǒng)規(guī)模盡量部署好多個Redis實例,這些實例占用系統(tǒng)資源很小,一臺物理機(jī)可部署多個,讓他們都參與sharding,當(dāng)需要擴(kuò)容時,選中一個實例作為主節(jié)點,新加入的Redis節(jié)點作為從節(jié)點進(jìn)行數(shù)據(jù)復(fù)制。數(shù)據(jù)同步后,修改sharding配置,讓指向原實例的Shard指向新機(jī)器上擴(kuò)容后的Redis節(jié)點,同時調(diào)整新Redis節(jié)點為主節(jié)點,原實例可不再使用。
這樣,我們的架構(gòu)模式變成一個Redis節(jié)點切片包含一個主Redis和一個備Redis。在主Redis宕機(jī)時,備Redis接管過來,上升為主Redis,繼續(xù)提供服務(wù)。主備共同組成一個Redis節(jié)點,通過自動故障轉(zhuǎn)移,保證了節(jié)點的高可用性。則Sharding架構(gòu)演變成:
?
Redis Sentinel提供了主備模式下Redis監(jiān)控、故障轉(zhuǎn)移功能達(dá)到系統(tǒng)的高可用性。
高訪問量下,即使采用Sharding分片,一個單獨節(jié)點還是承擔(dān)了很大的訪問壓力,這時我們還需要進(jìn)一步分解。通常情況下,應(yīng)用訪問Redis讀操作量和寫操作量差異很大,讀常常是寫的數(shù)倍,這時我們可以將讀寫分離,而且讀提供更多的實例數(shù)。
可以利用主從模式實現(xiàn)讀寫分離,主負(fù)責(zé)寫,從負(fù)責(zé)只讀,同時一主掛多個從。在Sentinel監(jiān)控下,還可以保障節(jié)點故障的自動監(jiān)測。
?
3.利用代理中間件實現(xiàn)大規(guī)模Redis集群
上面分別介紹了多Redis服務(wù)器集群的兩種方式,它們是基于客戶端sharding的Redis Sharding和基于服務(wù)端sharding的Redis Cluster。
客戶端sharding技術(shù)其優(yōu)勢在于服務(wù)端的Redis實例彼此獨立,相互無關(guān)聯(lián),每個Redis實例像單服務(wù)器一樣運行,非常容易線性擴(kuò)展,系統(tǒng)的靈活性很強。其不足之處在于:
1.由于sharding處理放到客戶端,規(guī)模進(jìn)步擴(kuò)大時給運維帶來挑戰(zhàn)。
2.服務(wù)端Redis實例群拓?fù)浣Y(jié)構(gòu)有變化時,每個客戶端都需要更新調(diào)整。連接不能共享,當(dāng)應(yīng)用規(guī)模增大時,資源浪費制約優(yōu)化。
服務(wù)端sharding的Redis Cluster其優(yōu)勢在于服務(wù)端Redis集群拓?fù)浣Y(jié)構(gòu)變化時,客戶端不需要感知,客戶端像使用單Redis服務(wù)器一樣使用Redis集群,運維管理也比較方便。不過Redis Cluster正式版推出時間不長,系統(tǒng)穩(wěn)定性、性能等都需要時間檢驗,尤其在大規(guī)模使用場合。
能不能結(jié)合二者優(yōu)勢?即能使服務(wù)端各實例彼此獨立(客戶端的好處),支持線性可伸縮,同時sharding又能集中處理(服務(wù)器端的好處),方便統(tǒng)一管理?本篇介紹的Redis代理中間件twemproxy就是這樣一種利用中間件做sharding的技術(shù)。
twemproxy處于客戶端和服務(wù)器的中間,將客戶端發(fā)來的請求,進(jìn)行一定的處理后(如sharding),再轉(zhuǎn)發(fā)給后端真正的Redis服務(wù)器。也就是說,客戶端不直接訪問Redis服務(wù)器,而是通過twemproxy代理中間件間接訪問。
參照Redis Sharding架構(gòu),增加代理中間件的Redis集群架構(gòu)如下:
twemproxy中間件的內(nèi)部處理是無狀態(tài)的,它本身可以很輕松地集群,這樣可避免單點壓力或故障。
twemproxy又叫nutcracker,起源于twitter系統(tǒng)中redis/memcached集群開發(fā)實踐,運行效果良好,后代碼奉獻(xiàn)給開源社區(qū)。其輕量高效,采用C語言開發(fā),工程網(wǎng)址是:GitHub - twitter/twemproxy: A fast, light-weight proxy for memcached andredis
twemproxy后端不僅支持redis,同時也支持memcached,這是twitter系統(tǒng)具體環(huán)境造成的。
由于使用了中間件,twemproxy可以通過共享與后端系統(tǒng)的連接,降低客戶端直接連接后端服務(wù)器的連接數(shù)量。同時,它也提供sharding功能,支持后端服務(wù)器集群水平擴(kuò)展。統(tǒng)一運維管理也帶來了方便。
當(dāng)然,也是由于使用了中間件代理,相比客戶端直連服務(wù)器方式,性能上會有所損耗,實測結(jié)果大約降低了20%左右。
#################################這是分割線###########################################
說到主從備份、分片、集群 往往很模糊,下面做了幾個圖來說明。
主從復(fù)制備份:
nosql的數(shù)據(jù)庫(redis mongodb等)量大部分都支持主從復(fù)制
?
redis分片:
redis集群:
3個方法總結(jié):
(1)客戶端實現(xiàn)數(shù)據(jù)分片?
即客戶端自己計算數(shù)據(jù)的key應(yīng)該在哪個機(jī)器上存儲和查找,此方法的好處是降低了服務(wù)器集群的復(fù)雜度,客戶端實現(xiàn)數(shù)據(jù)分片時,服務(wù)器是獨立的,服務(wù)器之前沒有任何關(guān)聯(lián)。多數(shù)redis客戶端庫實現(xiàn)了此功能,也叫sharding,這種方式的缺點是客戶端需要實時知道當(dāng)前集群節(jié)點的聯(lián)系信息,同時,當(dāng)添加一個新的節(jié)點時,客戶端要支持動態(tài)sharding.,多數(shù)客戶端實現(xiàn)不支持此功能,需要重啟redis。另一個弊端是redis的HA需要額外考慮。
?
(2)服務(wù)器實現(xiàn)數(shù)據(jù)分片?
其理論是,客戶端隨意與集群中的任何節(jié)點通信,服務(wù)器端負(fù)責(zé)計算某個key在哪個機(jī)器上,當(dāng)客戶端訪問某臺機(jī)器時,服務(wù)器計算對應(yīng)的key應(yīng)該存儲在哪個機(jī)器,然后把結(jié)果返回給客戶端,客戶端再去對應(yīng)的節(jié)點操作key,是一個重定向的過程,此方式是redis3.0正在實現(xiàn),目前處于beta版本,?Redis 3.0的集群同時支持HA功能,某個master節(jié)點掛了后,其slave會自動接管。
?
(3)通過代理服務(wù)器實現(xiàn)數(shù)據(jù)分片?
此方式是借助一個代理服務(wù)器實現(xiàn)數(shù)據(jù)分片,客戶端直接與proxy聯(lián)系,proxy計算集群節(jié)點信息,并把請求發(fā)送到對應(yīng)的集群節(jié)點。降低了客戶端的復(fù)雜度,需要proxy收集集群節(jié)點信息。Twemproxy是twitter開源的,實現(xiàn)這一功能的proxy。這個實現(xiàn)方式在客戶端和服務(wù)器之間加了一個proxy,但這是在redis 3.0穩(wěn)定版本出來之前官方推薦的方式。結(jié)合redis-sentinel的HA方案,是個不錯的組合
總結(jié)
以上是生活随笔為你收集整理的Redis集群:sharding策略的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis:内存满了的解决方案
- 下一篇: Redis集群:哨兵(Sentinel)