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
- 進入客戶端
redis-cli -p 6380
- 關閉客戶端
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 的範圍內.計算完成之後能夠進行動態的節點的掛載
特點:
- 均衡性
a) 儘可能的讓資料均衡的落入快取區
- 單調性
a) 如果資料已經進行了動態的分配.如果有新節點引入能夠進行動態的分配.
- 分散性
a) 由於分散式開發,使用者不能看到快取的全部.那麼資料計算的結果能位置不固定.好的雜湊一致性演算法應該儘可能的降低分散性
- 負載
a) 從另一個角度研究分散性.由於使用者不能看到快取區的全部,經過計算後,同一個快取區可以會有多個資料.這樣的方式不是特別的友好,所以高階的雜湊演算法應該儘可能降低負載.
1.2.2 圖示
說明:
- 通過節點的ip+編號通過hash運算,算出具體的位置
- 如果需要進行key的儲存.首先根據key值進行計算,找到位置,之後進行資料的儲存
- 按照順時針的方向,資料找最近的節點進行掛載.
- 取資料時通過node資訊.獲取資料.
- 以上的節點(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 主從掛載
- 複製新的配置檔案,後重新啟動新的redis節點資訊
- 查詢節點的狀態
127.0.0.1:6380> info replication
實現掛載
127.0.0.1:6380> SLAVEOF 192.168.126.142 6379
通過該命令實現掛載
- 將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
- 修改埠
- 修改序列號
說明:由於哨兵啟動時會自動的生成序列號.序列號相同時哨兵不能相互通訊.所以修改為不同的
- 修改哨兵的個數
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 編輯工具類程式碼
說明:在工具類中定義方法.之後測試檢視效果