Redis学習(一):redisクラスタの哨兵モードでの負荷均衡

29157 ワード

説明


Redisクラスタの導入を学習研究する過程で、哨兵モードでクラスタを配置する場合、Jedisをクライアントとしてホストに接続するだけで、スレーブからバックアップとしてのみ高可用性を保証できることが分かった.このように読み書きはホストにあり,比較的高い読み取りでホストに大きなプレッシャーを与える.JedisSentinelPoolのソースコードを読むことで、このクラスに基づいてJedisSentinelMasterSlavePoolクラスを実現し、このクラスによってredis哨兵モードでの読み取り操作負荷の均衡を実現する.

本文


基礎知識


redisクラスタの基礎知識については、ここではまとめずに、以下の資料を見て学習と構築を行うことができる:Redisシリーズを深く分析する(一)-Redis入門の紹介と主従構築からRedisシリーズを深く分析する(二)-Redis哨兵モードと高利用可能なクラスタを深く分析するRedisシリーズ(三)-Redisクラスタモード構築と原理を詳しく理解Redisシリーズを深く分析する(四)-Redisデータ構造とグローバルコマンドの概要Redisシリーズを深く分析する(五)-Redisデータ構造の文字列深く分析Redisシリーズ(六)-Redisデータ構造のハッシュ深く分析Redisシリーズ(七)-Redisデータ構造のリスト深く分析Redisシリーズ(八)-Redisデータ構造の集合
哨兵モードでは、一般的に3つのノードを哨兵クラスタとして配置し、哨兵の高可用性を保証する.同時に、各masterノードは主従レプリケーションのモードを採用し、masterで書き込み、slaveノードにデータを同期します.ここでの哨兵はmasterノードの状態を監視し,masterノードが正常に動作しない場合にslaveノードから新しいmasterノードを自動的にフェイルオーバして選択し,古いmasterノードが正常に戻った後,新しいslaveノードとしてクラスタに再加入できることを保証するために用いられる.

JedisSentinelPool


このクラスはJedisがredis哨兵モードをサポートする接続プールで、このクラスにGenericObjectPoolオブジェクトがあり、このクラスを初期化するとホスト接続プールが作成され、MasterListenerが作成され、フェイルオーバが発生するとホスト接続プールが再初期化されます.MasterListenerリスナーでは主に+switch-masterチャネルの傍受を購読しており、ホスト切替が発生した場合、哨兵はこのチャネルを通じて同名のイベントを送信し、このイベントJedisSentinelPoolを傍受することで接続プールの再初期化を実現する.
詳細は公式ドキュメントを参照
this.j.subscribe(new JedisPubSub() {
   public void onMessage(String channel, String message) {
        JedisSentinelPool.this.log.debug("Sentinel {}:{} published: {}.", new Object[]{MasterListener.this.host, MasterListener.this.port, message});
        String[] switchMasterMsg = message.split(" ");
        if (switchMasterMsg.length > 3) {
            if (MasterListener.this.masterName.equals(switchMasterMsg[0])) {
                JedisSentinelPool.this.initPool(JedisSentinelPool.this.toHostAndPort(Arrays.asList(switchMasterMsg[3], switchMasterMsg[4])));
            } else {
                JedisSentinelPool.this.log.debug("Ignoring message on +switch-master for master name {}, our master name is {}", switchMasterMsg[0], MasterListener.this.masterName);
            }
        } else {
            JedisSentinelPool.this.log.error("Invalid message received on Sentinel {}:{} on channel +switch-master: {}", new Object[]{MasterListener.this.host, MasterListener.this.port, message});
        }

    }
}, new String[]{"+switch-master"});

以上の特性に基づいて、JedisSentinelPoolを書き換えることにより、ホスト接続プールがある場合、スレーブ接続プールを携帯し、リスナーを書き換えて他のイベントをリスニングし、スレーブ変化時にスレーブ接続プールが変化に追従できるようにする.

JedisSentinelMasterSlavePool


このクラスはJedisSentinelPoolクラスに基づいて実現される.スレーブ接続プールアドレスリストslavesAddrを追加し、スレーブ接続プール集合Map>slavePoolsからMasterListenerを書き換え、リスニング+slave,+sdown,-sdownイベントを増加し、ホスト切替が発生し、スレーブダウン時に自動的に接続プールを変更できるようにした.同時にThreadLocal>objectPoolThreadLocal変数を追加し、主にリソースを返却できるようにするため、ホストを介してjedisオブジェクトを取得する際にDataSourceを設定し、閉じるとjedisはこの変数を介して接続プールオブジェクトを取得し、接続プールpoolはreturnResource()メソッドを使用してリソースを返します.この特性に基づいて、ThreadLocal変数を追加し、slaveからリソースを取得するときに、そのスレッドがマシン接続プールから取得したJedisを保存し、リソースを返却するときに対応する接続プールを見つけることができます.
このようにしてスレーブ上でのリード動作の負荷等化を実現し,クラスタ状態が変化すると接続プールも変化し,接続が得られない場合があり,フォールトトレランス処理が必要となる.
ここで,マシン接続の取得にはランダムアルゴリズムを用い,他のアルゴリズムを用いてもよい.
新規変数
private volatile Map> slavePools;
private volatile List slavesAddr;
private final Object changeSlavePoolLock;
private final ThreadLocal> objectPoolThreadLocal = new ThreadLocal<>();
private volatile JedisFactory2 factory;

JedisFactoryはパッケージ内のリソースに属するため、JedisFactory 2を新規作成します.
ランダムアルゴリズムによるスレーブ接続の取得
public Jedis getSlaveResource() {
    try{
        if (this.slavePools != null && this.slavePools.size() > 0) {
            Random random = new Random();
            HostAndPort slaveHP = this.slavesAddr.get(random.nextInt(slavePools.size()));
            GenericObjectPool pool = this.slavePools.get(slaveHP);
            this.log.info("Get a slave pool, the address is {}", slaveHP);
            objectPoolThreadLocal.set(pool);
            return pool.borrowObject();
        }
    }catch(Exception e){
        this.log.debug("Could not get a resource form slave pools");
    }
    return this.getResource();
}

スレーブ接続プールリソースの返却
public void closeSlaveJedis(Jedis jedis) {
    GenericObjectPool pool = objectPoolThreadLocal.get();
    //        
    if (pool != null) {
        pool.returnObject(jedis);
    } else {
        jedis.close();
    }
}

Listenerの変更、その他のListenerイベントの追加
//                ,           。        (         ,        ),           
//                 
this.j.subscribe(new JedisPubSub() {
    public void onMessage(String channel, String message) {
        JedisSentinelMasterSlavePool.this.log.debug("Sentinel {}:{}, channel is {} == published: {}.", new Object[]{JedisSentinelMasterSlavePool.MasterListener.this.host, JedisSentinelMasterSlavePool.MasterListener.this.port, channel, message});

        String[] switchMasterMsg = message.split(" ");

        if (switchMasterMsg.length > 3 && channel.equals("+switch-master")) {
            if (JedisSentinelMasterSlavePool.MasterListener.this.masterName.equals(switchMasterMsg[0])) {
                JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on +switch-master for master name {}, the new master address is {} : {}", switchMasterMsg[0], switchMasterMsg[3], switchMasterMsg[4]);
                JedisSentinelMasterSlavePool.this.initPool(JedisSentinelMasterSlavePool.this.toHostAndPort(Arrays.asList(switchMasterMsg[3], switchMasterMsg[4])));
            }
        }
        if (switchMasterMsg.length > 5 && JedisSentinelMasterSlavePool.MasterListener.this.masterName.equals(switchMasterMsg[5])) {
            if (channel.equals("+slave")) {
                JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on +slave for master name {}, the new slave address is {} : {}", switchMasterMsg[5], switchMasterMsg[2], switchMasterMsg[3]);
                JedisSentinelMasterSlavePool.this.addSlavePool(switchMasterMsg);
            }

            if (channel.equals("+sdown")) {
                if ("slave".equals(switchMasterMsg[0])) {
                    JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on +sdown for master name {}, the slave is now in Subjectively Down state, remove the slave, the address is {} : {}", switchMasterMsg[5], switchMasterMsg[2], switchMasterMsg[3]);
                    JedisSentinelMasterSlavePool.this.removeSlavePool(switchMasterMsg);
                }
            }

            if (channel.equals("-sdown")) {
                if ("slave".equals(switchMasterMsg[0])) {
                    JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on -sdown for master name {}, the slave is no logger in Subjectively Down state, readd the slave, the address is {} : {}", switchMasterMsg[5], switchMasterMsg[2], switchMasterMsg[3]);
                    JedisSentinelMasterSlavePool.this.addSlavePool(switchMasterMsg);
                }
            }

        }

    }
}, new String[]{"+switch-master", "+slave", "+sdown", "-sdown"});

ソースコード

public class JedisSentinelMasterSlavePool extends JedisPoolAbstract {
    protected GenericObjectPoolConfig poolConfig;
    protected int connectionTimeout;
    protected int soTimeout;
    protected String password;
    protected int database;
    protected String clientName;
    protected Set masterListeners;
    protected Logger log;
    private volatile HostAndPort currentHostMaster;
    private volatile JedisFactory2 factory;
    private volatile Map> slavePools;
    private volatile List slavesAddr;
    private final Set sentinels;
    private final Object initPoolLock;
    private final Object changeSlavePoolLock;
    private final ThreadLocal> objectPoolThreadLocal = new ThreadLocal<>();

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig) {
        this(masterName, sentinels, poolConfig, 2000, (String)null, 0);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels) {
        this(masterName, sentinels, new GenericObjectPoolConfig(), 2000, (String)null, 0);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, String password) {
        this(masterName, sentinels, new GenericObjectPoolConfig(), 2000, password);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, int timeout, String password) {
        this(masterName, sentinels, poolConfig, timeout, password, 0);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, int timeout) {
        this(masterName, sentinels, poolConfig, timeout, (String)null, 0);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, String password) {
        this(masterName, sentinels, poolConfig, 2000, password);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, int timeout, String password, int database) {
        this(masterName, sentinels, poolConfig, timeout, timeout, password, database);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, int timeout, String password, int database, String clientName) {
        this(masterName, sentinels, poolConfig, timeout, timeout, password, database, clientName);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, int timeout, int soTimeout, String password, int database) {
        this(masterName, sentinels, poolConfig, timeout, soTimeout, password, database, (String)null);
    }

    public JedisSentinelMasterSlavePool(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password, int database, String clientName) {
        this.connectionTimeout = 2000;
        this.soTimeout = 2000;
        this.database = 0;
        this.masterListeners = new HashSet();
        this.log = LoggerFactory.getLogger(JedisSentinelMasterSlavePool.class);
        this.initPoolLock = new Object();
        this.changeSlavePoolLock = new Object();
        this.poolConfig = poolConfig;
        this.connectionTimeout = connectionTimeout;
        this.soTimeout = soTimeout;
        this.password = password;
        this.database = database;
        this.clientName = clientName;
        this.sentinels = sentinels;
        HostAndPort master = this.initSentinels(sentinels, masterName);
        this.initPool(master, this.slavesAddr);
    }

    public void destroy() {
        Iterator var1 = this.masterListeners.iterator();

        while(var1.hasNext()) {
            JedisSentinelMasterSlavePool.MasterListener m = (JedisSentinelMasterSlavePool.MasterListener)var1.next();
            m.shutdown();
        }

        super.destroy();
        //       
        this.destroySlavePool(this.slavePools);
    }

    private void destroySlavePool(Map> slavePools) {
        for (GenericObjectPool pool : slavePools.values()) {
            pool.close();
        }
    }

    public HostAndPort getCurrentHostMaster() {
        return this.currentHostMaster;
    }

    private void initPool(HostAndPort master) {
        Object var2 = this.initPoolLock;
        synchronized(this.initPoolLock) {
            if (!master.equals(this.currentHostMaster)) {
                this.currentHostMaster = master;
                if (this.factory == null) {
                    this.factory = new JedisFactory2(master.getHost(), master.getPort(), this.connectionTimeout, this.soTimeout, this.password, this.database, this.clientName);
                    this.initPool(this.poolConfig, this.factory);
                } else {
                    this.factory.setHostAndPort(this.currentHostMaster);
                    this.internalPool.clear();
                }

                this.log.info("Rcreated JedisPool to master at " + master);
            }

        }
    }

    //   initPool              
    private void initPool(HostAndPort master, List slaves) {
        Object var2 = this.initPoolLock;
        synchronized(this.initPoolLock) {
            if (!master.equals(this.currentHostMaster)) {
                this.currentHostMaster = master;
                this.slavesAddr = slaves;
                if (this.factory == null) {
                    this.factory = new JedisFactory2(master.getHost(), master.getPort(), this.connectionTimeout, this.soTimeout, this.password, this.database, this.clientName);
                    this.initPool(this.poolConfig, this.factory);
                    //        
                    this.initSlavePool(slaves);
                } else {
                    this.factory.setHostAndPort(this.currentHostMaster);
                    this.internalPool.clear();
                }

                this.log.info("Created JedisPool to master at " + master);
            }

        }
    }

    //       
    private void initSlavePool(List slaves) {
        Map> slavePools = new HashMap<>();
        for (HostAndPort slave : slaves) {
            GenericObjectPool slavePool = new GenericObjectPool(new JedisFactory2(slave.getHost(), slave.getPort(), this.connectionTimeout, this.soTimeout, this.password, this.database, this.clientName), this.poolConfig);
            this.log.info("Found Redis slave at {}, created a Slave JedisPool", slave);
            slavePools.put(slave, slavePool);
        }
        this.slavePools = slavePools;
    }

    private HostAndPort initSentinels(Set sentinels, String masterName) {
        HostAndPort master = null;
        boolean sentinelAvailable = false;
        this.log.info("Trying to find master from available Sentinels...");
        Iterator var5 = sentinels.iterator();

        String sentinel;
        HostAndPort hap;
        while(var5.hasNext()) {
            sentinel = (String)var5.next();
            hap = HostAndPort.parseString(sentinel);
            this.log.debug("Connecting to Sentinel {}", hap);
            Jedis jedis = null;

            try {
                jedis = new Jedis(hap);
                List masterAddr = jedis.sentinelGetMasterAddrByName(masterName);
                sentinelAvailable = true;
                //      
                List> slaveAddr = jedis.sentinelSlaves(masterName);
                if (masterAddr != null && masterAddr.size() == 2 && slaveAddr != null && slaveAddr.size() > 0) {
                    master = this.toHostAndPort(masterAddr);
                    this.log.info("Found Redis master at {}", master);
                    //       
                    this.slavesAddr = this.slaveAddrToHostAndPort(slaveAddr);
                    break;
                }

                this.log.warn("Can not get master addr, master name: {}. Sentinel: {}", masterName, hap);
            } catch (JedisException var13) {
                this.log.warn("Cannot get master address from sentinel running @ {}. Reason: {}. Trying next one.", hap, var13.toString());
            } finally {
                if (jedis != null) {
                    jedis.close();
                }

            }
        }

        if (master == null) {
            if (sentinelAvailable) {
                throw new JedisException("Can connect to sentinel, but " + masterName + " seems to be not monitored...");
            } else {
                throw new JedisConnectionException("All sentinels down, cannot determine where is " + masterName + " master is running...");
            }
        } else {
            this.log.info("Redis master running at " + master + ", starting Sentinel listeners...");
            var5 = sentinels.iterator();

            while(var5.hasNext()) {
                sentinel = (String)var5.next();
                hap = HostAndPort.parseString(sentinel);
                JedisSentinelMasterSlavePool.MasterListener masterListener = new JedisSentinelMasterSlavePool.MasterListener(masterName, hap.getHost(), hap.getPort());
                masterListener.setDaemon(true);
                this.masterListeners.add(masterListener);
                masterListener.start();
            }

            return master;
        }
    }

    //      
    private List slaveAddrToHostAndPort(List> slaveAddr) {
        List slaveHPList = new ArrayList();
        for (Map salve : slaveAddr) {
            String ip = salve.get("ip");
            if ("127.0.0.1".equals(ip)) {
                continue;
            }
            String port = salve.get("port");
            String flags = salve.get("flags");
            if (!flags.contains("disconnected") && !flags.contains("s_down")) {
                HostAndPort hostAndPort = toHostAndPort(ip, port);
                slaveHPList.add(hostAndPort);

            }
        }

        return slaveHPList;
    }

    private HostAndPort toHostAndPort(String ip, String port) {
        return new HostAndPort(ip, Integer.parseInt(port));
    }

    private HostAndPort toHostAndPort(List getMasterAddrByNameResult) {
        String host = (String)getMasterAddrByNameResult.get(0);
        int port = Integer.parseInt((String)getMasterAddrByNameResult.get(1));
        return new HostAndPort(host, port);
    }

    //      
    public Jedis getResource() {
        while(true) {
            Jedis jedis = (Jedis)super.getResource();
            jedis.setDataSource(this);
            HostAndPort master = this.currentHostMaster;
            HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient().getPort());
            if (master.equals(connection)) {
                this.log.info("master address is {}", master);
                return jedis;
            }

            this.returnBrokenResource(jedis);
        }
    }

    public Jedis getSlaveResource() {
        try{
            if (this.slavePools != null && this.slavePools.size() > 0) {
                Random random = new Random();
                HostAndPort slaveHP = this.slavesAddr.get(random.nextInt(slavePools.size()));
                GenericObjectPool pool = this.slavePools.get(slaveHP);
                this.log.info("Get a slave pool, the address is {}", slaveHP);
                objectPoolThreadLocal.set(pool);
                return pool.borrowObject();
            }
        }catch(Exception e){
            this.log.debug("Could not get a resource form slave pools");
        }
        return this.getResource();
    }

    //       
    public void closeSlaveJedis(Jedis jedis) {
        GenericObjectPool pool = objectPoolThreadLocal.get();
        //        
        if (pool != null) {
            pool.returnObject(jedis);
        } else {
            jedis.close();
        }
    }

    protected void returnBrokenResource(Jedis resource) {
        if (resource != null) {
            this.returnBrokenResourceObject(resource);
        }

    }

    //      
    protected void returnResource(Jedis resource) {
        if (resource != null) {
            resource.resetState();
            this.returnResourceObject(resource);
        }

    }

    protected class MasterListener extends Thread {
        protected String masterName;
        protected String host;
        protected int port;
        protected long subscribeRetryWaitTimeMillis;
        protected volatile Jedis j;
        protected AtomicBoolean running;

        protected MasterListener() {
            this.subscribeRetryWaitTimeMillis = 5000L;
            this.running = new AtomicBoolean(false);
        }

        public MasterListener(String masterName, String host, int port) {
            super(String.format("MasterListener-%s-[%s:%d]", masterName, host, port));
            this.subscribeRetryWaitTimeMillis = 5000L;
            this.running = new AtomicBoolean(false);
            this.masterName = masterName;
            this.host = host;
            this.port = port;
        }

        public MasterListener(String masterName, String host, int port, long subscribeRetryWaitTimeMillis) {
            this(masterName, host, port);
            this.subscribeRetryWaitTimeMillis = subscribeRetryWaitTimeMillis;
        }

        public void run() {
            this.running.set(true);
            while(this.running.get()) {
                this.j = new Jedis(this.host, this.port);

                try {
                    if (!this.running.get()) {
                        break;
                    }

                    List masterAddr = this.j.sentinelGetMasterAddrByName(this.masterName);
                    //      
                    List> slavesAddr = this.j.sentinelSlaves(this.masterName);
                    if (masterAddr != null && masterAddr.size() == 2) {
                        JedisSentinelMasterSlavePool.this.initPool(JedisSentinelMasterSlavePool.this.toHostAndPort(masterAddr), JedisSentinelMasterSlavePool.this.slaveAddrToHostAndPort(slavesAddr));
                    } else {
                        JedisSentinelMasterSlavePool.this.log.warn("Can not get master addr, master name: {}. Sentinel: {}:{}.", new Object[]{this.masterName, this.host, this.port});
                    }

                    //                ,           。        (         ,        ),           
                    //                 
                    this.j.subscribe(new JedisPubSub() {
                        public void onMessage(String channel, String message) {
                            JedisSentinelMasterSlavePool.this.log.debug("Sentinel {}:{}, channel is {} == published: {}.", new Object[]{JedisSentinelMasterSlavePool.MasterListener.this.host, JedisSentinelMasterSlavePool.MasterListener.this.port, channel, message});

                            String[] switchMasterMsg = message.split(" ");

                            if (switchMasterMsg.length > 3 && channel.equals("+switch-master")) {
                                if (JedisSentinelMasterSlavePool.MasterListener.this.masterName.equals(switchMasterMsg[0])) {
                                    JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on +switch-master for master name {}, the new master address is {} : {}", switchMasterMsg[0], switchMasterMsg[3], switchMasterMsg[4]);
                                    JedisSentinelMasterSlavePool.this.initPool(JedisSentinelMasterSlavePool.this.toHostAndPort(Arrays.asList(switchMasterMsg[3], switchMasterMsg[4])));
                                }
                            }
                            if (switchMasterMsg.length > 5 && JedisSentinelMasterSlavePool.MasterListener.this.masterName.equals(switchMasterMsg[5])) {
                                if (channel.equals("+slave")) {
                                    JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on +slave for master name {}, the new slave address is {} : {}", switchMasterMsg[5], switchMasterMsg[2], switchMasterMsg[3]);
                                    JedisSentinelMasterSlavePool.this.addSlavePool(switchMasterMsg);
                                }

                                if (channel.equals("+sdown")) {
                                    if ("slave".equals(switchMasterMsg[0])) {
                                        JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on +sdown for master name {}, the slave is now in Subjectively Down state, remove the slave, the address is {} : {}", switchMasterMsg[5], switchMasterMsg[2], switchMasterMsg[3]);
                                        JedisSentinelMasterSlavePool.this.removeSlavePool(switchMasterMsg);
                                    }
                                }

                                if (channel.equals("-sdown")) {
                                    if ("slave".equals(switchMasterMsg[0])) {
                                        JedisSentinelMasterSlavePool.this.log.debug("Listening messgae on -sdown for master name {}, the slave is no logger in Subjectively Down state, readd the slave, the address is {} : {}", switchMasterMsg[5], switchMasterMsg[2], switchMasterMsg[3]);
                                        JedisSentinelMasterSlavePool.this.addSlavePool(switchMasterMsg);
                                    }
                                }

                            }

                        }
                    }, new String[]{"+switch-master", "+slave", "+sdown", "-sdown"});
                } catch (JedisException var8) {
                    if (this.running.get()) {
                        JedisSentinelMasterSlavePool.this.log.error("Lost connection to Sentinel at {}:{}. Sleeping 5000ms and retrying.", new Object[]{this.host, this.port, var8});

                        try {
                            Thread.sleep(this.subscribeRetryWaitTimeMillis);
                        } catch (InterruptedException var7) {
                            JedisSentinelMasterSlavePool.this.log.error("Sleep interrupted: ", var7);
                        }
                    } else {
                        JedisSentinelMasterSlavePool.this.log.debug("Unsubscribing from Sentinel at {}:{}", this.host, this.port);
                    }
                } finally {
                    this.j.close();
                }
            }

        }

        public void shutdown() {
            try {
                JedisSentinelMasterSlavePool.this.log.debug("Shutting down listener on {}:{}", this.host, this.port);
                this.running.set(false);
                if (this.j != null) {
                    this.j.disconnect();
                }
            } catch (Exception var2) {
                JedisSentinelMasterSlavePool.this.log.error("Caught exception while shutting down: ", var2);
            }

        }
    }

    //                            
    private void removeSlavePool(String[] switchMasterMsg) {
        synchronized (this.changeSlavePoolLock) {
            String ip = switchMasterMsg[2];
            String port = switchMasterMsg[3];
            HostAndPort oldSlave = this.toHostAndPort(ip, port);
            if (this.slavesAddr != null && slavesAddr.contains(oldSlave)) {
                this.slavesAddr.remove(oldSlave);
                this.slavePools.remove(oldSlave);
                this.log.debug("Remove the slave that is in Subjectively Down state ", oldSlave);
            }

        }
    }

    //    +slave        ,        
    private void addSlavePool(String[] switchMasterMsg) {
        synchronized(this.changeSlavePoolLock) {
            String ip = switchMasterMsg[2];
            String port = switchMasterMsg[3];
            HostAndPort newSlave = this.toHostAndPort(ip, port);
            if (this.slavesAddr != null && !slavesAddr.contains(newSlave)) {
                this.slavesAddr.add(newSlave);
                GenericObjectPool slavePool = new GenericObjectPool<>(new JedisFactory2(newSlave.getHost(), newSlave.getPort(), this.connectionTimeout, this.soTimeout, this.password, this.database, this.clientName), this.poolConfig);
                this.slavePools.put(newSlave, slavePool);
                this.log.debug("Added a new slave JedisPool " + newSlave);
            } else {
                this.log.debug("The slave already existed");
            }
        }
    }

}

ソースアドレス:https://github.com/Edenwds/redis_study/tree/master/sentinelslaveredis