Redis集羣的使用測試(Jedis客戶端的使用)java
一、 Jedis客戶端建議升級到最新版(當前爲2.7.3),這樣對3.0.x集羣有比較好的支持。node
https://github.com/xetorthio/jedisgit
http://mvnrepository.com/artifact/redis.clients/jedisgithub
二、 直接在Java代碼中連接Redis集羣:redis
// 數據庫連接池配置數據庫
JedisPoolConfig config = new JedisPoolConfig(); 架構
config.setMaxTotal(100); app
config.setMaxIdle(50); 異步
config.setMinIdle(20); ide
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 = newJedisCluster(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>
</set>
</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 = "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);
}
Redis集羣的高可用性測試
1、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)?
A:若是集羣任意master掛掉,且當前master沒有slave。集羣進入fail狀態,也能夠理解成集羣的slot映射[0-16383]不完整時進入fail狀態。 ps : redis-3.0.0.rc1加入cluster-require-full-coverage參數,默認關閉,打開集羣兼容部分失敗;
B:若是集羣超過半數以上master掛掉,不管是否有slave集羣進入fail狀態。ps:當集羣不可用時,全部對集羣的操做作都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤。
2、客戶端集羣命令
集羣
cluster info:打印集羣的信息
cluster nodes:列出集羣當前已知的全部節點(node),以及這些節點的相關信息。
節點
cluster meet<ip> <port> :將ip和port所指定的節點添加到集羣當中,讓它成爲集羣的一份子。
cluster forget<node_id>:從集羣中移除 node_id 指定的節點。
clusterreplicate <node_id>:將當前節點設置爲node_id指定的節點的從節點。
clustersaveconfig:將節點的配置文件保存到硬盤裏面。
槽(slot)
cluster addslots<slot> [slot ...]:將一個或多個槽(slot)指派(assign)給當前節點。
clusterdelslots <slot> [slot ...]:移除一個或多個槽對當前節點的指派。
clusterflushslots:移除指派給當前節點的全部槽,讓當前節點變成一個沒有指派任何槽的節點。
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 應該被放置在哪一個槽上。
clustercountkeysinslot <slot>:返回槽 slot 目前包含的鍵值對數量。
clustergetkeysinslot <slot> <count>:返回 count 個 slot 槽中的鍵。
3、集羣高可用測試
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/
# cpredis-trib.rb /usr/local/bin/redis-trib
# redis-tribcreate --replicas 1192.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、查看當前集羣各節點的狀態
[root@edu-redis-01 7111]# /usr/local/redis3/bin/redis-cli -c -p 7111
127.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集羣當前狀態(用於接下來作節點狀態變化對比)
(3)關閉其中一個master節點(7111)
(4)觀察該master節點和對應的slave節點的狀態變化
節點狀態 fail? 表示正在判斷是否失敗
節點狀態 fail 表示節點失敗,對應的slave節點提高爲master
(5)再查看集羣狀態變化# /usr/local/src/redis-3.0.3/src/redis-trib.rbcheck 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)查看集羣狀態
其中7111變成 7114的slave
7、觀察集羣節點切換過程當中,對客戶端的影響
JedisCluster連接Redis集羣操做時遇到的幾個常見異常:
(1)重定向次數過多
redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException:Too many Cluster redirections?
解決方法: 初始化JedisCluster時,設定JedisCluster的maxRedirections
//集羣各節點集合,超時時間(默認2秒),最多重定向次數(默認5),連接池
newJedisCluster(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節點)這兩個操做,因此實際中,命令丟失的窗口很是小。
本文參考:http://www.roncoo.com/course/view/f614343765bc4aac8597c6d8b38f06fd