redis-cluster是近年來redis架構不斷改進中的相對較好的redis高可用方案。本文涉及到近年來redis多實例架構的演變過程,包括普通主從架構(Master、slave可進行寫讀分離)、哨兵模式下的主從架構、redis-cluster高可用架構(redis官方默認cluster下不進行讀寫分離)的簡介。同時還介紹使用Java的兩大redis客戶端:Jedis與Lettuce用於讀寫redis-cluster的數據的通常方法。再經過官方文檔以及互聯網的相關技術文檔,給出redis-cluster架構下的讀寫能力的優化方案,包括官方的推薦的擴展redis-cluster下的Master數量以及非官方默認的redis-cluster的讀寫分離方案,案例中使用Lettuce的特定方法進行redis-cluster架構下的數據讀寫分離。java
redis是基於內存的高性能key-value數據庫,若要讓redis的數據更穩定安全,須要引入多實例以及相關的高可用架構。而近年來redis的高可用架構亦不斷改進,前後出現了本地持久化、主從備份、哨兵模式、redis-cluster羣集高可用架構等等方案。node
經過持久化功能,Redis保證了即便在服務器重啓的狀況下也不會損失(或少許損失)數據,由於持久化會把內存中數據保存到硬盤上,重啓會從硬盤上加載數據。 。可是因爲數據是存儲在一臺服務器上的,若是這臺服務器出現硬盤故障等問題,也會致使數據丟失。爲了不單點故障,一般的作法是將數據庫複製多個副本以部署在不一樣的服務器上,這樣即便有一臺服務器出現故障,其餘服務器依然能夠繼續提供服務。爲此, Redis 提供了複製(replication)功能,能夠實現當一臺數據庫中的數據更新後,自動將更新的數據同步到其餘數據庫上。redis
在複製的概念中,數據庫分爲兩類,一類是主數據庫(master),另外一類是從數據庫(slave)。主數據庫能夠進行讀寫操做,當寫操做致使數據變化時會自動將數據同步給從數據庫。而從數據庫通常是隻讀的,並接受主數據庫同步過來的數據。一個主數據庫能夠擁有多個從數據庫,而一個從數據庫只能擁有一個主數據庫。
算法
主從模式的配置,通常只須要再做爲slave的redis節點的conf文件上加入「slaveof masterip masterport」, 或者做爲slave的redis節點啓動時使用以下參考命令:數據庫
redis-server --port 6380 --slaveof masterIp masterPort
redis的普通主從模式,能較好地避免單獨故障問題,以及提出了讀寫分離,下降了Master節點的壓力。互聯網上大多數的對redis讀寫分離的教程,都是基於這一模式或架構下進行的。但實際上這一架構並不是是目前最好的redis高可用架構。緩存
主從複製過程見下圖安全
Redis Sentinel 是一個分佈式系統, 你能夠在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來接收關於主服務器是否下線的信息, 並使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪一個從服務器做爲新的主服務器。服務器
能夠用info replication查看主從狀況 例子: 1主2從 1哨兵,能夠用命令起也能夠用配置文件裏 可使用雙哨兵,更安全,參考命令以下:架構
redis-server --port 6379
redis-server --port 6380 --slaveof 192.168.0.167 6379
redis-server --port 6381 --slaveof 192.168.0.167 6379
redis-sentinel sentinel.conf
其中,哨兵配置文件sentinel.conf參考以下:app
sentinel monitor mymaster 192.168.0.167 6379 1
其中mymaster表示要監控的主數據庫的名字。配置哨兵監控一個系統時,只須要配置其監控主數據庫便可,哨兵會自動發現全部複製該主數據庫的從數據庫。
Master與slave的切換過程:
即便使用哨兵,redis每一個實例也是全量存儲,每一個redis存儲的內容都是完整的數據,浪費內存且有木桶效應。爲了最大化利用內存,能夠採用cluster羣集,就是分佈式存儲。即每臺redis存儲不一樣的內容。
採用redis-cluster架構正是知足這種分佈式存儲要求的集羣的一種體現。redis-cluster架構中,被設計成共有16384個hash slot。每一個master分得一部分slot,其算法爲:hash_slot = crc16(key) mod 16384 ,這就找到對應slot。採用hash slot的算法,其實是解決了redis-cluster架構下,有多個master節點的時候,數據如何分佈到這些節點上去。key是可用key,若是有{}則取{}內的做爲可用key,不然整個能夠是可用key。羣集至少須要3主3從,且每一個實例使用不一樣的配置文件。
在redis-cluster架構中,redis-master節點通常用於接收讀寫,而redis-slave節點則通常只用於備份,其與對應的master擁有相同的slot集合,若某個redis-master意外失效,則再將其對應的slave進行升級爲臨時redis-master。
在redis的官方文檔中,對redis-cluster架構上,有這樣的說明:在cluster架構下,默認的,通常redis-master用於接收讀寫,而redis-slave則用於備份,當有請求是在向slave發起時,會直接重定向到對應key所在的master來處理。但若是不介意讀取的是redis-cluster中有可能過時的數據而且對寫請求不感興趣時,則亦可經過readonly命令,將slave設置成可讀,而後經過slave獲取相關的key,達到讀寫分離。
具體能夠參閱redis官方文檔(https://redis.io/commands/readonly)等相關內容:
Enables read queries for a connection to a Redis Cluster slave node. Normally slave nodes will redirect clients to the authoritative master for the hash slot involved in a given command, however clients can use slaves in order to scale reads using the READONLY command. READONLY tells a Redis Cluster slave node that the client is willing to read possibly stale data and is not interested in running write queries. When the connection is in readonly mode, the cluster will send a redirection to the client only if the operation involves keys not served by the slave's master node. This may happen because: The client sent a command about hash slots never served by the master of this slave. The cluster was reconfigured (for example resharded) and the slave is no longer able to serve commands for a given hash slot.
例如,咱們假設已經創建了一個三主三從的redis-cluster架構,其中A、B、C節點都是redis-master節點,A一、B一、C1節點都是對應的redis-slave節點。在咱們只有master節點A,B,C的狀況下,對應redis-cluster若是節點B失敗,則羣集沒法繼續,由於咱們沒有辦法再在節點B的所具備的約三分之一的hash slot集合範圍內提供相對應的slot。然而,若是咱們爲每一個主服務器節點添加一個從服務器節點,以便最終集羣由做爲主服務器節點的A,B,C以及做爲從服務器節點的A1,B1,C1組成,那麼若是節點B發生故障,系統可以繼續運行。節點B1複製B,而且B失效時,則redis-cluster將促使B的從節點B1做爲新的主服務器節點而且將繼續正確地操做。但請注意,若是節點B和B1在同一時間發生故障,則Redis羣集沒法繼續運行。
Redis羣集配置參數:在繼續以前,讓咱們介紹一下Redis Cluster在redis.conf文件中引入的配置參數。有些命令的意思是顯而易見的,有些命令在你閱讀下面的解釋後纔會更加清晰。
如下是最小的Redis集羣配置文件:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
注意: