10、redis哨兵叢集高可用

項羽齊發表於2018-03-26

Redis的分片技術

1.1 分片介紹

1.1.1 傳統方式的問題

說明:如果採用單臺redis,如果redis出現當機現象.那麼會直接影響我們的整個的服務.

1.1.2 採用分片模式

說明:由一臺redis擴充套件到多臺redis.由多臺redis共同為使用者提供服務.並且每臺redis中儲存1/N的資料.

好處:如果一臺redis出現了問題.不會影響整個redis的服務.

 

1.1.3 配置多臺redis

說明:redis.conf檔案拷貝3份到shard資料夾下.分別形成6379/6380/6381的檔案

cp redis.conf shard/redis-6379.conf

 

 

1.1.4 修改埠

1.將埠改為6380

 

 

2.將埠號為6381

 

 

1.1.5 啟動多臺redis

redis-server redis-6379.conf

redis-server redis-6380.conf

redis-server redis-6381.conf

  1. 進入客戶端

redis-cli -p 6380

  1. 關閉客戶端

redis-cli -p 6380 shutdown

 

1.1.6 分片測試

@Test
    public void test02(){
        /**
         * 定義分片的連線池
         * 引數介紹
         * 1.poolConfig 定義連結池的大小
         * 2.shards     表示List<Shardinfo> 表示redis的資訊的集合
         * 
         * 補充知識:
         *     Jedis 引入會有執行緒安全性問題.所以通過執行緒池的方式動態獲取
         * jedis連結.
         */
        
        //定義連結池大小
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(1000);
        poolConfig.setTestOnBorrow(true);//測試連結是否正常,如果不正常會重新獲取
        poolConfig.setMaxIdle(30);
        //定義分片的list集合
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add(new JedisShardInfo("192.168.126.142",6379));
        shards.add(new JedisShardInfo("192.168.126.142",6380));
        shards.add(new JedisShardInfo("192.168.126.142",6381));
        ShardedJedisPool jedisPool = 
                new ShardedJedisPool(poolConfig, shards);
        //獲取redis的連結
        ShardedJedis jedis = jedisPool.getResource();
        for(int i=1;i<=20;i++){
            jedis.set("KEY"+i, ""+i);
        }
        System.out.println("redis插入操作成功!!!");
    }

 

1.2 Redis分片的演算法介紹

1.2.1 雜湊一致性演算法

說明:根據節點的資訊進行雜湊計算計算的結果在0-2^32-1  的範圍內.計算完成之後能夠進行動態的節點的掛載

特點:

  1. 均衡性

a) 儘可能的讓資料均衡的落入快取區

  1. 單調性

a) 如果資料已經進行了動態的分配.如果有新節點引入能夠進行動態的分配.

  1. 分散性

a) 由於分散式開發,使用者不能看到快取的全部.那麼資料計算的結果能位置不固定.好的雜湊一致性演算法應該儘可能的降低分散性

  1. 負載

a) 從另一個角度研究分散性.由於使用者不能看到快取區的全部,經過計算後,同一個快取區可以會有多個資料.這樣的方式不是特別的友好,所以高階的雜湊演算法應該儘可能降低負載.

 

1.2.2 圖示

 

 

說明:

  1. 通過節點的ip+編號通過hash運算,算出具體的位置
  2. 如果需要進行key的儲存.首先根據key值進行計算,找到位置,之後進行資料的儲存
  3. 按照順時針的方向,資料找最近的節點進行掛載.
  4. 取資料時通過node資訊.獲取資料.
  5. 以上的節點(node)資訊都是動態

1.2.3 均衡性

說明:由於雜湊計算可能會出現節點位置較近的現象.通過均衡性中虛擬節點.儘可能的讓資料達到平均

 

 

 

1.2.4 單調性

說明:由於node節點資訊可能會出現變化,資料可以動態的掛載到新的節點中.

如果節點需要刪除.那麼該節點中的資料會動態的掛載到新的節點中,保證資料是有效的

 

 

 

1.2.5 分散性

 

說明:由於採用了分散式的部署,某些使用者不能夠看到全部的快取區(node)節點資訊.這時在進行資料操作時,可會出現同一key位於不同的位置.

1.2.6 負載

說明:從另外的一個角度考慮分散性.同一個位置.可以存放不同的key

要求:好的hash演算法應該儘可能的降低分散性和負載.

1.3 Spring的方式整合分片

1.3.1 編輯配置檔案

說明:將原有redis的配置檔案改名,為了不讓Spring容器掃描解析出錯.

 

圖上的配置檔案保留原有的配置前邊多加字母A.可以保證spring容器不會載入該配置

 

<!--通過執行緒池的方式整合單臺redis  -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--定義連線的總數  -->
        <property name="maxTotal" value="${redis.maxTotal}"/>
        <!--定義最大的空閒數量  -->
        <property name="maxIdle" value="${redis.maxIdle}"/>
        
        <!--定義最小空閒數量  -->
        <property name="minIdle" value="${redis.minIdle}"></property>
    </bean>
    
    <!--
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add(new JedisShardInfo("192.168.126.142",6379));
        shards.add(new JedisShardInfo("192.168.126.142",6380));
        shards.add(new JedisShardInfo("192.168.126.142",6381));
        ShardedJedisPool jedisPool = 
                new ShardedJedisPool(poolConfig, shards);
      -->
      
      <!--定義jediShardinfo物件  -->
      <bean id="host1" class="redis.clients.jedis.JedisShardInfo">
          <constructor-arg index="0" value="${redis.host1}" type="java.lang.String"/>
          <constructor-arg index="1" value="${redis.port1}" type="int"/>
      </bean>
      
      <bean id="host2" class="redis.clients.jedis.JedisShardInfo">
          <constructor-arg index="0" value="${redis.host2}" type="java.lang.String"/>
          <constructor-arg index="1" value="${redis.port2}" type="int"/>
      </bean>
      
       <bean id="host3" class="redis.clients.jedis.JedisShardInfo">
          <constructor-arg index="0" value="${redis.host3}" type="java.lang.String"/>
          <constructor-arg index="1" value="${redis.port3}" type="int"/>
      </bean>
      
    <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
        <constructor-arg index="0" ref="poolConfig" />
        <constructor-arg index="1">
            <list>
                <ref bean="host1"/>
                <ref bean="host2"/>
                <ref bean="host3"/>
            </list>
        </constructor-arg>
    </bean>

 

