Redis 叢集的高可用測試(含 Jedis 客戶端的使用)
阿新 • • 發佈:2018-12-25
Redis 叢集的使用測試(Jedis 客戶端的使用)
1、 Jedis 客戶端建議升級到最新版(當前為 2.7.3) ,這樣對 3.0.x 叢集有比較好的支援。https://github.com/xetorthio/jedis
http://mvnrepository.com/artifact/redis.clients/jedis
2、 直接在 Java 程式碼中連結 Redis 叢集:// 資料庫連結池配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(100);
config.setMaxIdle(50);
config.setMinIdle(20);
config.setMaxWaitMillis(6 * 1000);
config.setTestOnBorrow(true);
// Redis叢集的節點集合
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort("192.168.1.111", 7111));
jedisClusterNodes.add(new HostAndPort("192.168.1.112", 7112));
jedisClusterNodes.add(new HostAndPort("192.168.1.113", 7113));
jedisClusterNodes.add(new HostAndPort("192.168.1.114", 7114));
jedisClusterNodes.add(new HostAndPort("192.168.1.115", 7115));
jedisClusterNodes.add(new HostAndPort("192.168.1.116", 7116));
// 根據節點集創叢集連結物件
//JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
// 節點,超時時間,最多重定向次數,連結池
JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes, 2000, 100, config);
int num = 1000;
String key = "wusc";
String value = "";
for (int i=1; i <= num; i++){
// 存資料
jedisCluster.set(key+i, "WuShuicheng"+i);
// 取資料
value = jedisCluster.get(key+i);
log.info(key+i + "=" + value);
// 刪除資料
//jedisCluster.del(key+i);
//value = jedisCluster.get(key+i);
//log.info(key+i + "=" + value);
}
3、Spring 配置 Jedis 連結 Redis3.0 叢集的配置:
<!-- Jedis連結池配置,注意:Jedis版本建議升級到最新(當前最新版為2.7.2) -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="20" />
<property name="minIdle" value="10" />
<property name="blockWhenExhausted" value="true"></property>
<property name="maxWaitMillis" value="3000" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<property name="minEvictableIdleTimeMillis" value="60000" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="numTestsPerEvictionRun" value="-1" />
</bean>
<!-- JedisCluster -->
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg index="0">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.1.111" />
<constructor-arg index="1" value="7111" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.1.112" />
<constructor-arg index="1" value="7112" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.1.113" />
<constructor-arg index="1" value="7113" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.1.114" />
<constructor-arg index="1" value="7114" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.1.115" />
<constructor-arg index="1" value="7115" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.1.116" />
<constructor-arg index="1" value="7116" type="int" />
</bean>
</constructor-arg>
<constructor-arg index="1" value="2000" type="int"></constructor-arg>
<constructor-arg index="2" value="100" type="int"></constructor-arg>
<constructor-arg index="3" ref="jedisPoolConfig"></constructor-arg>
</bean>
對應的 Java 呼叫程式碼樣例 :
JedisCluster jedisCluster = (JedisCluster) context.getBean("jedisCluster");
int num = 1000;
String key = "lw";
String value = "";
for (int i=1; i <= num; i++){
// 存資料
jedisCluster.set(key+i, "llw"+i);
// 取資料
value = jedisCluster.get(key+i);
log.info(key+i + "=" + value);
// 刪除資料
//jedisCluster.del(key+i);
}
4、測試操作
一、Redis 叢集特點
1、叢集架構特點:
(1)所有的 redis 節點彼此互聯(PING-PONG 機制),內部使用二進位制協議優化傳輸速度和頻寬;
(2)節點的 fail 是通過叢集中超過半數的節點檢測失效時才生效;
(3)客戶端與 redis 節點直連, 不需要中間 proxy 層。客戶端不需要連線叢集所有節點,連線叢集中任何一
個可用節點即可;
(4)redis-cluster 把所有的物理節點對映到[0-16383]個 slot(雜湊槽)上,cluster 負責維護
node<->slot<->value 。
2、叢集選舉容錯:(1)節點失效選舉過程是叢集中所有 master 參與,如果半數以上 master 節點與當前被檢測 master 節點通
信檢測超時(cluster-node-timeout),就認為當前 master 節點掛掉;
(2):什麼時候整個叢集不可用(cluster_state:fail)?
slot 對映[0-16383]不完整時進入 fail 狀態。 ps : redis-3.0.0.rc1 加入 cluster-require-fullcoverage 引數,預設關閉,開啟叢集相容部分失敗;
B:如果叢集超過半數以上 master 掛掉,無論是否有 slave 叢集進入 fail 狀態。ps:當叢集不可用時,
所有對叢集的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤。
二、客戶端叢集命令
叢集cluster info :列印叢集的資訊
cluster nodes :列出叢集當前已知的所有節點(node),以及這些節點的相關資訊。
節點
cluster meet <ip> <port> :將 ip 和 port 所指定的節點新增到叢集當中,讓它成為叢集的一份子。cluster forget <node_id> :從叢集中移除 node_id 指定的節點。
cluster replicate <node_id> :將當前節點設定為 node_id 指定的節點的從節點。
cluster saveconfig :將節點的配置檔案儲存到硬盤裡面。
槽(slot)
cluster addslots <slot> [slot ...] :將一個或多個槽(slot)指派(assign)給當前節點。cluster delslots <slot> [slot ...] :移除一個或多個槽對當前節點的指派。
cluster flushslots :移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點。
cluster setslot <slot> node <node_id> :將槽 slot 指派給 node_id 指定的節點,如果槽已經指派給
另一個節點,那麼先讓另一個節點刪除該槽>,然後再進行指派。
cluster setslot <slot> migrating <node_id> :將本節點的槽 slot 遷移到 node_id 指定的節點中。
cluster setslot <slot> importing <node_id> :從 node_id 指定的節點中匯入槽 slot 到本節點。
cluster setslot <slot> stable :取消對槽 slot 的匯入(import)或者遷移(migrate)。
鍵
cluster keyslot <key> :計算鍵 key 應該被放置在哪個槽上。cluster countkeysinslot <slot> :返回槽 slot 目前包含的鍵值對數量。
cluster getkeysinslot <slot> <count> :返回 count 個 slot 槽中的鍵。
三、叢集高可用測試
1、重建叢集,步驟:(1)關閉叢集的各節點;
(2)刪除各節點資料目錄下的 nodes.conf、appendonly.aof、dump.rdb;
# rm -rf appendonly.aof | rm -rf dump.rdb | rm -rf nodes.conf
(3)重新啟用所有的節點
192.168.1.111
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7111/redis-7111.conf
192.168.1.112
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7112/redis-7112.conf
192.168.1.113
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7113/redis-7113.conf
192.168.1.114
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7114/redis-7114.conf
192.168.1.115
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7115/redis-7115.conf
192.168.1.116
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7116/redis-7116.conf
(4)執行叢集建立命令(只需要在其中一個節點上執行一次則可)
# cd /usr/local/src/redis-3.0.3/src/
# cp redis-trib.rb /usr/local/bin/redis-trib
# redis-trib create --replicas 1 192.168.1.114:7114 192.168.1.115:7115 192.168.1.116:7116
192.168.1.111:7111 192.168.1.112:7112 192.168.1.113:7113
2、檢視當前叢集各節點的狀態
[[email protected] 7111]# /usr/local/redis3/bin/redis-cli -c -p 7111127.0.0.1:7111> cluster nodes
3、使用 demo 應用向叢集寫入 1000 個鍵值資料
使用 /usr/local/redis3/bin/redis-cli -c -p 711X 命令登入各節點,使用 keys * 檢視各節點的所有key
4、執行 demo 應用,獲取所有的鍵值資料
如果有空值則停止5、模擬叢集節點宕機(實現故障轉移)
(1)Jedis 客戶端迴圈操作叢集資料(模擬使用者持續使用系統)(2)檢視 Redis 叢集當前狀態(用於接下來做節點狀態變化對比)
(4)觀察該 master 節點和對應的 slave 節點的狀態變化
節點狀態 fail 表示節點失敗,對應的 slave 節點提升為 master
(5)再檢視叢集狀態變化# /usr/local/src/redis-3.0.3/src/redis-trib.rb check 192.168.1.116:7116
由上可見,7114 節點替換 7111,由 slave 變成了 master
此時再執行 demo 應用獲取所有的鍵值資料,依然正常,說明 slave 替換 master 成功,叢集正常。
6、恢復 fail 節點
(1)啟動 7111
# /usr/local/redis3/bin/redis-server /usr/local/redis3/cluster/7111/redis-7111.conf
(2)檢視叢集狀態
7、觀察叢集節點切換過程中,對客戶端的影響
JedisCluster 連結 Redis 叢集操作時遇到的幾個常見異常:
(1)重定向次數過多
redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections?
解決方法: 初始化 JedisCluster 時,設定 JedisCluster 的 maxRedirections
//叢集各節點集合,超時時間(預設 2 秒) ,最多重定向次數(預設 5),連結池
new JedisCluster(jedisClusterNodes, 2000, 100, config);
(2)叢集不可以用
redis.clients.jedis.exceptions.JedisClusterException: CLUSTERDOWN The cluster is down
原因:叢集節點狀態切換過程中會出現臨時閃斷,客戶端重試操作則可。
(3)連結超時
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
解決方法: 初始化 JedisCluster 時,設定 JedisCluster 的 timeout (預設為兩秒);也可以修改原始碼中的
預設時間。
7、總結:
優點:
在 master 節點下線後,slave 節點會自動提升為 master 節點,儲存叢集持續提供服務;
fail 節點恢復後,會自動新增到叢集中,變成 slave 節點;
缺點:
由於 redis 的複製使用非同步機制,在自動故障轉移的過程中,叢集可能會丟失寫命令。然而 redis 幾
乎是同時執行(將命令恢復傳送給客戶端,以及將命令複製到 slave 節點)這兩個操作,所以實際中,命令
丟失的視窗非常小。