Redis集群的高可用測試(含Jedis客戶端的使用)
04-28
Redis集群的使用測試(Jedis客戶端的使用)1、Jedis客戶端建議升級到最新版(當前為2.7.3),這樣對3.0.x集群有比較好的支持。https://github.com/xetorthio/jedishttp://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 = 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);http://log.info(key+i + "=" + value);// 刪除數據
//jedisCluster.del(key+i);//value = jedisCluster.get(key+i);//http://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);http://log.info(key+i + "=" + value);// 刪除數據//jedisCluster.del(key+i);}Redis集群的高可用性測試一、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)錯誤。二、客戶端集群命令集群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 槽中的鍵。三、集群高可用測試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.conf192.168.1.112# /usr/local/redis3/bin/redis-server/usr/local/redis3/cluster/7112/redis-7112.conf192.168.1.113# /usr/local/redis3/bin/redis-server/usr/local/redis3/cluster/7113/redis-7113.conf192.168.1.114# /usr/local/redis3/bin/redis-server/usr/local/redis3/cluster/7114/redis-7114.conf192.168.1.115# /usr/local/redis3/bin/redis-server/usr/local/redis3/cluster/7115/redis-7115.conf192.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:7111192.168.1.112:7112 192.168.1.113:71132、查看當前集群各節點的狀態[root@edu-redis-01 7111]# /usr/local/redis3/bin/redis-cli -c -p 7111127.0.0.1:7111> cluster nodes3、使用demo應用向集群寫入1000個鍵值數據使用 /usr/local/redis3/bin/redis-cli-c -p 711X命令登錄各節點,使用 keys *查看各節點的所有key4、運行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的slave7、觀察集群節點切換過程中,對客戶端的影響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
推薦閱讀: