1. 程式人生 > >Redis: sentinel叢集的搭建和測試

Redis: sentinel叢集的搭建和測試

Sentinel叢集的搭建和測試

1.1    測試環境

    master:     127.0.0.16379

   slave1:     127.0.0.1 6380

   slave2:     127.0.0.1 6381

   master-sentinel: 127.0.0.1  26379

   slave1-sentinel: 127.0.0.1  26380

   slave2-sentinel: 127.0.0.1  26381

1.2   叢集配置

1)   Master

redis.conf:
daemonize yes
port 6379
requirepass pw       
masterauth  pw
appendonly no
save ""
slave-read-only yes

6379-sentinal.conf
port 26379
sentinel monitor mymaster 192.168.0.105 6379 2
sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 900000


2)   Salve1

Redis.conf
daemonize yes
port 6380
requirepass pw       
masterauth  pw
appendonly no
save ""
slave-read-only yes
slaveof 192.168.0.105 6379
6380-sentinal.conf
port 26380
sentinel monitormymaster 192.168.0.105 6379 2
sentinel auth-passmymaster pw
sentineldown-after-milliseconds mymaster 30000
sentinel parallel-syncsmymaster 1
sentinel failover-timeout mymaster 900000

3)    Salve2

Redis.conf
daemonize yes
port 6381
requirepass pw       
masterauth  pw
appendonly no
save ""
slave-read-only yes
slaveof 192.168.0.105 6379
6381-sentinal.conf
port 26381
sentinel monitormymaster 192.168.0.105 6379 2
sentinel auth-passmymaster pw
sentineldown-after-milliseconds mymaster 30000
sentinel parallel-syncsmymaster 1
sentinel failover-timeout mymaster 900000

1.3        啟動叢集

寫一個批量啟動叢集的shell指令碼:

St-batch-start.sh

./bin/redis-server./st_cluster_1/master-6379/redis.conf&
./bin/redis-sentinel./st_cluster_1/master-6379/6379-sentinal.conf&
./bin/redis-server./st_cluster_1/salve-6380/redis.conf&
./bin/redis-sentinel ./st_cluster_1/salve-6380/6380-sentinal.conf&
./bin/redis-server./st_cluster_1/salve-6381/redis.conf&
./bin/redis-sentinel./st_cluster_1/salve-6381/6381-sentinal.conf&

#sh st-batch-start.sh

寫一個批量關閉叢集的shell指令碼:

St-batch-stop.sh

kill -9 `ps -ef | grep redis | awk '{print $2}'`

#sh st-batch-stop.sh

1.1   啟動後的結果


起一個會話檢視master的情況:

redis-cli -h 192.168.0.105 -p 6379
auth pw
info Replication



起一個會話查詢salve1的情況:

redis-cli -h192.168.0.105 -p 6380


起一個會話查詢salve2的情況:

redis-cli -h192.168.0.105 -p 6381


此時檢視sentinal各個主機的配置檔案:

埠為26379的sentinel的配置檔案沒有改變:


埠為26380的sentinel的配置檔案有改變:


埠為26381的檔案被重寫了,因為它們發現了master的salve 6381,和另一個sentinel 26381。


1.4        場景測試

 ----場景1:master宕機

master-sentinel作為master 1的leader,會選取一個master 1的slave作為新的master。slave的選取是根據一個判斷DNS情況的優先順序來得到,優先順序相同通過runid的排序得到,但目前優先順序設定還沒實現,所以直接獲取runid排序得到slave 1。然後傳送命令slaveofno one來取消slave 1的slave狀態來轉換為master。當其他sentinel觀察到該slave成為master後,就知道錯誤處理例程啟動了。sentinel A然後傳送給其他slave slaveof new-slave-ip-port 命令,當所有slave都配置完後,sentinelA從監測的masters列表中刪除故障master,然後通知其他sentinels。

    關閉master:

    現在6379是master,6380和6381是salve。

    

Sentinel底下觀察選舉新的master的過程:

顯示了failover的過程:


選擇6380為master:


----場景2:master恢復

重新啟動原來的master:

./bin/redis-server./st_cluster_1/master-6379/redis.conf&


檢視sentinel狀態:


