Redis集群模式搭建與原理詳解
前言
在 Redis 3.0 之前,使用 哨兵(sentinel)機(jī)制來(lái)監(jiān)控各個(gè)節(jié)點(diǎn)之間的狀態(tài)。Redis Cluster 是 Redis 的 分布式解決方案,在 3.0 版本正式推出,有效地解決了 Redis 在 分布式 方面的需求。當(dāng)遇到 單機(jī)內(nèi)存、并發(fā)、流量 等瓶頸時(shí),可以采用 Cluster 架構(gòu)方案達(dá)到 負(fù)載均衡 的目的。
本文將從 集群方案、數(shù)據(jù)分布、搭建集群、節(jié)點(diǎn)通信、集群伸縮、請(qǐng)求路由、故障轉(zhuǎn)移、集群運(yùn)維 等幾個(gè)方面介紹 Redis Cluster。
正文
1. Redis集群方案
Redis Cluster 集群模式通常具有 高可用、可擴(kuò)展性、分布式、容錯(cuò) 等特性。Redis 分布式方案一般有兩種:
1.1 客戶端分區(qū)方案
客戶端 就已經(jīng)決定數(shù)據(jù)會(huì)被 存儲(chǔ) 到哪個(gè) redis 節(jié)點(diǎn)或者從哪個(gè) redis 節(jié)點(diǎn) 讀取數(shù)據(jù)。其主要思想是采用 哈希算法 將 Redis 數(shù)據(jù)的 key 進(jìn)行散列,通過(guò) hash 函數(shù),特定的 key會(huì) 映射 到特定的 Redis 節(jié)點(diǎn)上。
客戶端分區(qū)方案 的代表為 Redis Sharding,Redis Sharding 是 Redis Cluster 出來(lái)之前,業(yè)界普遍使用的 Redis 多實(shí)例集群 方法。Java 的 Redis 客戶端驅(qū)動(dòng)庫(kù) Jedis,支持 Redis Sharding 功能,即 ShardedJedis 以及 結(jié)合緩存池 的 ShardedJedisPool。
優(yōu)點(diǎn)
不使用 第三方中間件,分區(qū)邏輯 可控,配置 簡(jiǎn)單,節(jié)點(diǎn)之間無(wú)關(guān)聯(lián),容易 線性擴(kuò)展,靈活性強(qiáng)。
缺點(diǎn)
客戶端 無(wú)法 動(dòng)態(tài)增刪 服務(wù)節(jié)點(diǎn),客戶端需要自行維護(hù) 分發(fā)邏輯,客戶端之間 無(wú)連接共享,會(huì)造成 連接浪費(fèi)。
1.2. 代理分區(qū)方案
客戶端 發(fā)送請(qǐng)求到一個(gè) 代理組件,代理 解析 客戶端 的數(shù)據(jù),并將請(qǐng)求轉(zhuǎn)發(fā)至正確的節(jié)點(diǎn),最后將結(jié)果回復(fù)給客戶端。
優(yōu)點(diǎn):簡(jiǎn)化 客戶端 的分布式邏輯,客戶端 透明接入,切換成本低,代理的 轉(zhuǎn)發(fā) 和 存儲(chǔ) 分離。
缺點(diǎn):多了一層 代理層,加重了 架構(gòu)部署復(fù)雜度 和 性能損耗。
代理分區(qū) 主流實(shí)現(xiàn)的有方案有 Twemproxy 和 Codis。
1.2.1. Twemproxy
Twemproxy 也叫 nutcraker,是 twitter 開(kāi)源的一個(gè) redis 和 memcache 的 中間代理服務(wù)器 程序。Twemproxy 作為 代理,可接受來(lái)自多個(gè)程序的訪問(wèn),按照 路由規(guī)則,轉(zhuǎn)發(fā)給后臺(tái)的各個(gè) Redis 服務(wù)器,再原路返回。Twemproxy 存在 單點(diǎn)故障 問(wèn)題,需要結(jié)合 Lvs 和 Keepalived 做 高可用方案。
優(yōu)點(diǎn):應(yīng)用范圍廣,穩(wěn)定性較高,中間代理層 高可用。
缺點(diǎn):無(wú)法平滑地 水平擴(kuò)容/縮容,無(wú) 可視化管理界面,運(yùn)維不友好,出現(xiàn)故障,不能 自動(dòng)轉(zhuǎn)移。
1.2.2. Codis
Codis 是一個(gè) 分布式 Redis 解決方案,對(duì)于上層應(yīng)用來(lái)說(shuō),連接 Codis-Proxy 和直接連接 原生的 Redis-Server 沒(méi)有的區(qū)別。Codis 底層會(huì) 處理請(qǐng)求的轉(zhuǎn)發(fā),不停機(jī)的進(jìn)行 數(shù)據(jù)遷移 等工作。Codis 采用了無(wú)狀態(tài)的 代理層,對(duì)于 客戶端 來(lái)說(shuō),一切都是透明的。
優(yōu)點(diǎn)
實(shí)現(xiàn)了上層 Proxy 和底層 Redis 的 高可用,數(shù)據(jù)分片 和 自動(dòng)平衡,提供 命令行接口 和 RESTful API,提供 監(jiān)控 和 管理 界面,可以動(dòng)態(tài) 添加 和 刪除 Redis 節(jié)點(diǎn)。
缺點(diǎn)
部署架構(gòu) 和 配置 復(fù)雜,不支持 跨機(jī)房 和 多租戶,不支持 鑒權(quán)管理。
1.3. 查詢路由方案
客戶端隨機(jī)地 請(qǐng)求任意一個(gè) Redis 實(shí)例,然后由 Redis 將請(qǐng)求 轉(zhuǎn)發(fā) 給 正確 的 Redis 節(jié)點(diǎn)。Redis Cluster 實(shí)現(xiàn)了一種 混合形式 的 查詢路由,但并不是 直接 將請(qǐng)求從一個(gè) Redis 節(jié)點(diǎn) 轉(zhuǎn)發(fā) 到另一個(gè) Redis 節(jié)點(diǎn),而是在 客戶端 的幫助下直接 重定向( redirected)到正確的 Redis 節(jié)點(diǎn)。
優(yōu)點(diǎn)
無(wú)中心節(jié)點(diǎn),數(shù)據(jù)按照 槽 存儲(chǔ)分布在多個(gè) Redis 實(shí)例上,可以平滑的進(jìn)行節(jié)點(diǎn) 擴(kuò)容/縮容,支持 高可用 和 自動(dòng)故障轉(zhuǎn)移,運(yùn)維成本低。
缺點(diǎn)
嚴(yán)重依賴 Redis-trib 工具,缺乏 監(jiān)控管理,需要依賴 Smart Client (維護(hù)連接,緩存路由表,MultiOp 和 Pipeline 支持)。Failover 節(jié)點(diǎn)的 檢測(cè)過(guò)慢,不如 中心節(jié)點(diǎn) ZooKeeper 及時(shí)。Gossip 消息具有一定開(kāi)銷。無(wú)法根據(jù)統(tǒng)計(jì)區(qū)分 冷熱數(shù)據(jù)。
2. 數(shù)據(jù)分布
2.1. 數(shù)據(jù)分布理論
分布式數(shù)據(jù)庫(kù) 首先要解決把 整個(gè)數(shù)據(jù)集 按照 分區(qū)規(guī)則 映射到 多個(gè)節(jié)點(diǎn) 的問(wèn)題,即把 數(shù)據(jù)集 劃分到 多個(gè)節(jié)點(diǎn) 上,每個(gè)節(jié)點(diǎn)負(fù)責(zé) 整體數(shù)據(jù) 的一個(gè) 子集。
數(shù)據(jù)分布通常有 哈希分區(qū) 和 順序分區(qū) 兩種方式,對(duì)比如下:
由于 Redis Cluster 采用 哈希分區(qū)規(guī)則,這里重點(diǎn)討論 哈希分區(qū)。常見(jiàn)的 哈希分區(qū) 規(guī)則有幾種,下面分別介紹:
2.1.1. 節(jié)點(diǎn)取余分區(qū)
使用特定的數(shù)據(jù),如 Redis 的 鍵 或 用戶 ID,再根據(jù) 節(jié)點(diǎn)數(shù)量 N 使用公式:hash(key)% N 計(jì)算出 哈希值,用來(lái)決定數(shù)據(jù) 映射 到哪一個(gè)節(jié)點(diǎn)上。
優(yōu)點(diǎn)
這種方式的突出優(yōu)點(diǎn)是 簡(jiǎn)單性,常用于 數(shù)據(jù)庫(kù) 的 分庫(kù)分表規(guī)則。一般采用 預(yù)分區(qū)的方式,提前根據(jù) 數(shù)據(jù)量 規(guī)劃好 分區(qū)數(shù),比如劃分為 512 或 1024 張表,保證可支撐未來(lái)一段時(shí)間的 數(shù)據(jù)容量,再根據(jù) 負(fù)載情況 將 表 遷移到其他 數(shù)據(jù)庫(kù) 中。擴(kuò)容時(shí)通常采用 翻倍擴(kuò)容,避免 數(shù)據(jù)映射 全部被 打亂,導(dǎo)致 全量遷移 的情況。
缺點(diǎn)
當(dāng) 節(jié)點(diǎn)數(shù)量 變化時(shí),如 擴(kuò)容 或 收縮 節(jié)點(diǎn),數(shù)據(jù)節(jié)點(diǎn) 映射關(guān)系 需要重新計(jì)算,會(huì)導(dǎo)致數(shù)據(jù)的 重新遷移。
2.1.2. 一致性哈希分區(qū)
一致性哈希 可以很好的解決 穩(wěn)定性問(wèn)題,可以將所有的 存儲(chǔ)節(jié)點(diǎn) 排列在 收尾相接的 Hash 環(huán)上,每個(gè) key 在計(jì)算 Hash 后會(huì) 順時(shí)針 找到 臨接 的 存儲(chǔ)節(jié)點(diǎn) 存放。而當(dāng)有節(jié)點(diǎn) 加入 或 退出 時(shí),僅影響該節(jié)點(diǎn)在 Hash 環(huán)上 順時(shí)針相鄰 的 后續(xù)節(jié)點(diǎn)。
優(yōu)點(diǎn)
加入 和 刪除 節(jié)點(diǎn)只影響 哈希環(huán) 中 順時(shí)針?lè)较?的 相鄰的節(jié)點(diǎn),對(duì)其他節(jié)點(diǎn)無(wú)影響。
缺點(diǎn)
加減節(jié)點(diǎn) 會(huì)造成 哈希環(huán) 中部分?jǐn)?shù)據(jù) 無(wú)法命中。當(dāng)使用 少量節(jié)點(diǎn) 時(shí),節(jié)點(diǎn)變化 將大范圍影響 哈希環(huán) 中 數(shù)據(jù)映射,不適合 少量數(shù)據(jù)節(jié)點(diǎn) 的分布式方案。普通 的 一致性哈希分區(qū) 在增減節(jié)點(diǎn)時(shí)需要 增加一倍 或 減去一半 節(jié)點(diǎn)才能保證 數(shù)據(jù) 和 負(fù)載的均衡。
注意:因?yàn)?一致性哈希分區(qū) 的這些缺點(diǎn),一些分布式系統(tǒng)采用 虛擬槽 對(duì) 一致性哈希 進(jìn)行改進(jìn),比如 Dynamo 系統(tǒng)。
2.1.3. 虛擬槽分區(qū)
虛擬槽分區(qū) 巧妙地使用了 哈希空間,使用 分散度良好 的 哈希函數(shù) 把所有數(shù)據(jù) 映射 到一個(gè) 固定范圍 的 整數(shù)集合 中,整數(shù)定義為 槽(slot)。這個(gè)范圍一般 遠(yuǎn)遠(yuǎn)大于 節(jié)點(diǎn)數(shù),比如 Redis Cluster 槽范圍是 0 ~ 16383。槽 是集群內(nèi) 數(shù)據(jù)管理 和 遷移 的 基本單位。采用 大范圍槽 的主要目的是為了方便 數(shù)據(jù)拆分 和 集群擴(kuò)展。每個(gè)節(jié)點(diǎn)會(huì)負(fù)責(zé) 一定數(shù)量的槽,如圖所示:
當(dāng)前集群有 5 個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)平均大約負(fù)責(zé) 3276 個(gè) 槽。由于采用 高質(zhì)量 的 哈希算法,每個(gè)槽所映射的數(shù)據(jù)通常比較 均勻,將數(shù)據(jù)平均劃分到 5 個(gè)節(jié)點(diǎn)進(jìn)行 數(shù)據(jù)分區(qū)。Redis Cluster 就是采用 虛擬槽分區(qū)。
- 節(jié)點(diǎn)1: 包含 0 到 3276 號(hào)哈希槽。
- 節(jié)點(diǎn)2:包含 3277 到 6553 號(hào)哈希槽。
- 節(jié)點(diǎn)3:包含 6554 到 9830 號(hào)哈希槽。
- 節(jié)點(diǎn)4:包含 9831 到 13107 號(hào)哈希槽。
- 節(jié)點(diǎn)5:包含 13108 到 16383 號(hào)哈希槽。
這種結(jié)構(gòu)很容易 添加 或者 刪除 節(jié)點(diǎn)。如果 增加 一個(gè)節(jié)點(diǎn) 6,就需要從節(jié)點(diǎn) 1 ~ 5 獲得部分 槽 分配到節(jié)點(diǎn) 6 上。如果想 移除 節(jié)點(diǎn) 1,需要將節(jié)點(diǎn) 1 中的 槽 移到節(jié)點(diǎn) 2 ~ 5 上,然后將 沒(méi)有任何槽 的節(jié)點(diǎn) 1 從集群中 移除 即可。
由于從一個(gè)節(jié)點(diǎn)將 哈希槽 移動(dòng)到另一個(gè)節(jié)點(diǎn)并不會(huì) 停止服務(wù),所以無(wú)論 添加刪除 或者 改變 某個(gè)節(jié)點(diǎn)的 哈希槽的數(shù)量 都不會(huì)造成 集群不可用 的狀態(tài).
2.2. Redis的數(shù)據(jù)分區(qū)
Redis Cluster 采用 虛擬槽分區(qū),所有的 鍵 根據(jù) 哈希函數(shù) 映射到 0~16383 整數(shù)槽內(nèi),計(jì)算公式:slot = CRC16(key)& 16383。每個(gè)節(jié)點(diǎn)負(fù)責(zé)維護(hù)一部分槽以及槽所映射的 鍵值數(shù)據(jù),如圖所示:
2.2.1. Redis虛擬槽分區(qū)的特點(diǎn)
- 解耦 數(shù)據(jù) 和 節(jié)點(diǎn) 之間的關(guān)系,簡(jiǎn)化了節(jié)點(diǎn) 擴(kuò)容 和 收縮 難度。
- 節(jié)點(diǎn)自身 維護(hù)槽的 映射關(guān)系,不需要 客戶端 或者 代理服務(wù) 維護(hù) 槽分區(qū)元數(shù)據(jù)。
- 支持 節(jié)點(diǎn)、槽、鍵 之間的 映射查詢,用于 數(shù)據(jù)路由、在線伸縮 等場(chǎng)景。
2.3. Redis集群的功能限制
Redis 集群相對(duì) 單機(jī) 在功能上存在一些限制,需要 開(kāi)發(fā)人員 提前了解,在使用時(shí)做好規(guī)避。
- key 批量操作 支持有限。
類似 mset、mget 操作,目前只支持對(duì)具有相同 slot 值的 key 執(zhí)行 批量操作。對(duì)于 映射為不同 slot 值的 key 由于執(zhí)行 mget、mget 等操作可能存在于多個(gè)節(jié)點(diǎn)上,因此不被支持。
- key 事務(wù)操作 支持有限。
只支持 多 key 在 同一節(jié)點(diǎn)上 的 事務(wù)操作,當(dāng)多個(gè) key 分布在 不同 的節(jié)點(diǎn)上時(shí) 無(wú)法 使用事務(wù)功能。
- key 作為 數(shù)據(jù)分區(qū) 的最小粒度
不能將一個(gè) 大的鍵值 對(duì)象如 hash、list 等映射到 不同的節(jié)點(diǎn)。
不支持 多數(shù)據(jù)庫(kù)空間
單機(jī) 下的 Redis 可以支持 16 個(gè)數(shù)據(jù)庫(kù)(db0 ~ db15),集群模式 下只能使用 一個(gè) 數(shù)據(jù)庫(kù)空間,即 db0。
- 復(fù)制結(jié)構(gòu) 只支持一層
從節(jié)點(diǎn) 只能復(fù)制 主節(jié)點(diǎn),不支持 嵌套樹(shù)狀復(fù)制 結(jié)構(gòu)。
3. Redis集群搭建
Redis-Cluster 是 Redis 官方的一個(gè) 高可用 解決方案,Cluster 中的 Redis 共有 2^14(16384) 個(gè) slot 槽。創(chuàng)建 Cluster 后,槽 會(huì) 平均分配 到每個(gè) Redis 節(jié)點(diǎn)上。
下面介紹一下本機(jī)啟動(dòng) 6 個(gè) Redis 的 集群服務(wù),并使用 redis-trib.rb 創(chuàng)建 3主3從 的 集群。搭建集群工作需要以下三個(gè)步驟:
3.1. 準(zhǔn)備節(jié)點(diǎn)
Redis 集群一般由 多個(gè)節(jié)點(diǎn) 組成,節(jié)點(diǎn)數(shù)量至少為 6 個(gè),才能保證組成 完整高可用 的集群。每個(gè)節(jié)點(diǎn)需要 開(kāi)啟配置 cluster-enabled yes,讓 Redis 運(yùn)行在 集群模式 下。
Redis 集群的節(jié)點(diǎn)規(guī)劃如下:
注意:建議為集群內(nèi) 所有節(jié)點(diǎn) 統(tǒng)一目錄,一般劃分三個(gè)目錄:conf、data、log,分別存放 配置、數(shù)據(jù) 和 日志 相關(guān)文件。把 6 個(gè)節(jié)點(diǎn)配置統(tǒng)一放在 conf 目錄下。
3.1.1. 創(chuàng)建redis各實(shí)例目錄
- $ sudo mkdir -p /usr/local/redis-cluster
- $ cd /usr/local/redis-cluster
- $ sudo mkdir conf data log
- $ sudo mkdir -p data/redis-6379 data/redis-6389 data/redis-6380 data/redis-6390 data/redis-6381 data/redis-6391
3.1.2. redis配置文件管理
根據(jù)以下 模板 配置各個(gè)實(shí)例的 redis.conf,以下只是搭建集群需要的 基本配置,可能需要根據(jù)實(shí)際情況做修改。
$ sudo mkdir -p /usr/local/redis-cluster
$ cd /usr/local/redis-cluster
$ sudo mkdir conf data log
$ sudo mkdir -p data/redis-6379 data/redis-6389 data/redis-6380 data/redis-6390 data/redis-6381 data/redis-6391
3.1.2. redis配置文件管理
根據(jù)以下 模板 配置各個(gè)實(shí)例的 redis.conf,以下只是搭建集群需要的 基本配置,可能需要根據(jù)實(shí)際情況做修改。
- # redis后臺(tái)運(yùn)行
- daemonize yes
- # 綁定的主機(jī)端口
- bind 127.0.0.1
- # 數(shù)據(jù)存放目錄
- dir /usr/local/redis-cluster/data/redis-6379
- # 進(jìn)程文件
- pidfile /var/run/redis-cluster/${自定義}.pid
- # 日志文件
- logfile /usr/local/redis-cluster/log/${自定義}.log
- # 端口號(hào)
- port 6379
- # 開(kāi)啟集群模式,把注釋#去掉
- cluster-enabled yes
- # 集群的配置,配置文件首次啟動(dòng)自動(dòng)生成
- cluster-config-file /usr/local/redis-cluster/conf/${自定義}.conf
- # 請(qǐng)求超時(shí),設(shè)置10秒
- cluster-node-timeout 10000
- # aof日志開(kāi)啟,有需要就開(kāi)啟,它會(huì)每次寫(xiě)操作都記錄一條日志
- appendonly yes
- redis-6379.conf
- daemonize yes
- bind 127.0.0.1
- dir /usr/local/redis-cluster/data/redis-6379
- pidfile /var/run/redis-cluster/redis-6379.pid
- logfile /usr/local/redis-cluster/log/redis-6379.log
- port 6379
- cluster-enabled yes
- cluster-config-file /usr/local/redis-cluster/conf/node-6379.conf
- cluster-node-timeout 10000
- appendonly yes
- redis-6389.conf
- daemonize yes
- bind 127.0.0.1
- dir /usr/local/redis-cluster/data/redis-6389
- pidfile /var/run/redis-cluster/redis-6389.pid
- logfile /usr/local/redis-cluster/log/redis-6389.log
- port 6389
- cluster-enabled yes
- cluster-config-file /usr/local/redis-cluster/conf/node-6389.conf
- cluster-node-timeout 10000
- appendonly yes
- redis-6380.conf
- daemonize yes
- bind 127.0.0.1
- dir /usr/local/redis-cluster/data/redis-6380
- pidfile /var/run/redis-cluster/redis-6380.pid
- logfile /usr/local/redis-cluster/log/redis-6380.log
- port 6380
- cluster-enabled yes
- cluster-config-file /usr/local/redis-cluster/conf/node-6380.conf
- cluster-node-timeout 10000
- appendonly yes
- redis-6390.conf
- daemonize yes
- bind 127.0.0.1
- dir /usr/local/redis-cluster/data/redis-6390
- pidfile /var/run/redis-cluster/redis-6390.pid
- logfile /usr/local/redis-cluster/log/redis-6390.log
- port 6390
- cluster-enabled yes
- cluster-config-file /usr/local/redis-cluster/conf/node-6390.conf
- cluster-node-timeout 10000
- appendonly yes
redis-port 6381.conf
- daemonize yes
- bind 127.0.0.1
- dir /usr/local/redis-cluster/data/redis-6381
- pidfile /var/run/redis-cluster/redis-6381.pid
- logfile /usr/local/redis-cluster/log/redis-6381.log
- port 6381
- cluster-enabled yes
- cluster-config-file /usr/local/redis-cluster/conf/node-6381.conf
- cluster-node-timeout 10000
- appendonly yes
redis-port 6391.conf
- daemonize yes
- bind 127.0.0.1
- dir /usr/local/redis-cluster/data/redis-6391
- pidfile /var/run/redis-cluster/redis-6391.pid
- logfile /usr/local/redis-cluster/log/redis-6391.log
- port 6391
- cluster-enabled yes
- cluster-config-file /usr/local/redis-cluster/conf/node-6391.conf
- cluster-node-timeout 10000
- appendonly yes
3.2. 環(huán)境準(zhǔn)備
3.2.1. 安裝Ruby環(huán)境
- $ sudo brew install ruby
3.2.2. 準(zhǔn)備rubygem redis依賴
- $ sudo gem install redis
- Password:
- Fetching: redis-4.0.2.gem (100%)
- Successfully installed redis-4.0.2
- Parsing documentation for redis-4.0.2
- Installing ri documentation for redis-4.0.2
- Done installing documentation for redis after 1 seconds
- 1 gem installed
3.2.3. 拷貝redis-trib.rb到集群根目錄
redis-trib.rb 是 redis 官方推出的管理 redis 集群 的工具,集成在 redis 的源碼 src 目錄下,將基于 redis 提供的 集群命令 封裝成 簡(jiǎn)單、便捷、實(shí)用 的 操作工具。
- $ sudo cp /usr/local/redis-4.0.11/src/redis-trib.rb /usr/local/redis-cluster
查看 redis-trib.rb 命令環(huán)境是否正確,輸出如下:
- $ ./redis-trib.rb
- Usage: redis-trib <command> <options> <arguments ...>
- create host1:port1 ... hostN:portN
- --replicas <arg>
- check host:port
- info host:port
- fix host:port
- --timeout <arg>
- reshard host:port
- --from <arg>
- --to <arg>
- --slots <arg>
- --yes
- --timeout <arg>
- --pipeline <arg>
- rebalance host:port
- --weight <arg>
- --auto-weights
- --use-empty-masters
- --timeout <arg>
- --simulate
- --pipeline <arg>
- --threshold <arg>
- add-node new_host:new_port existing_host:existing_port
- --slave
- --master-id <arg>
- del-node host:port node_id
- set-timeout host:port milliseconds
- call host:port command arg arg .. arg
- import host:port
- --from <arg>
- --copy
- --replace
- help (show this help)
- For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
redis-trib.rb 是 redis 作者用 ruby 完成的。redis-trib.rb 命令行工具 的具體功能如下:
3.3. 安裝集群
3.3.1. 啟動(dòng)redis服務(wù)節(jié)點(diǎn)
運(yùn)行如下命令啟動(dòng) 6 臺(tái) redis 節(jié)點(diǎn):
- sudo redis-server conf/redis-6379.conf
- sudo redis-server conf/redis-6389.conf
- sudo redis-server conf/redis-6380.conf
- sudo redis-server conf/redis-6390.conf
- sudo redis-server conf/redis-6381.conf
- sudo redis-server conf/redis-6391.conf
啟動(dòng)完成后,redis 以集群模式啟動(dòng),查看各個(gè) redis 節(jié)點(diǎn)的進(jìn)程狀態(tài):
- $ ps -ef | grep redis-server
- 0 1908 1 0 4:59下午 ?? 0:00.01 redis-server *:6379 [cluster]
- 0 1911 1 0 4:59下午 ?? 0:00.01 redis-server *:6389 [cluster]
- 0 1914 1 0 4:59下午 ?? 0:00.01 redis-server *:6380 [cluster]
- 0 1917 1 0 4:59下午 ?? 0:00.01 redis-server *:6390 [cluster]
- 0 1920 1 0 4:59下午 ?? 0:00.01 redis-server *:6381 [cluster]
- 0 1923 1 0 4:59下午 ?? 0:00.01 redis-server *:6391 [cluster]
在每個(gè) redis 節(jié)點(diǎn)的 redis.conf 文件中,我們都配置了 cluster-config-file 的文件路徑,集群?jiǎn)?dòng)時(shí),conf 目錄會(huì)新生成 集群 節(jié)點(diǎn)配置文件。查看文件列表如下:
- $ tree -L 3 .
- .
- ├── appendonly.aof
- ├── conf
- │ ├── node-6379.conf
- │ ├── node-6380.conf
- │ ├── node-6381.conf
- │ ├── node-6389.conf
- │ ├── node-6390.conf
- │ ├── node-6391.conf
- │ ├── redis-6379.conf
- │ ├── redis-6380.conf
- │ ├── redis-6381.conf
- │ ├── redis-6389.conf
- │ ├── redis-6390.conf
- │ └── redis-6391.conf
- ├── data
- │ ├── redis-6379
- │ ├── redis-6380
- │ ├── redis-6381
- │ ├── redis-6389
- │ ├── redis-6390
- │ └── redis-6391
- ├── log
- │ ├── redis-6379.log
- │ ├── redis-6380.log
- │ ├── redis-6381.log
- │ ├── redis-6389.log
- │ ├── redis-6390.log
- │ └── redis-6391.log
- └── redis-trib.rb
- 9 directories, 20 files
3.3.2. redis-trib關(guān)聯(lián)集群節(jié)點(diǎn)
按照 從主到從 的方式 從左到右 依次排列 6 個(gè) redis 節(jié)點(diǎn)。
- $ sudo ./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6389 127.0.0.1:6390 127.0.0.1:6391
集群創(chuàng)建后,redis-trib 會(huì)先將 16384 個(gè) 哈希槽 分配到 3 個(gè) 主節(jié)點(diǎn),即 redis-6379,redis-6380 和 redis-6381。然后將各個(gè) 從節(jié)點(diǎn) 指向 主節(jié)點(diǎn),進(jìn)行 數(shù)據(jù)同步。
- >>> Creating cluster
- >>> Performing hash slots allocation on 6 nodes...
- Using 3 masters:
- 127.0.0.1:6379
- 127.0.0.1:6380
- 127.0.0.1:6381
- Adding replica 127.0.0.1:6390 to 127.0.0.1:6379
- Adding replica 127.0.0.1:6391 to 127.0.0.1:6380
- Adding replica 127.0.0.1:6389 to 127.0.0.1:6381
- >>> Trying to optimize slaves allocation for anti-affinity
- [WARNING] Some slaves are in the same host as their master
- M: ad4b9ffceba062492ed67ab336657426f55874b7 127.0.0.1:6379
- slots:0-5460 (5461 slots) master
- M: df23c6cad0654ba83f0422e352a81ecee822702e 127.0.0.1:6380
- slots:5461-10922 (5462 slots) master
- M: ab9da92d37125f24fe60f1f33688b4f8644612ee 127.0.0.1:6381
- slots:10923-16383 (5461 slots) master
- S: 25cfa11a2b4666021da5380ff332b80dbda97208 127.0.0.1:6389
- replicates ad4b9ffceba062492ed67ab336657426f55874b7
- S: 48e0a4b539867e01c66172415d94d748933be173 127.0.0.1:6390
- replicates df23c6cad0654ba83f0422e352a81ecee822702e
- S: d881142a8307f89ba51835734b27cb309a0fe855 127.0.0.1:6391
- replicates ab9da92d37125f24fe60f1f33688b4f8644612ee
- 然后輸入 yes,redis-trib.rb 開(kāi)始執(zhí)行 節(jié)點(diǎn)握手 和 槽分配 操作,輸出如下:
- Can I set the above configuration? (type 'yes' to accept): yes
- >>> Nodes configuration updated
- >>> Assign a different config epoch to each node
- >>> Sending CLUSTER MEET messages to join the cluster
- Waiting for the cluster to join....
- >>> Performing Cluster Check (using node 127.0.0.1:6379)
- M: ad4b9ffceba062492ed67ab336657426f55874b7 127.0.0.1:6379
- slots:0-5460 (5461 slots) master
- 1 additional replica(s)
- M: ab9da92d37125f24fe60f1f33688b4f8644612ee 127.0.0.1:6381
- slots:10923-16383 (5461 slots) master
- 1 additional replica(s)
- S: 48e0a4b539867e01c66172415d94d748933be173 127.0.0.1:6390
- slots: (0 slots) slave
- replicates df23c6cad0654ba83f0422e352a81ecee822702e
- S: d881142a8307f89ba51835734b27cb309a0fe855 127.0.0.1:6391
- slots: (0 slots) slave
- replicates ab9da92d37125f24fe60f1f33688b4f8644612ee
- M: df23c6cad0654ba83f0422e352a81ecee822702e 127.0.0.1:6380
- slots:5461-10922 (5462 slots) master
- 1 additional replica(s)
- S: 25cfa11a2b4666021da5380ff332b80dbda97208 127.0.0.1:6389
- slots: (0 slots) slave
- replicates ad4b9ffceba062492ed67ab336657426f55874b7
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
執(zhí)行 集群檢查,檢查各個(gè) redis 節(jié)點(diǎn)占用的 哈希槽(slot)的個(gè)數(shù)以及 slot 覆蓋率。16384 個(gè)槽位中,主節(jié)點(diǎn) redis-6379、redis-6380 和 redis-6381 分別占用了 5461、5461 和 5462 個(gè)槽位。
3.3.3. redis主節(jié)點(diǎn)的日志
可以發(fā)現(xiàn),通過(guò) BGSAVE 命令,從節(jié)點(diǎn) redis-6389 在 后臺(tái) 異步地從 主節(jié)點(diǎn)redis-6379 同步數(shù)據(jù)。
- $ cat log/redis-6379.log
- 1907:C 05 Sep 16:59:52.960 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
- 1907:C 05 Sep 16:59:52.961 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1907, just started
- 1907:C 05 Sep 16:59:52.961 # Configuration loaded
- 1908:M 05 Sep 16:59:52.964 * Increased maximum number of open files to 10032 (it was originally set to 256).
- 1908:M 05 Sep 16:59:52.965 * No cluster configuration found, I'm ad4b9ffceba062492ed67ab336657426f55874b7
- 1908:M 05 Sep 16:59:52.967 * Running mode=cluster, port=6379.
- 1908:M 05 Sep 16:59:52.967 # Server initialized
- 1908:M 05 Sep 16:59:52.967 * Ready to accept connections
- 1908:M 05 Sep 17:01:17.782 # configEpoch set to 1 via CLUSTER SET-CONFIG-EPOCH
- 1908:M 05 Sep 17:01:17.812 # IP address for this node updated to 127.0.0.1
- 1908:M 05 Sep 17:01:22.740 # Cluster state changed: ok
- 1908:M 05 Sep 17:01:23.681 * Slave 127.0.0.1:6389 asks for synchronization
- 1908:M 05 Sep 17:01:23.681 * Partial resynchronization not accepted: Replication ID mismatch (Slave asked for '4c5afe96cac51cde56039f96383ea7217ef2af41', my replication IDs are '037b661bf48c80c577d1fa937ba55367a3692921' and '0000000000000000000000000000000000000000')
- 1908:M 05 Sep 17:01:23.681 * Starting BGSAVE for SYNC with target: disk
- 1908:M 05 Sep 17:01:23.682 * Background saving started by pid 1952
- 1952:C 05 Sep 17:01:23.683 * DB saved on disk
- 1908:M 05 Sep 17:01:23.749 * Background saving terminated with success
- 1908:M 05 Sep 17:01:23.752 * Synchronization with slave 127.0.0.1:6389 succeeded
3.3.4. redis集群完整性檢測(cè)
使用 redis-trib.rb check 命令檢測(cè)之前創(chuàng)建的 兩個(gè)集群 是否成功,check 命令只需要給出集群中 任意一個(gè)節(jié)點(diǎn)地址 就可以完成 整個(gè)集群 的 檢查工作,命令如下:
- $ ./redis-trib.rb check 127.0.0.1:6379
當(dāng)最后輸出如下信息,提示集群 所有的槽 都已分配到節(jié)點(diǎn):
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
小結(jié)
本文介紹了 Redis 集群解決方案,數(shù)據(jù)分布 和 集群搭建。集群方案包括 客戶端分區(qū) 方案,代理分區(qū) 方案 和 查詢路由 方案。數(shù)據(jù)分布 部分簡(jiǎn)單地對(duì) 節(jié)點(diǎn)取余 分區(qū),一致性哈希 分區(qū)以及 虛擬槽 分區(qū)進(jìn)行了闡述和對(duì)比。最后對(duì)使用 Redis-trib 搭建了一個(gè) 三主三從 的 虛擬槽 集群示例。