redis高可用性スキームredis sentinelの紹介と実践

73629 ワード

シナリオの紹介
まずredis高可用性スキームsentinelについていくつか紹介します.redisの基本的な使用と各種の概念原理の内容は比較的に多く,本稿では展開しない.1冊の本を推薦して、本文の中の内容も主にこの本の中から学ぶことができます.
**『Redis開発と運維』付磊張益軍編著**
redis sentinelはredisが公式に提供する高可用性スキームである.主な機能はredisの主従レプリケーションに基づいて,ノード障害検出,主ノード選挙,障害切替などの機能を提供する.サービスが単一のredisノードのダウンタイムによって障害を起こさないことを保証します.
まず、プライマリ・スレーブ・レプリケーションについて説明します.プライマリ・スレーブ・レプリケーションは、複数のredisサービスをプライマリ・ノードとスレーブ・ノードに分割し、プライマリ・ノードはデータの書き込みと、新しいデータを所属するスレーブ・ノードに同期します.
プライマリスレーブレプリケーションの基本原理は,初回レプリケーション時にプライマリノードがrdbデータファイルを保存し,スレーブノードに送信し,ノードから読み出したデータをデータ同期することである.rdbファイルの後のファイルマスターノードは、増加するたびに、バッファからスレーブノードに送信されてインクリメンタル同期されるバッファを保持する.
redisのプライマリスレーブレプリケーショントポロジーには、プライマリスレーブ、プライマリマルチスレーブ、ツリーマスタースレーブがあります.ここでは,よく用いられる一主多従構造について論じる.構造図は次のとおりです.
redisは,ノードの主従関係を維持するために,スレーブノードで以下の構成を用いる限り,主ノードを指定することができる.
slaveof {masterIP} {masterPort}
masterauth {masterPassword}

主従関係を切断すると、ノードから次のコマンドが実行されます.
 slaveof no one

プライマリ・スレーブ・レプリケーション・モードでは、プライマリ・ノードのデータはスレーブ・ノードに同期され続けます.プライマリノードに障害が発生し、サービスが提供されない場合は、ノードからプライマリノードに切り替えてデータの読み書きを継続するサービスを探すことができます.また,各ノードの主従関係を調整し,スレーブノードを主ノードとし,残りのスレーブノードが指す主ノードもそれに応じて調整する.
ノードからプライマリノードに切り替える操作と、プライマリ・セカンダリ・トポロジー関係を調整する操作は複雑で、手作業で調整するのに時間がかかり、タイムリーではありません.従ってredisはsentinelコンポーネントを公式に提供し,このプロセスを自動化した.
導入プロセス
次にdockerコンテナを使用して3つのredisおよびsentinelノードを配置し、redisのプライマリ・スレーブ・レプリケーションおよびフェイルオーバの実装を説明します.
redisは、プライマリ・セカンダリのプライマリ・セカンダリ・レプリケーション構造を使用します.sentinelノードは3つのノードを配置します.sentinelの数が3なのは理由があります.これは、プライマリノードのダウンタイムを認定し、新しいプライマリノードを選択する際に、半分以上(半分を除く)のsentinelノードが参加する必要があるためです.したがって、3つのノードは、単一の導入を回避する最小の数です.
すべてのノードの配置にはdockerが使用されます.各ノードの詳細は次のとおりです.
ロール#ロール#
ポート
説明
master
6380
redisプライマリノード
slave-1
6381
redisスレーブノード1
slave-2
6382
redisスレーブノード2
sentinel-1
26380
sentinelノード1
sentinel-2
26381
sentinelノード2
sentinel-3
26382
sentinelノード3
トポロジーは次のとおりです.
![](/home/markfengfeng/ダウンロード/未命名ファイル(1).png)
プライマリ・セカンダリ・レプリケーションの導入
まずredisノードを配置し、主従関係を構成します.
主従構成に基づいてredisの構成ファイルを3部修正します.slave-1,slace-2はmasterノードのスレーブノードである.slaveof {masterip} {masterport}構成でマスターをプライマリノードとして指定します.重要な構成項目は次のとおりです.
マスターノードconf
#   IP
bind 0.0.0.0
#    
port 6380
#    
requirepass password
masterauth password