原來的master自動切換成slave,不會自動恢復成master。

----場景3salve1宕機

接著上面的繼續實驗。

關閉slave16379


檢視masterReplication資訊:


此時只存在一個slave

----場景4:salve1重啟

./bin/redis-server./st_cluster_1/master-6379/redis.conf&

檢視sentinel狀態:

sentinel能快速的發現slave加入到叢集中:


檢視master的Replication資訊:


1.5   Java客戶端測試

修改Jedis 2.8的test case進行測試。
package redis.clients.jedis.tests;

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

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Before;
import org.junit.Test;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.jedis.tests.utils.JedisSentinelTestUtil;

public class JedisSentinelPoolTest extends JedisTestBase {
  private static final String MASTER_NAME = "mymaster";
  private static final String localHost = "192.168.0.106";

  protected static HostAndPort master = new HostAndPort(localHost, 6379);
  protected static HostAndPort slave1 = new HostAndPort(localHost, 6380);
  protected static HostAndPort slave2 = new HostAndPort(localHost, 6381);
  
 
  protected static HostAndPort sentinel1 = new HostAndPort(localHost, 26379);
  protected static HostAndPort sentinel2 = new HostAndPort(localHost, 26380);
  protected static HostAndPort sentinel3 = new HostAndPort(localHost, 26381);
  

  protected static Jedis sentinelJedis1;
  protected static Jedis sentinelJedis2;
  protected static Jedis sentinelJedis3;

  protected Set<String> sentinels = new HashSet<String>();

  @Before
  public void setUp() throws Exception {
    sentinels.add(sentinel1.toString());
    sentinels.add(sentinel2.toString());
    sentinels.add(sentinel3.toString());

    sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort());
    sentinelJedis2 = new Jedis(sentinel2.getHost(), sentinel2.getPort());
    sentinelJedis3 = new Jedis(sentinel3.getHost(), sentinel3.getPort());
  }

  @Test(expected = JedisConnectionException.class)
  public void initializeWithNotAvailableSentinelsShouldThrowException() {
    Set<String> wrongSentinels = new HashSet<String>();
    wrongSentinels.add(new HostAndPort(localHost, 65432).toString());
    wrongSentinels.add(new HostAndPort(localHost, 65431).toString());

    JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, wrongSentinels);
    pool.destroy();
  }

  
  @Test(expected = JedisException.class)
  public void initializeWithNotMonitoredMasterNameShouldThrowException() {
    final String wrongMasterName = "wrongMasterName";
    JedisSentinelPool pool = new JedisSentinelPool(wrongMasterName, sentinels);
    pool.destroy();
  }
  

  @Test
  public void checkCloseableConnections() throws Exception {
    GenericObjectPoolConfig config = new GenericObjectPoolConfig();

    JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, config, 10000,
        "pw", 3);
    Jedis jedis = pool.getResource();
    jedis.auth("pw");
    jedis.set("foo", "bar"); 
    String ss = jedis.get("test");
    assertEquals("bar", jedis.get("foo"));
    jedis.close();
    pool.close();
    assertTrue(pool.isClosed());
  }

 
  @Test
  public void ensureSafeTwiceFailover() throws InterruptedException {
    JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels,
        new GenericObjectPoolConfig(), 9000, "pw", 3);

    forceFailover(pool);
    // after failover sentinel needs a bit of time to stabilize before a new
    // failover
    Thread.sleep(100);
    forceFailover(pool);

    // you can test failover as much as possible
  }
  
  @Test
  public void returnResourceShouldResetState() {
    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    config.setMaxTotal(1);
    config.setBlockWhenExhausted(false);
    JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, config, 1000,
        "pw", 3);

    Jedis jedis = pool.getResource();
    Jedis jedis2 = null;

    try {
      jedis.set("hello", "jedis");
      Transaction t = jedis.multi();
      t.set("hello", "world");
      jedis.close();

      jedis2 = pool.getResource();

      assertTrue(jedis == jedis2);
      assertEquals("jedis", jedis2.get("hello"));
    } catch (JedisConnectionException e) {
      if (jedis2 != null) {
        jedis2 = null;
      }
    } finally {
      jedis2.close();

      pool.destroy();
    }
  }

  @Test
  public void checkResourceIsCloseable() {
    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    config.setMaxTotal(1);
    config.setBlockWhenExhausted(false);
    JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, config, 1000,
        "pw", 3);

    Jedis jedis = pool.getResource();
    try {
      jedis.set("hello", "jedis");
    } finally {
      jedis.close();
    }

    Jedis jedis2 = pool.getResource();
    try {
      assertEquals(jedis, jedis2);
    } finally {
      jedis2.close();
    }
  }

  private void forceFailover(JedisSentinelPool pool) throws InterruptedException {
    HostAndPort oldMaster = pool.getCurrentHostMaster();

    // jedis connection should be master
    Jedis beforeFailoverJedis = pool.getResource();
    assertEquals("PONG", beforeFailoverJedis.ping());

    waitForFailover(pool, oldMaster);

    Jedis afterFailoverJedis = pool.getResource();
    assertEquals("PONG", afterFailoverJedis.ping());
    assertEquals("pw", afterFailoverJedis.configGet("requirepass").get(1));
    assertEquals(3, afterFailoverJedis.getDB());

    // returning both connections to the pool should not throw
    beforeFailoverJedis.close();
    afterFailoverJedis.close();
  }

  private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster)
      throws InterruptedException {
    HostAndPort newMaster = JedisSentinelTestUtil.waitForNewPromotedMaster(MASTER_NAME,
      sentinelJedis1, sentinelJedis2);

    waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster);
  }

  private void waitForJedisSentinelPoolRecognizeNewMaster(JedisSentinelPool pool,
      HostAndPort newMaster) throws InterruptedException {

    while (true) {
      HostAndPort currentHostMaster = pool.getCurrentHostMaster();

      if (newMaster.equals(currentHostMaster)) break;

      System.out.println("JedisSentinelPool's master is not yet changed, sleep...");

      Thread.sleep(100);
    }
  }

}



