單機
redis最主要的適用場景:少許數據存儲,高速讀寫訪問,數據所有in-momery 的方式來保證高速訪問,同時提供數據落地的功能。html
分佈式
隨着用戶量的增加,數據量隨之增加,大型網站應用,熱點數據量每每巨大,幾十G上百G是很正常的事兒,這時候咱們須要橫向擴展,多臺主機共同提供服務,既分佈多個redis協同工做。大體有以下幾種集羣方案:java
方案一:Redis官方集羣方案Redis Cluster
Redis Cluster由3.0版本正式推出,是一種服務器sharding技術,對客戶端來講是徹底透明的。node
Redis Cluster中,Sharding採用slot(槽)的概念,一共分紅16384個槽。對於每一個進入Redis的鍵值對,根據key進行散列,分配到這16384個slot中的某一箇中。使用的hash算法也比較簡單,就是CRC16後16384取模。redis
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會返回轉向指令,指向正確的node,這有點兒像瀏覽器頁面的302 redirect跳轉。分佈式
Redis Cluster是Redis 3.0之後才正式推出,時間較晚,目前能證實在大規模生產環境下成功的案例還不是不少,須要時間檢驗。memcached
方案二:Redis Sharding集羣
這種方案把sharding徹底放在客戶端,每一個redis都是獨立的存在,其只要思想是將key進行散列,經過hash函數,不一樣的key映射到指定的redis節點上。
jedis已經很好的支持了redis sharding功能:
JedisShardInfo jedisShardInfo1 = new JedisShardInfo(bundle.getString("redis1.ip"), Integer.valueOf(bundle.getString("redis.port"))); JedisShardInfo jedisShardInfo2 = new JedisShardInfo(bundle.getString("redis2.ip"), Integer.valueOf(bundle.getString("redis.port"))); List list = new LinkedList(); list.add(jedisShardInfo1); list.add(jedisShardInfo2); ShardedJedisPool pool = new ShardedJedisPool(config, list); ShardedJedis jedis = pool.getResource();
此模式下的擴容問題,做者給出瞭解決方案
Redis的做者提出了一種叫作presharding的方案來解決動態擴容和數據分區的問題,實際就是在同一臺機器上部署多個Redis實例的方式,當容量不夠時將多個實例拆分到不一樣的機器上,這樣實際就達到了擴容的效果。
拆分過程以下:
1.在新機器上啓動好對應端口的Redis實例。 2.配置新端口爲待遷移端口的從庫。 3.待複製完成,與主庫完成同步後,切換全部客戶端配置到新的從庫的端口。 4.配置從庫爲新的主庫。 5.移除老的端口實例。 6.重複上述過程遷移好全部的端口到指定服務器上。
redis單點問題
對應單臺redis咱們可使用master/slaver模式,儘可能不要出現單點,可以在master機出現宕機的狀況下,slaver可以從新接管,繼續提供服務。
方案三:代理中間件實現集羣
twemproxy是目前使用最爲普遍的redis代理中間件,twemproxy將客戶端發送過來的請求,進行sharding處理後,轉發給相應的redis服務器,客戶端不直接訪問redis服務器,對客戶端來講,後臺redis集羣是徹底透明的。
twemproxy內部處理是無狀態的,因此它自己能夠很容易的進行集羣,防止出現單點故障。twemproxy後臺不只支持redis,還支持memcached。
固然因爲使用了中間件代理,相比客戶端直接鏈接服務器,性能上會有一點的影響,性能大概下降了20%-30%左右。
基於Twemproxy的Redis集羣方案
方案四:基於Redis的開源分佈式服務Codis
Codis是豌豆莢在以上三種方式都不能很好的解決問題的狀況下,從新開發的基於Redis的開源分佈式服務。
Codis的總體設計:
Pre-sharding slot->[0,1023] Zookeeper Proxy無狀態 平滑擴展和縮容 擴容對用戶透明
能夠看一張總體的架構圖:
總結:每一種方案都有它適用的環境,也沒有哪一種方案是能夠解決任何問題的,方案每每都是根據咱們系統的不斷髮展不斷進行改進的。