slave-1ノード、slave-1.conf
bind 0.0.0.0
port 6381
requirepass password
#master   IP   
slaveof 172.17.0.1 6380
#master     
masterauth password

slave-2ノード、slave-2.conf
bind 0.0.0.0
requirepass password
port 6382
slaveof 172.17.0.1 6380
masterauth password

dockerデプロイメントコマンドは、次のとおりです.プロファイルはdockerコンテナにマッピングされます.
docker run --name master -v /data/redis/master.conf:/usr/local/etc/redis/redis.conf -p 6380:6380 -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf

docker run --name slave-1 -v /data/redis/slave-1.conf:/usr/local/etc/redis/redis.conf -p 6381:6381 -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf

docker run --name slave-2 -v /data/redis/slave-2.conf:/usr/local/etc/redis/redis.conf -p 6382:6382 -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf

**注意事項**
  • すべてのノードパスワード構成は同じで、sentinelがプライマリノードパスワードを構成するため、異なる場合は正常に切り替えることができません.
  • プライマリノードもmasterauthを構成する必要があります.現在のプライマリノードは、障害とリカバリが発生した後、ノードから切り替える可能性があるためです.
  • redisポートとdockerマッピングのポートは一致している必要があります.プライマリノードは,スレーブノードを探す際にノードのredisポートから探すが,ポートが一致せず,スレーブノードが見つからない.
  • プロファイルの1つであるrename-command CONFIG "Sstarnetpbx"は、後でsentinelが障害ノードを切り替えることに影響します.
  • データの一貫性を保証するために、ノードから書き込み機能が提供されず、プロファイルにslave-read-only yesを追加するには、一般的にデフォルトの構成項目があり、変更する必要はありません.

  • デプロイが完了すると、info replicationコマンドを使用してredisのプライマリ・セカンダリ・サービス情報を表示できます.
    プライマリノード
    markfengfeng@markfengfeng:~$ redis-cli -p 6380 -a password6380
    127.0.0.1:6380> info replication
    # Replication
    role:master	#                                                      
    connected_slaves:2 #        
    slave0:ip=172.17.0.1,port=6381,state=online,offset=28,lag=1 #   1    ,  ,     ,  
    slave1:ip=172.17.0.1,port=6382,state=online,offset=28,lag=1 #   2    ,  ,     ,  
    master_replid:73e9036c293329e91c87f719794d0095438c6154
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:28
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:28
    

    2つのスレーブノード
    markfengfeng@markfengfeng:~$ redis-cli -p 6381 -a password6381
    127.0.0.1:6381> info replication
    # Replication
    role:slave  	#           
    master_host:172.17.0.1 #     
    master_port:6380 #     
    master_link_status:up #       
    master_last_io_seconds_ago:8
    master_sync_in_progress:0
    slave_repl_offset:1652
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:73e9036c293329e91c87f719794d0095438c6154
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:1652
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:1652
    127.0.0.1:6381> exit
    markfengfeng@markfengfeng:~$ redis-cli -p 6382 -a password6382
    127.0.0.1:6382> info replication
    # Replication
    role:slave
    master_host:172.17.0.1
    master_port:6380
    master_link_status:up
    master_last_io_seconds_ago:5
    master_sync_in_progress:0
    slave_repl_offset:1708
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:73e9036c293329e91c87f719794d0095438c6154
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:1708
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:15
    repl_backlog_histlen:1694
    
    

    プライマリ・スレーブ・ノードのレプリケーション情報から、プライマリ・スレーブ・ノードの構成が成功したことがわかります.
    主従レプリケーションテスト
    主従同期の機能をテストします.
    プライマリノードでのデータ追加コマンドの実行
    markfengfeng@markfengfeng:~$ redis-cli -p 6380 -a password6380
    127.0.0.1:6380> set name xiehuafeng
    OK
    127.0.0.1:6380> get name
    "xiehuafeng"
    127.0.0.1:6380> 
    

    ノードからのデータの表示
    markfengfeng@markfengfeng:~$ redis-cli -p 6381 -a password6381
    127.0.0.1:6381> get name
    "xiehuafeng"
    127.0.0.1:6381> exit
    markfengfeng@markfengfeng:~$ redis-cli -p 6382 -a password6382
    127.0.0.1:6382> get name
    "xiehuafeng"
    

    プライマリノードのデータがスレーブノードに同期できることがわかる.
    sentinel配備
    次にsentinelノードを配置します.同様にdockerコンテナを使用して配置します.
    3つのノードを配置しますが、ポートが異なる以外は同じ構成です.Redisノードアドレスを構成するには、プライマリノードアドレスを使用します.redis自体はGossipプロトコルを用い,masterノードを介してmasterノード上のスレーブノード情報とsentinelノード情報を各sentinelに提供する.
    次のように構成されています.
    sentinel-1ノード
    port 26380   #sentinel   
    sentinel monitor master 172.17.0.1 6380 2  #   redis          ,2      sentinel             
    sentinel auth-pass master password  #      
    sentinel down-after-milliseconds master 30000   #     30  ,        
    sentinel parallel-syncs master 1  #        ,              
    

    sentinel-2ノード
    port 26381
    sentinel monitor master 172.17.0.1 6380 2
    sentinel auth-pass master password
    sentinel down-after-milliseconds master 30000
    sentinel parallel-syncs master 1
    

    sentinel-3ノード
    port 26382
    sentinel monitor master 172.17.0.1 6380 2
    sentinel auth-pass master password
    sentinel down-after-milliseconds master 30000
    sentinel parallel-syncs master 1
    

    dockerデプロイメントコマンドは、docker hubから私のdockerミラーをダウンロードします.すべての構成項目をコンテナの環境変数として構成します.したがって、上記の構成項目はdocker配置コマンドの環境変数に反映されます.
    
    docker  run --name sentinel-1 -p 26380:26380 -e SENTINEL_PORT=26380 -e MASTER_NAME=master -e QUORUM=2 -e DOWN_AFTER=30000 -e PARALLEL_SYNCS=1 -e MASTER=172.17.0.1:6380 -e AUTH_PASS=password -d s7anley/redis-sentinel-docker
    
    docker  run --name sentinel-2 -p 26381:26381 -e SENTINEL_PORT=26381 -e MASTER_NAME=master -e QUORUM=2 -e DOWN_AFTER=30000 -e PARALLEL_SYNCS=1 -e MASTER=172.17.0.1:6380 -e AUTH_PASS=password -d s7anley/redis-sentinel-docker
    
    docker  run --name sentinel-3 -p 26382:26382 -e SENTINEL_PORT=26382 -e MASTER_NAME=master -e QUORUM=2 -e DOWN_AFTER=30000 -e PARALLEL_SYNCS=1 -e MASTER=172.17.0.1:6380 -e AUTH_PASS=password -d s7anley/redis-sentinel-docker
    

    ここでは,ノードの1つの配置コマンドを出して,各環境変数の意味を説明する.
    docker  run --name sentinel-1 -p 26380:26380 
    -e SENTINEL_PORT=26380 # sentinel    26380
    -e MASTER_NAME=master #      
    -e QUORUM=2 #             2
    -e DOWN_AFTER=30000 #30000   redis      ,      
    -e PARALLEL_SYNCS=1 #                ,        ,    1   
    -e MASTER=172.17.0.1:6380 #    ip   
    -e AUTH_PASS=password #        
    -d s7anley/redis-sentinel-docker
    
    

    各コンテナがそれぞれ起動すると、redis-cliクライアントを使用してsentinelノードの1つに接続します.infoコマンドを使用して接続の詳細を表示
    markfengfeng@markfengfeng:~$ redis-cli -p 26380
    127.0.0.1:26380> info
    # Server
    redis_version:2.8.16
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:9b6f16e360929887
    redis_mode:sentinel
    os:Linux 4.15.0-45-generic x86_64
    arch_bits:64
    multiplexing_api:epoll
    gcc_version:4.8.2
    process_id:1
    run_id:0c53be652240cc31135318c7f94bae86329b97bd
    tcp_port:26380
    uptime_in_seconds:258
    uptime_in_days:0
    hz:10
    lru_clock:8899661
    config_file:/etc/redis/sentinel.conf
    
    # Sentinel
    sentinel_masters:1
    sentinel_tilt:0
    sentinel_running_scripts:0
    sentinel_scripts_queue_length:0
    master0:name=master,status=ok,address=172.17.0.1:6380,slaves=2,sentinels=3
    #    sentinel    ok,master   ip,  。             sentinel     
    

    この場合sentinelによるredisノードのモニタリングは成功した.
    フェイルオーバーテスト
    次に、プライマリノードがダウンタイムした後、sentinelが自動的にフェイルオーバーできるかどうかをテストします.
    まずsentinelのログを開き、docker stop masterでプライマリノードを手動で閉じます.
    1:X 14 Mar 14:53:41.237 # +sdown master master 172.17.0.1 6380   
    1:X 14 Mar 14:53:41.325 # +new-epoch 1
    1:X 14 Mar 14:53:41.333 # +vote-for-leader 06b9bedb039ec5cd119e2ea24ae02f3513e7a4f8 1
    1:X 14 Mar 14:53:41.333 # +odown master master 172.17.0.1 6380 #quorum 2/2
    1:X 14 Mar 14:53:41.333 # Next failover delay: I will not start a failover before Thu Mar 14 14:59:42 2019
    1:X 14 Mar 14:53:42.538 # +config-update-from sentinel 06b9bedb039ec5cd119e2ea24ae02f3513e7a4f8 172.17.0.5 26381 @ master 172.17.0.1 6380
    1:X 14 Mar 14:53:42.538 # +switch-master master 172.17.0.1 6380 172.17.0.1 6381 
    #      6381    
    1:X 14 Mar 14:53:42.538 * +slave slave 172.17.0.1:6382 172.17.0.1 6382 @ master 172.17.0.1 6381 6382  6381    
    

    6381を参照するマスタースレーブ情報は、以下の通りであり、6381はマスターノードであり、6382はスレーブノードである.
    markfengfeng@markfengfeng:~$ redis-cli -p 6381 -a password
    127.0.0.1:6381> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=172.17.0.1,port=6382,state=online,offset=74435,lag=1
    master_replid:7be531aa99fa3f3b73effb05823a273163c7b078
    master_replid2:67b5a57405c7a737ba461f2ee9d949909014f7ac
    master_repl_offset:74701
    second_repl_offset:10923
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:74701
    
    
    docker start masterコマンドを使用してmasterノードを起動
    1:X 14 Mar 15:00:05.866 * +convert-to-slave slave 172.17.0.1:6380 172.17.0.1 6380 @ master 172.17.0.1 6381
    

    6380を6381のスレーブノードに再切り替えます.さらに6381の主従情報を見ると,6380がその従ノードとなることがわかる.
    127.0.0.1:6381> info replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=172.17.0.1,port=6382,state=online,offset=113285,lag=1
    slave1:ip=172.17.0.1,port=6380,state=online,offset=113418,lag=1
    master_replid:7be531aa99fa3f3b73effb05823a273163c7b078
    master_replid2:67b5a57405c7a737ba461f2ee9d949909014f7ac
    master_repl_offset:113418
    second_repl_offset:10923
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:113418
    

    sentinelの構成は終わりました.
    クライアント接続
    次に、クライアント・プログラムがsentinelを介してredisデータベースに接続する方法について説明します.sentinelが自動的に切り替えた場合、クライアントプログラムの実行に影響しません.
    きほんげんり
    簡単に言えば、sentinelが各ノードを管理していることが知られており、現在のプライマリノードが誰であるかが知られています.ではsentinelのノードをクライアントに構成するプログラムで、クライアントはsentinelを通じて利用可能なプライマリノード接続を取得します.詳細な実装については、redisが提供するクライアントパッケージが実装されています.以下に、いくつかの例を示します.
    JAvaプログラム接続
    JAvaプログラムがsentinel接続でredisを使用する簡単な例.
    redisのjarパッケージを先に導入
    <dependencies>
    	<dependency>
    		<groupId>redis.clientsgroupId>
    		<artifactId>jedisartifactId>
    		<version>2.8.2version>
    	dependency>
    dependencies>
    

    JAvaプログラムは以下の通りです
    public class JedisSentinelDemo {
    	private static JedisSentinelPool pool = null;
    	public void initPool() {
    		//    sentinel          set
    		Set<String> sentinels = new HashSet<String>();
    		sentinels.add("172.17.0.1:26380");
    		sentinels.add("172.17.0.1:26381");
    		sentinels.add("172.17.0.1:26382");
    		//             ,                 api
    		GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    		//  sentinel    ,  (     ,sentinel    ,     ,       ,redis      )
    		pool = new JedisSentinelPool("master", sentinels, config, 10000, "password");
    	}
    	public static void main(String[] args) {
    		JedisSentinelDemo demo = new JedisSentinelDemo();
    		demo.initPool();
    		Jedis jedis = null;
    		try {
    			int incre = 1;
    			while (true) {
    				Thread.currentThread().sleep(10000);
    				jedis = pool.getResource();
    				jedis.set("number", String.valueOf(incre++));
    				String value = jedis.get("number");
    				System.out.println(value);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			if (jedis != null) 
    				jedis.close();
    		}
    	}
    }
    

    プログラムテスト
    プログラムを実行して、コンソールの結果
       18, 2019 11:10:29    redis.clients.jedis.JedisSentinelPool initSentinels
      : Trying to find master from available Sentinels...
       18, 2019 11:10:29    redis.clients.jedis.JedisSentinelPool initSentinels
      : Redis master running at 172.17.0.1:6380, starting Sentinel listeners...
       18, 2019 11:10:29    redis.clients.jedis.JedisSentinelPool initPool
      : Created JedisPool to master at 172.17.0.1:6380
    1
    2
    redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.
    	at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:199)
    	at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)
    	at redis.clients.jedis.Protocol.process(Protocol.java:147)
    	at redis.clients.jedis.Protocol.read(Protocol.java:211)
    	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:297)
    	at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:196)
    	at redis.clients.jedis.Jedis.set(Jedis.java:69)
    	at test.JedisSentinelDemo.main(JedisSentinelDemo.java:35)
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    	at redis.clients.util.Pool.getResource(Pool.java:53)
    	at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:209)
    	at test.JedisSentinelDemo.main(JedisSentinelDemo.java:34)
    Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException:      (Connection refused)
    	at redis.clients.jedis.Connection.connect(Connection.java:164)
    	at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:80)
    	at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1677)
    	at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:87)
    	at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:868)
    	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435)
    	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
    	at redis.clients.util.Pool.getResource(Pool.java:49)
    	... 2 more
    Caused by: java.net.ConnectException:      (Connection refused)
    	at java.net.PlainSocketImpl.socketConnect(Native Method)
    	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    	at java.net.Socket.connect(Socket.java:589)
    	at redis.clients.jedis.Connection.connect(Connection.java:158)
    	... 9 more
    redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
    	at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:103)
    	at redis.clients.jedis.JedisSentinelPool.returnBrokenResource(JedisSentinelPool.java:234)
    	at redis.clients.jedis.JedisSentinelPool.returnBrokenResource(JedisSentinelPool.java:17)
    	at redis.clients.jedis.Jedis.close(Jedis.java:3355)
    	at test.JedisSentinelDemo.main(JedisSentinelDemo.java:43)
    Caused by: java.lang.IllegalStateException: Invalidated object not currently part of this pool
    	at org.apache.commons.pool2.impl.GenericObjectPool.invalidateObject(GenericObjectPool.java:640)
    	at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:101)
    	... 4 more
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    	at redis.clients.util.Pool.getResource(Pool.java:53)
    	at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:209)
    	at test.JedisSentinelDemo.main(JedisSentinelDemo.java:34)
    Caused by: redis.clients.jedis.exceptions.JedisConnectionException: 
    ......          
       18, 2019 11:11:30    redis.clients.jedis.JedisSentinelPool initPool
      : Created JedisPool to master at 172.17.0.1:6381
    4
    5
    
    

    いくつかの接続プールの初期化情報が印刷され、基本的な流れの順序がわかります.
  • 利用可能なsentinelノードによりredisマスターノード
  • を取得する.
  • プライマリノードのアドレス172.17.0.1:6380が見つかり、sentinelは
  • のリスニングを開始した.
  • プライマリノードの接続プール
  • を作成する.
  • 最後にredisの関連apiを実行し、setとgetの結果
  • を印刷します.
    その後、docker stop masterでプライマリノードを停止すると、プログラムに接続異常が発生します.
    しばらくするとsentinelがプライマリノードを切り替え、今回sentinelで取得したプライマリノードは172.17.0.1:6381になりました.
    redisのノードフェイルオーバーは,クライアントプログラムがsentinelによって正しい利用可能なプライマリノードを取得できることが分かる.
    スプリングの構成
    通常spring構成redisの接続プールを使用するが、ここでもspring構成の例を示す.
    redis関連とspring関連jarパッケージインポート
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0modelVersion>
      <groupId>com.xhfgroupId>
      <artifactId>JedisSentinelSpringartifactId>
      <version>0.0.1-SNAPSHOTversion>
      <name>JedisSentinelSpringname>
      
      <dependencies>
    	 <dependency>
    	    <groupId>org.springframeworkgroupId>
    	    <artifactId>spring-beansartifactId>
    	    <version>4.0.8.RELEASEversion>
    	dependency>
    	 
    	<dependency>
    	    <groupId>org.springframeworkgroupId>
    	    <artifactId>spring-coreartifactId>
    	    <version>4.0.8.RELEASEversion>
    	dependency>
    	 
    	<dependency>
    	    <groupId>org.springframeworkgroupId>
    	    <artifactId>spring-contextartifactId>
    	    <version>4.0.8.RELEASEversion>
    	dependency>
     
         <dependency>
             <groupId>redis.clientsgroupId>
             <artifactId>jedisartifactId>
             <version>2.8.2version>
         dependency>
         
         <dependency>
             <groupId>org.springframework.datagroupId>
             <artifactId>spring-data-redisartifactId>
             <version>1.7.5.RELEASEversion>
         dependency>
         
         <dependency>
             <groupId>com.fasterxml.jackson.coregroupId>
             <artifactId>jackson-databindartifactId>
             <version>2.8.4version>
         dependency>
         
      dependencies>
    project>
    

    Springの構成、spring-redis.xml.redisのspring構成と比較します.違いは
  • RedisSentinelConfigurationの構成を追加
  • RedisFactoryの構成を調整し、sentinelの構成をredisFactoryに注入します.クライアントがsentinelを介してredis接続を取得するため、redisのアドレス構成を削除します.
  • 
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd"
    	   xmlns:cache="http://www.springframework.org/schema/cache    
        	http://www.springframework.org/schema/cache
        	http://www.springframework.org/schema/cache/spring-cache.xsd">
        	
        	
    	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >  
             <property name="maxIdle" value="10000" />  
             <property name="maxWaitMillis" value="10000" />  
             <property name="testOnBorrow" value="true" />  
        bean >  
    
        
    	<bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
            <property name="master">
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <property name="name" value="master">
                    property>
                bean>
            property>
            <property name="sentinels">
                <set>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="172.17.0.1" />
                        <constructor-arg name="port" value="26380" />
                    bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="172.17.0.1" />
                        <constructor-arg name="port" value="26381" />
                    bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode ">
                        <constructor-arg name="host" value="172.17.0.1" />
                        <constructor-arg name="port" value="26382" />
                    bean>
                set>
            property>
    	bean>
    	
    	
        <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >  
             <property name="password" value="password" />  
             <property name="timeout" value="30000" >property>
    	     <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration">				 constructor-arg>
        	 <constructor-arg name="poolConfig" ref="poolConfig">constructor-arg>  
        bean >  
        
        
        <bean id="keySerializer" class="org.springframework.data.redis.serializer.GenericToStringSerializer">
            <constructor-arg index="0" type="java.lang.Class" value="java.lang.Object" />
        bean>
        <bean id="serializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer">
        bean>
    
        <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
            <property name="connectionFactory" ref="connectionFactory" />
            <property name="defaultSerializer" ref="serializer" />
            <property name="keySerializer" ref="keySerializer" />
            <property name="hashKeySerializer" ref="keySerializer" />
        bean>
    beans>
    

    簡単なjavaプログラムは以下の通りです.
    
    public class Main {
    	public static void main(String[] args) {
    		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-redis.xml");
    		RedisTemplate<String, String> template = (RedisTemplate<String, String>) context.getBean("redisTemplate");
    		int incre = 0;
    		while (true) {
    			try {
    				Thread.currentThread().sleep(5000);				
    				template.opsForValue().set("number", String.valueOf(incre++));
    				String city = template.opsForValue().get("number");
    				System.out.println(city);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    プログラムテスト
    プログラムを実行し、メインノードシミュレーションのダウンタイムを途中で停止した場合、コンソールの結果は次のとおりです.
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
       18, 2019 12:36:50    redis.clients.jedis.JedisSentinelPool initSentinels
      : Trying to find master from available Sentinels...
       18, 2019 12:36:50    redis.clients.jedis.JedisSentinelPool initSentinels
      : Redis master running at 172.17.0.1:6380, starting Sentinel listeners...
       18, 2019 12:36:50    redis.clients.jedis.JedisSentinelPool initPool
      : Created JedisPool to master at 172.17.0.1:6380
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:198)
    	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:345)
    	at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:129)
    	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:92)
    	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:79)
    	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:191)
    	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:166)
    	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:88)
    	at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:169)
    	at Main.main(Main.java:12)
    Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    	at redis.clients.util.Pool.getResource(Pool.java:53)
    	at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:209)
    	at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:17)
    	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:191)
    	... 9 more
    Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException:      (Connection refused)
    	at redis.clients.jedis.Connection.connect(Connection.java:164)
    	at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:80)
    	at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1677)
    	at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:87)
    	at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:868)
    	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435)
    	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
    	at redis.clients.util.Pool.getResource(Pool.java:49)
    	... 12 more
    Caused by: java.net.ConnectException:      (Connection refused)
    	at java.net.PlainSocketImpl.socketConnect(Native Method)
    	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    	at java.net.Socket.connect(Socket.java:589)
    	at redis.clients.jedis.Connection.connect(Connection.java:158)
    	... 19 more
    ...............           
       18, 2019 12:38:12    redis.clients.jedis.JedisSentinelPool initPool
      : Created JedisPool to master at 172.17.0.1:6381
       18, 2019 12:38:12    redis.clients.jedis.JedisSentinelPool initPool
      : Created JedisPool to master at 172.17.0.1:6381
    16
    17
    
    

    接続が開始されたのは6380ノードで、正常に動作していることがわかります.その後、プライマリノードがダウンタイムした後、プログラムに接続異常が発生しました.sentinelがプライマリノードを自動的に切り替えた後、コンソールはプライマリノードが6382ポートに切り替えたノードを印刷し、プログラムが正常に実行される.
    結論
    以上はsentinelの基礎的なトポロジーの導入プロセスです.実践的な操作からsentinelがredisノードの障害を自動的に検出し,切り替えることができることが分かった.また,クライアントに対してこれらの変化を遮断し,単純なクライアントプログラムの処理を行う.これはredisの高可用性をある程度保証する.
    しかし、クライアントがプライマリノードのみを読み書きできるなど、サーバのパフォーマンスが単一のノードに制限されるという問題もあります.これらの問題を解決するためにredisはredis clusterのクラスタスキームを提供し,後続の研究で関連紹介を整理して送った.