相關推薦

Redis 叢集搭建測試教程

請注意,本教程使用於Redis3.0(包括3.0)以上版本 Redis叢集介紹 Redis 叢集是一個提供在多個Redis間節點間共享資料的程式集。 Redis叢集並不支援處理多個keys的命令,因為這需要在不同的節點間移動資料,從而達不到像Redis那樣的效能,在高

hadoop學習第二天~Hadoop2.6.5完全分散式叢集搭建測試

環境配置: 系統 centos7 節點 192.168.1.111 namenode 192.168.1.115 datanode2 192.168.1.116 datanode3 java 環境 :

Redis: sentinel叢集搭建測試

Sentinel叢集的搭建和測試 1.1    測試環境     master:     127.0.0.16379    slave1:     127.0.0.1 6380    slave2:     127.0.0.1 6381    master-sentine

Redis 復制、Sentinel搭建原理說明(轉)

單個 高可用 模式 ogre 出現 password 並不會 shc generated Redis 復制、Sentinel的搭建和原理說明 轉自:http://www.cnblogs.com/zhoujinyi/p/5570024.html. 背景: R

Redis哨兵Sentinel搭建原理說明

原文地址:http://www.cnblogs.com/zhoujinyi/p/5570024.html 背景:       Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis做Master-slave的高可用方

redis之二 主從複製、sentinel叢集搭建

redis中文官網: replication sentinel 一、主從複製 通過redis的持久化功能,redis可以保證伺服器重啟也不會損失(或少量損失)資料。但資料儲存在單臺redis伺服器上,如果這臺伺服器出現硬碟故障,則會導致資料丟失。 為了避免單點故障,可以將資

redis詳解——redis叢集搭建使用(二)

上一章我寫到redis簡單的介紹和如何單機的使用,當我們redis相當重要的時候那麼接下來就需要搭建一個叢集了。 1 Redis叢集的介紹 1.1 redis-cluster(叢集)架構圖 架構細節: (1)所有的redis節點彼此互聯(PING-PONG機制),

