關於Redis集羣方案

爲何集羣?

一般,爲了提升網站響應速度,老是把熱點數據保存在內存中而不是直接從後端數據庫中讀取。Redis是一個很好的Cache工具。大型網站應用,熱點數據量每每巨大,幾十G上百G是很正常的事兒,在這種狀況下,如何正確架構Redis呢?
首先,不管咱們是使用本身的物理主機,仍是使用雲服務主機,內存資源每每是有限制的,scale up不是一個好辦法,咱們須要scale out橫向可伸縮擴展,這須要由多臺主機協同提供服務,即分佈式多個Redis實例協同運行。
其次,目前硬件資源成本下降,多核CPU,幾十G內存的主機很廣泛,對於主進程是單線程工做的Redis,只運行一個實例就顯得有些浪費。同時,管理一個巨大內存不如管理相對較小的內存高效。所以,實際使用中,一般一臺機器上同時跑多個Redis實例。java

方案

1.Redis官方集羣方案 Redis Cluster

Redis Cluster是一種服務器Sharding技術,3.0版本開始正式提供。Redis Cluster中,Sharding採用slot(槽)的概念,一共分紅16384個槽,這有點兒相似前面講的pre sharding思路。對於每一個進入Redis的鍵值對,根據key進行散列,分配到這16384個slot中的某一箇中。使用的hash算法也比較簡單,就是CRC16後16384取模,公式爲CRC16(key) % 16384。Redis集羣中的每一個node(節點)負責分攤這16384個slot中的一部分,也就是說,每一個slot都對應一個node負責處理。當動態添加或減小node節點時,須要將16384個槽作個再分配,槽中的鍵值也要遷移。固然,這一過程,在目前實現中,還處於半自動狀態,須要人工介入。Redis集羣,要保證16384個槽對應的node都正常工做,若是某個node發生故障,那它負責的slots也就失效,整個集羣將不能工做。爲了增長集羣的可訪問性,官方推薦的方案是將node配置成主從結構,即一個master主節點,掛n個slave從節點。這時,若是主節點失效,Redis Cluster會根據選舉算法從slave節點中選擇一個上升爲主節點,整個集羣繼續對外提供服務。這很是相似前篇文章提到的Redis Sharding場景下服務器節點經過Sentinel監控架構成主從結構,只是Redis Cluster自己提供了故障轉移容錯的能力。
Redis Cluster的新節點識別能力、故障判斷及故障轉移能力是經過集羣中的每一個node都在和其它nodes進行通訊,這被稱爲集羣總線(cluster bus)。它們使用特殊的端口號,即對外服務端口號加10000。例如若是某個node的端口號是6379,那麼它與其它nodes通訊的端口號是16379。nodes之間的通訊採用特殊的二進制協議。
對客戶端來講,整個cluster被看作是一個總體,客戶端能夠鏈接任意一個node進行操做,就像操做單一Redis實例同樣,當客戶端操做的key沒有分配到該node上時,就像操做單一Redis實例同樣,當客戶端操做的key沒有分配到該node上時,Redis會返回轉向指令,指向正確的node,這有點兒像瀏覽器頁面的302 redirect跳轉。
Redis Cluster是Redis 3.0之後才正式推出,時間較晚,目前能證實在大規模生產環境下成功的案例還不是不少,須要時間檢驗。node

2.Redis Sharding集羣

Redis 3正式推出了官方集羣技術,解決了多Redis實例協同服務問題。Redis Cluster能夠說是服務端Sharding分片技術的體現,即將鍵值按照必定算法合理分配到各個實例分片上,同時各個實例節點協調溝通,共同對外承擔一致服務。
多Redis實例服務,比單Redis實例要複雜的多,這涉及到定位、協同、容錯、擴容等技術難題。這裏,咱們介紹一種輕量級的客戶端Redis Sharding技術。
Redis Sharding能夠說是Redis Cluster出來以前,業界廣泛使用的多Redis實例集羣方法。其主要思想是採用哈希算法將Redis數據的key進行散列,經過hash函數,特定的key會映射到特定的Redis節點上。這樣,客戶端就知道該向哪一個Redis節點操做數據。Sharding架構如圖:
這裏寫圖片描述
慶幸的是,Java redis客戶端驅動jedis,已支持Redis Sharding功能,即ShardedJedis以及結合緩存池的ShardedJedisPool。
Jedis的Redis Sharding實現具備以下特色:
一、採用一致性哈希算法(consistent hashing),將key和節點name同時hashing,而後進行映射匹配,採用的算法是MURMUR_HASH。採用一致性哈希而不是採用簡單相似哈希求模映射的主要緣由是當增長或減小節點時,不會產生因爲從新匹配形成的rehashing。一致性哈希隻影響相鄰節點key分配,影響量小。
2.爲了不一致性哈希隻影響相鄰節點形成節點分配壓力,ShardedJedis會對每一個Redis節點根據名字(沒有,Jedis會賦予缺省名字)會虛擬化出160個虛擬節點進行散列。根據權重weight,也可虛擬化出160倍數的虛擬節點。用虛擬節點作映射匹配,能夠在增長或減小Redis節點時,key在各Redis節點移動再分配更均勻,而不是隻有相鄰節點受影響。
3.ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag作sharding,這樣經過合理命名key,能夠將一組相關聯的key放入同一個Redis節點,這在避免跨節點訪問相關數據時很重要。mysql

擴容問題

Redis Sharding採用客戶端Sharding方式,服務端Redis仍是一個個相對獨立的Redis實例節點,沒有作任何變更。同時,咱們也不須要增長額外的中間處理組件,這是一種很是輕量、靈活的Redis多實例集羣方法。
Redis Sharding採用客戶端Sharding方式,服務端Redis仍是一個個相對獨立的Redis實例節點,沒有作任何變更。同時,咱們也不須要增長額外的中間處理組件,這是一種很是輕量、靈活的Redis多實例集羣方法。
固然,Redis Sharding這種輕量靈活方式必然在集羣其它能力方面作出妥協。好比擴容,當想要增長Redis節點時,儘管採用一致性哈希,畢竟仍是會有key匹配不到而丟失,這時須要鍵值遷移。
做爲輕量級客戶端sharding,處理Redis鍵值遷移是不現實的,這就要求應用層面容許Redis中數據丟失或從後端數據庫從新加載數據。但有些時候,擊穿緩存層,直接訪問數據庫層,會對系統訪問形成很大壓力。有沒有其它手段改善這種狀況?
Redis做者給出了一個比較討巧的辦法–presharding,即預先根據系統規模儘可能部署好多個Redis實例,這些實例佔用系統資源很小,一臺物理機可部署多個,讓他們都參與sharding,當須要擴容時,選中一個實例做爲主節點,新加入的Redis節點做爲從節點進行數據複製。數據同步後,修改sharding配置,讓指向原實例的Shard指向新機器上擴容後的Redis節點,同時調整新Redis節點爲主節點,原實例可再也不使用。
這樣,咱們的架構模式變成一個Redis節點切片包含一個主Redis和一個備Redis。在主Redis宕機時,備Redis接管過來,上升爲主Redis,繼續提供服務。主備共同組成一個Redis節點,經過自動故障轉移,保證了節點的高可用性。則Sharding架構演變成:
這裏寫圖片描述
Redis Sentinel提供了主備模式下Redis監控、故障轉移功能達到系統的高可用性。git

高訪問量下,即便採用Sharding分片,一個單獨節點仍是承擔了很大的訪問壓力,這時咱們還須要進一步分解。一般狀況下,應用訪問Redis讀操做量和寫操做量差別很大,讀經常是寫的數倍,這時咱們能夠將讀寫分離,並且讀提供更多的實例數。
能夠利用主從模式實現讀寫分離,主負責寫,從負責只讀,同時一主掛多個從。在Sentinel監控下,還能夠保障節點故障的自動監測。github

3.利用代理中間件實現大規模Redis集羣

上面分別介紹了多Redis服務器集羣的兩種方式,它們是基於客戶端sharding的Redis Sharding和基於服務端sharding的Redis Cluster。
客戶端sharding技術其優點在於服務端的Redis實例彼此獨立,相互無關聯,每一個Redis實例像單服務器同樣運行,很是容易線性擴展,系統的靈活性很強。其不足之處在於:redis

  • 因爲sharding處理放到客戶端,規模進步擴大時給運維帶來挑戰。 服務端Redis實例
  • 羣拓撲結構有變化時,每一個客戶端都須要更新調整。
  • 鏈接不能共享,當應用規模增大時,資源浪費制約優化。

服務端sharding的Redis Cluster其優點在於服務端Redis集羣拓撲結構變化時,客戶端不須要感知,客戶端像使用單Redis服務器同樣使用Redis集羣,運維管理也比較方便。
不過Redis Cluster正式版推出時間不長,系統穩定性、性能等都須要時間檢驗,尤爲在大規模使用場合。
能不能結合兩者優點?即能使服務端各實例彼此獨立,支持線性可伸縮,同時sharding又能集中處理,方便統一管理?本篇介紹的Redis代理中間件twemproxy就是這樣一種利用中間件作sharding的技術。
twemproxy處於客戶端和服務器的中間,將客戶端發來的請求,進行必定的處理後(如sharding),再轉發給後端真正的Redis服務器。也就是說,客戶端不直接訪問Redis服務器,而是經過twemproxy代理中間件間接訪問。算法

參照Redis Sharding架構,增長代理中間件的Redis集羣架構以下:
twemproxy中間件的內部處理是無狀態的,它自己能夠很輕鬆地集羣,這樣可避免單點壓力或故障。
twemproxy又叫nutcracker,起源於twitter系統中redis/memcached集羣開發實踐,運行效果良好,後代碼奉獻給開源社區。其輕量高效,採用C語言開發,工程網址是:GitHub - twitter/twemproxy: A fast, light-weight proxy for memcached and redissql

twemproxy後端不只支持redis,同時也支持memcached,這是twitter系統具體環境形成的。
因爲使用了中間件,twemproxy能夠經過共享與後端系統的鏈接,下降客戶端直接鏈接後端服務器的鏈接數量。同時,它也提供sharding功能,支持後端服務器集羣水平擴展。統一運維管理也帶來了方便。
固然,也是因爲使用了中間件代理,相比客戶端直連服務器方式,性能上會有所損耗,實測結果大約下降了20%左右。數據庫

相關文章
相關標籤/搜索