Redisの--Redisクラスタの高可用性テストとクラスタ再構築

15606 ワード

転載は出典を明記してください.http://blog.csdn.net/l1028386804/article/details/72669962
このブログは、『Redisの-Redisクラスタのインストール(Redis+CentOS)』に基づいてテストされています.まず、ブログ『Redisの-Redisクラスタのインストール(Redis+CentOS)』を読んでから、このブログの学習実践を行ってください.
一、Redisクラスタの使用テスト(Jedisクライアントの使用)
1、Jedisクライアントは最新版にアップグレードすることを提案する.x.xクラスタは比較的良好なサポートがあります.
https://github.com/xetorthio/jedishttp://mvnrepository.com/artifact/redis.clients/jedis
2.Javaコードに直接Redisクラスタをリンクする
package com.lyz.demo.redis;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 
 * @  : Redis     .
 * @  : liuyazhuang
 * @    : 2017-05-23
 * @   : V1.0 .
 */
public class RedisClusterTest {
	private static final Log log = LogFactory.getLog(RedisClusterTest.class);

	public static void main(String[] args) {
		
		//         
		JedisPoolConfig config = new JedisPoolConfig();  
        config.setMaxTotal(100);  
        config.setMaxIdle(50);  
        config.setMinIdle(20);  
        config.setMaxWaitMillis(6 * 1000);  
        config.setTestOnBorrow(true);  
		
		// Redis       
		Set jedisClusterNodes = new HashSet();
		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 = "lyz";
		String value = "";
		for (int i=1; i <= num; i++){
			//    
			jedisCluster.set(key+i, "liuyazhuang"+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リンクRedis 3.0クラスタの構成
spring-redis.xml



	
	
		
		
		
		
		
		
		
		
		
		
		
	

	
	
		
			
				
					
					
				
				
					
					
				
				
					
					
				
				
					
					
				
				
					
					
				
				
					
					
				
			
		
		
		
		
	

RedisClusterSpringTest.java
package com.lyz.demo.redis;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import redis.clients.jedis.JedisCluster;

/**
 * 
 * @  : Redis       .
 * @  : liuyazhuang
 * @    : 2017-05-23
 * @   : V1.0 .
 */
public class RedisClusterSpringTest {
	private static final Log log = LogFactory.getLog(RedisClusterSpringTest.class);

	public static void main(String[] args) {
		try {
			ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context.xml");
			context.start();
			
			JedisCluster jedisCluster = (JedisCluster) context.getBean("jedisCluster");
			int num = 1000;
			String key = "lyz";
			String value = "";
			for (int i=1; i <= num; i++){
				//    
				//jedisCluster.set(key+i, "liuyazhuang"+i);
				//jedisCluster.setex(key+i, 60, "liuyazhuang"+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);
			}

			context.stop();
		} catch (Exception e) {
			log.error("==>RedisSpringTest context start error:", e);
			System.exit(0);
		} finally {
			log.info("===>System.exit");
			System.exit(0);
		}
	}
}
RedisClusterFailOverTest.java
package com.lyz.demo.redis;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 
 * @  : Redis     .
 * @  : liuyazhuang
 * @    : 2017-05-23
 * @   : V1.0 .
 */
public class RedisClusterFailoverTest {
	private static final Log log = LogFactory.getLog(RedisClusterFailoverTest.class);

	public static void main(String[] args) {
		
		//         
		JedisPoolConfig config = new JedisPoolConfig();  
        config.setMaxTotal(100);  
        config.setMaxIdle(50);  
        config.setMinIdle(20);  
        config.setMaxWaitMillis(6 * 1000);  
        config.setTestOnBorrow(true);  
		
		// Redis       
		Set jedisClusterNodes = new HashSet();
		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));
		
		try {
			
			//             
			//JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
			//        ,    ,       ,   
			JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes, 2000, 100, config);
			int num = 1000;
			String key = "lyz";
			String value = "";
			int count = 1;

			while(true){
				for (int i=1; i <= num; i++){
					try {
						//    
						//jedisCluster.set(key+i, "liuyazhuang"+i); 
						
						//    
						value = jedisCluster.get(key+i); 
						log.info(key+i + "=" + value);
						if (value == null || "".equals(value)){
							log.error("===>break" + key+i + " value is null");
							break;
						}
					} catch (Exception e) {
						log.error("====>", e);
						Thread.sleep(3000);
						continue;
					}
					//     
					//jedisCluster.del(key+i); 
					//value = jedisCluster.get(key+i); 
					//log.info(key+i + "=" + value);
				}
				log.info("===================================>count:" + count);
				if (value == null || "".equals(value)){
					break;
				}
				count++;
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			log.error("====>", e);
		}
		
	}
}

二、Redisクラスターの特徴
1、クラスタアーキテクチャの特徴
(1)すべてのredisノードは互いに相互接続し(PING-PONGメカニズム)、内部でバイナリプロトコルを用いて伝送速度と帯域幅を最適化する.(2)ノードのfailは,クラスタの半数を超えるノードによって失効が検出された場合に有効である.(3)クライアントはredisノードに直結し,中間proxy層を必要としない.クライアントはクラスタのすべてのノードを接続する必要はなく、クラスタ内のいずれかの使用可能なノードを接続すればよい.(4)redis−clusterはすべての物理ノードを[0−16383]個のslot(ハッシュスロット)にマッピングし,clusterはnodeslotvalueのメンテナンスを担当する.
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.rc 1はcluster-require-fullcoverageパラメータを追加し、デフォルトで閉じ、クラスタ互換性部分を開くのに失敗しました.B:クラスタが半数以上masterを切ると、slaveクラスタがfail状態に入るかどうかにかかわらず.ps:クラスタが使用できない場合、クラスタに対する操作はすべて使用できません.CLUSTERDOWN The cluster is downエラーが発生しました.
三、クライアントクラスタコマンド
1、クラスター
cluster info:クラスタの情報を印刷cluster nodes:クラスタで現在知られているすべてのノード(node)と、これらのノードに関する情報をリストします.
2、ノード
cluster meet:ipとportで指定したノードをクラスタに追加し、クラスタの一員にします.cluster forget:クラスタからnodeを削除するid指定ノード.cluster replicate:現在のノードをnode_に設定id指定されたノードのスレーブノード.cluster saveconfig:ノードのプロファイルをハードディスクに保存します.
3、スロット(slot)
cluster addslots [slot ...] :1つ以上のスロット(slot)を現在のノードに割り当てます.cluster delslots [slot ...] :現在のノードに対する1つ以上のスロットの割り当てを削除します.cluster flushslots:現在のノードに割り当てられたすべてのスロットを削除し、現在のノードをスロットが割り当てられていないノードにします.cluster setslot node:スロットslotをnode_に割り当てるid指定されたノードは、スロットが別のノードに割り当てられている場合は、スロット>を別のノードに削除させてから割り当てられます.cluster setslot migrating:本ノードのスロットslotをnode_に移行idで指定したノードにあります.cluster setslot importing:node_からid指定したノードにスロットslotを本ノードにインポートします.cluster setslot stable:スロットslotのインポート(import)または移行(migrate)をキャンセルします.
4、キー
cluster keyslot:キーキーキーがどのスロットに配置されるべきかを計算します.cluster countkeysinslot:スロットslotに現在含まれているキー値ペアの数を返します.cluster getkeysinslot: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)クラスタ作成コマンドを実行する(いずれかのノードで1回実行するだけでよい)
# cd /usr/local/src/redis-3.2.9/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、現在のクラスタの各ノードの状態を表示する
[root@liuyazhuang01 7111]# /usr/local/redis3/bin/redis-cli -c -p 7111 
127.0.0.1:7111> cluster nodes

3.demoアプリケーションを用いて1000個のキー値データをクラスタに書き込む
/usr/local/redis 3/bin/redis-cli-c-p 711 Xコマンドを使用して各ノードにログインし、keys*を使用して各ノードのすべてのkeyを表示します.
4、demoアプリケーションを実行し、すべてのキー値データを取得する
値が空の場合は停止
5、アナログクラスタノードのダウンタイム
(1)JedisClient Cycle Operation Cluster Data(アナログユーザ継続使用システム)(2)Redis Clusterの現在の状態(次のノード状態変化の比較用)
(3)いずれかのマスターノードを閉じる(7111)
(4)このマスターノードと対応するslaveノードの状態変化を観察するRedis之——Redis集群的高可用测试与集群重建_第1张图片
ノードステータスfail?失敗したかどうかを判断しているノード状態failはノードの失敗を表し、対応するslaveノードはmasterに昇格する
(5)クラスタ状態変化#/usr/local/src/redis-3.2.9/src/redis-tribを再確認する.rb check 192.168.1.116:7116
Redis之——Redis集群的高可用测试与集群重建_第2张图片
上から分かるように、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)、リンクプールnew 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を設定します(デフォルトは2秒).ソースコードのデフォルト時間を変更することもできます
8、まとめ
利点:masterノードがオフラインになると、slaveノードは自動的にmasterノードに昇格し、クラスタを保存してサービスを継続する.failノードが回復すると、クラスタに自動的に追加され、slaveノードになります.欠点:redisのレプリケーションは非同期メカニズムを使用するため、自動フェイルオーバ中にクラスタが書き込みコマンドを失う可能性があります.しかしredisは、コマンドリカバリをクライアントに送信し、コマンドをslaveノードにコピーする2つの操作をほぼ同時に実行するため、実際にはコマンドが失われたウィンドウは非常に小さい.