Redis高可用叢集-哨兵模式(Redis-Sentinel搭建配置教程【Windows環境】

No cross,no crown . 不經歷風雨,怎麼見彩虹。 Redis哨兵模式,用現在流行的話可以說就是一個“哨兵機器人”,給“哨兵機器人”進行相應的配置之後,這個”機器人”可以7*24小時工作,它能能夠自動幫助你做一些事情,如監控,提醒,自動處

Linux下Redis叢集搭建測試

叢集搭建 準備條件 一臺已經配置好Redis服務的虛擬機器,地址為: 192.168.2.100:6379 克隆6臺,使用命令nmtui修改地址分別為: 192.168.2.101 192.168.2.102 192.168.2.103 1

redis高可用sentinel叢集搭建

哨兵機制,它基於 Redis 主從複製,主要作用便是解決主節點故障恢復的自動化問題,進一步提高系統的高可用性。 哨兵的架構 它由兩部分組成,哨兵節點和資料節點: 哨兵節點:哨兵系統由一個或多個哨兵節點組成,哨兵節點是特殊的 Redis 節點,不儲存資料。 資料節點:主節點和

Redis 叢集搭建簡單使用教程

##一臺機器<br>ps -ef | grep redis root 61020 1 0 02:14 ? 00:00:01 redis-server 127.0.0.1:7000 [cluster] root 61024 1 0 02:14 ? 00:00:01 redis-ser

SMM框架的搭建測試(Spring MVC+MyBatis)

meta true model spa const -i ssp pan div Spring MVC:MVC框架,通過Model-View-Controller模式很好的將數據,業務與展現進行分離。 MyBatis:數據持久層框架 我這裏使用的是MyEclipse 2

SSH框架的搭建測試(Spring + Struts2 + Hibernate)

conf work fault 項目 -i extends struts2 scrip map SSH框架實現了視圖、控制器、和模型的徹底分離,同時還實現了業務邏輯層與持久層的分離。 Spring實現了MVC中的 Controller的功能,Struts實現Web視圖的功能

Windows平臺下的Redis-Sentinel叢集配置

一、環境介紹 Microsoft Windows 10 企業版 Redis-x64-3.2.100 jedis 2.9.0 Sentinel是一個管理多個redis例項的工具,它可以實現對redis的監控、通知、自動故障轉移。sentinel不斷的檢測red

VSCode + PYQT5 + QtDesigner 環境搭建測試

目的:編寫Python桌面應用程式。 備註:也可以選擇VS2017+QtDesigner ,但更喜歡VSCode    第1步:安裝PyQt5和PyQt5-tools pip3 install -i https://mirrors.aliyun.com/pypi/simple/&n

使用docker redis-cluster叢集搭建

參考https://www.cnblogs.com/cxbhakim/p/9151720.html此文 主要搭建過程參考上文,此處講下主要過程和遇到的坑 首先是映象的基礎搭建,我不知道是否是作者編寫時和我現在的版本不同了,第一個坑點Dockerfile中FROM Centos:7,這去掉算

MySQL 5.7 延遲復制環境搭建測試

uic glibc tin sed quic -s triggers def lee 安裝主從 MySQL 5.7 # 主 MySQL5.7 cd /usr/local tar -xvf mysql-5.7.23-linux-glibc2.12-x86_64.tar.gz

Redis Sentinel叢集雙機房容災實施步驟

概要目標防止雙機房情況下任一個機房完全無法提供服務時如何讓Redis繼續提供服務。架構設計A、B兩機房,其中A機房有一Master一Slave和兩個Sentinel,B機房只有2個Sentinel,如下圖。 初始規劃A機房192.168.71.213 S+哨兵192.168.71.214 M+哨兵B機房19

redis叢集模式哨兵模式

redis的叢集模式和哨兵模式 redis中叢集模式 redis叢集模式配置支援3.0及以上的版本。目的提高redis的可用性,但是隻能保證一定程度的高可用。 redis-cluster原理 Redis 叢集有16384個雜湊槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽.叢集的每個節點負

Zookeeper叢集搭建Kafka叢集搭建

Zookeeper!!! 一、Zookeeper叢集搭建步驟 0)叢集規劃 在hadoop01、hadoop02和hadoop03三個節點上部署Zookeeper。 1)解壓安裝 (1)解壓zookeeper安裝包到/home/hadoop/insatll/目錄下 [[email