1. 程式人生 > >10、redis哨兵集群高可用

10、redis哨兵集群高可用

ava 動態 保存 拷貝 rep 工作原理 arraylist AR 虛擬

1 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依賴註入的形式進行賦值.所以不需要修改.

思想(面向接口編程的好處)

2 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 編輯工具類代碼

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

技術分享圖片

10、redis哨兵集群高可用