1.3.2 編輯redis.properties

 

 

1.3.3 編輯RedisService

 

 

1.3.4 編輯業務層Service

說明:ItemCatService中通過Spring依賴注入的形式進行賦值.所以不需要修改.

思想(面向介面程式設計的好處)

 

 

Redis哨兵

2.1 搭建主從結構

2.1.1 配置主從

說明:配置主從時需要啟動主從的redis節點資訊.之後進行主從掛載.

2.1.2 主從掛載

  1. 複製新的配置檔案,後重新啟動新的redis節點資訊

 

 

  1. 查詢節點的狀態

127.0.0.1:6380> info replication

 

 實現掛載

127.0.0.1:6380> SLAVEOF 192.168.126.142 6379

 

通過該命令實現掛載

 

 

 

  1. 6381掛載到6379中

SLAVEOF 192.168.126.142 6379

2.1.3 主從測試

說明:通過6379查詢info資訊.並且通過set命令為6379賦值後檢測從機中是否含有資料.

 

 

 

2.1.4 哨兵的原理

 

 

 

工作原理:

1.使用者連結時先通過哨兵獲取主機Master的資訊

2.獲取Master的連結後實現redis的操作(set/get)

3.master出現當機時,哨兵的心跳檢測發現主機長時間沒有響應.這時哨兵會進行推選.推選出新的主機完成任務.

4.當新的主機出現時,其餘的全部機器都充當該主機的從機

2.1.5 哨兵的配置

 

1.將保護模式關閉

 

2.配置哨兵的監控

sentinel monitor mymaster 192.168.126.142 6379 1

mymaster:主機的名稱

192.168.126.142:主機的IP

6379 :表示主機的埠號

1:表示有幾個哨兵選舉後生效

3修改時間

說明:10秒後主機沒有響應則選舉新的主機

 

 

 

4.修改推選時間

 

 

2.1.6 啟動哨兵

說明:當啟動哨兵後,由於沒有後臺啟動所以需要重新開啟連線進行測試

redis-sentinel sentinel-6379.conf

 

 

 

redis主機當機後檢測哨兵是否工作

測試結果.redis主機當機後,哨兵自動選舉出新的主機

 

 

檢測6380是否為主機 info replication

 

 

2.1.7 多臺哨兵測試

1.哨兵編譯後的檔案

 

cp sentinel-6379.conf sentinel-6380.conf

   

  1. 修改埠

 

 

  1. 修改序列號

說明:由於哨兵啟動時會自動的生成序列號.序列號相同時哨兵不能相互通訊.所以修改為不同的

 

 

  1. 修改哨兵的個數

 

 

 

2.1.8  多臺哨兵測試

說明:關閉redis主機後,檢測哨兵是否能夠生效,選舉新的主機.如果能夠選舉新的主機表示多臺哨兵搭建完成.

 

2.1.9 測試報錯

說明:由於配置了哨兵,redis中配置了主從結構.所以從機不能進行寫庫操作,.如需測試分片需要關閉redis重新開啟分片的redis

 

 

 

2.2 Spring整合哨兵

2.2.1 測試用例

//哨兵的測試
    @Test
    public void test03(){
        //建立哨兵的連線池
        //String型別表示的是哨兵的IP:埠號
        Set<String> sentinels = new HashSet<String>();
        
        String msg = new HostAndPort("192.168.126.142",26379).toString();
        
        System.out.println("通過物件輸出哨兵的資訊格式:"+msg);
        
        //為set集合賦值 儲存全部的哨兵資訊
        sentinels.add(new HostAndPort("192.168.126.142",26379).toString());
        sentinels.add(new HostAndPort("192.168.126.142",26380).toString());
        sentinels.add(new HostAndPort("192.168.126.142",26381).toString());
        
        /**
         * 引數介紹
         * 1.masterName 表示連結哨兵的主機的名稱一般是字串mymaster
         * 2.sentinels 哨兵的集合Set<>
         */
        JedisSentinelPool sentinelPool = 
                new JedisSentinelPool("mymaster", sentinels);
        
        Jedis jedis = sentinelPool.getResource();
        
        jedis.set("name", "tom");
        System.out.println("獲取資料:"+jedis.get("name"));
    }

 

 

2.3 Spring整合哨兵

2.3.1 編輯配置檔案

<bean id="jedisSentinelPool" class="redis.clients.jedis.JedisSentinelPool">
        <constructor-arg index="0" value="${redis.masterName}"/>
        <constructor-arg index="1">
            <set>
                <value>${redis.sentinel.host1}</value>
                <value>${redis.sentinel.host2}</value>
                <value>${redis.sentinel.host3}</value>
            </set>
        </constructor-arg>
    </bean>

 

2.3.2 配置哨兵的配置檔案

 

 

2.3.3 編輯工具類程式碼

說明:在工具類中定義方法.之後測試檢視效果

 

 

相關文章