1. Redis分片機制
1.1 為什么需要分片機制
如果需要存盤海量的記憶體資料,如果只使用一臺redis,無法保證redis作業的效率. 大量的時間都浪費到了尋址當中.所以需要一種機制能夠滿足該要求.
采用分片機制實作:

1.2 Redis分片搭建
1.2.1 搭建注意事項
Redis服務的啟動需要依賴于redis.conf的組態檔. 如果需要準備3臺redis.則需要準備3個redis.conf的配置.
準備埠號:
1.6379
2.6380
3.6381
1.2.2 分片實作

修改埠號: 將各自的埠號進行修改.

啟動3臺redis服務器

校驗服務器是否正常運行

1.2.3 關于分片的注意事項
1.問題描述:
當啟動多臺redis服務器之后,多臺redis暫時沒有必然的聯系,各自都是獨立的物體.可以資料資料的存盤.如圖所示.
2.如果將分片通程序式的方式進行操作,要把3臺redis當做一個整體,所以與上述的操作完全不同.不會出現一個key同時保存到多個redis的現象.

1.3 分片入門案例
/**
* 測驗Redis分片機制
* 思考: shards 如何確定應該存盤到哪臺redis中呢???
*/
@Test
public void testShards(){
List<JedisShardInfo> shards = new ArrayList<>();
shards.add(new JedisShardInfo("192.168.126.129",6379));
shards.add(new JedisShardInfo("192.168.126.129",6380));
shards.add(new JedisShardInfo("192.168.126.129",6381));
//準備分片物件
ShardedJedis shardedJedis = new ShardedJedis(shards);
shardedJedis.set("shards","redis分片測驗");
System.out.println(shardedJedis.get("shards"));
}
1.4 一致性hash演算法
1.4.0 常識說明
常識1: 一般的hash是8位16進制數. 0-9 A-F (24)8 = 2^32
常識2: 如果對相同的資料進行hash運算 結果必然相同的.
常識3: 一個資料1M 與資料1G的hash運算的速度一致.
1.4.1 一致性hash演算法介紹
一致性哈希演算法在1997年由麻省理工學院提出,是一種特殊的哈希演算法,目的是解決分布式快取的問題, [1] 在移除或者添加一個服務器時,能夠盡可能小地改變已存在的服務請求與處理請求服務器之間的映射關系,一致性哈希解決了簡單哈希演算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的動態伸縮等問題 [2] ,

1.4.2 特性1-平衡性
概念:平衡性是指hash的結果應該平均分配到各個節點,這樣從演算法上解決了負載均衡問題 [4] ,(大致平均)
問題描述: 由于節點都是通過hash方式進行算計.所以可能出現如圖中的現象.,導致負載嚴重不平衡

解決方法: 引入虛擬節點

1.4.3 特性2-單調性
特點: 單調性是指在新增或者刪減節點時,不影響系統正常運行 [4] ,

1.4.4 特性3-分散性
諺語: 雞蛋不要放到一個籃子里.
③分散性是指資料應該分散地存放在分布式集群中的各個節點(節點自己可以有備份),不必每個節點都存盤所有的資料 [4]
1.5 SpringBoot整合Redis分片
1.5.1 編輯組態檔
# 配置redis單臺服務器
redis.host=192.168.126.129
redis.port=6379
# 配置redis分片機制
redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381
1.5.2 編輯配置類
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {
@Value("${redis.nodes}")
private String nodes; //node,node,node.....
//配置redis分片機制
@Bean
public ShardedJedis shardedJedis(){
nodes = nodes.trim(); //去除兩邊多余的空格
List<JedisShardInfo> shards = new ArrayList<>();
String[] nodeArray = nodes.split(",");
for (String strNode : nodeArray){ //strNode = host:port
String host = strNode.split(":")[0];
int port = Integer.parseInt(strNode.split(":")[1]);
JedisShardInfo info = new JedisShardInfo(host, port);
shards.add(info);
}
return new ShardedJedis(shards);
}
}
1.5.3 修改AOP注入項

2 Redis哨兵機制
2.1 關于Redis分片說明
優點: 實作記憶體資料的擴容.
缺點: 如果redis分片中有一個節點出現了問題.,則整個redis分片機制用戶訪問必然有問題 直接影響用戶的使用.
解決方案: 實作redis高可用.
2.2 配置redis主從的結構
策略劃分: 1主2從 6379主 6380/6381從
1.將分片的目錄復制 改名位sentinel

- 重啟三臺redis服務器

3.檢查redis節點的主從的狀態

4.實作主從掛載

5.檢查主機的狀態

2.3 哨兵的作業原理

原理說明:
1.配置redis主從的結構.
2.哨兵服務啟動時,會監控當前的主機. 同時獲取主機的詳情資訊(主從的結構)
3.當哨兵利用心跳檢測機制(PING-PONG) 連續3次都沒有收到主機的反饋資訊則斷定主機宕機.
4.當哨兵發現主機宕機之后,則開啟選舉機制,在當前的從機中挑選一臺Redis當做主機.
5.將其他的redis節點設定為新主機的從.
2.4 編輯哨兵組態檔
1).復制組態檔
cp sentinel.conf sentinel/
2).修改保護模式

3).開啟后臺運行

4).設定哨兵的監控
其中的1 表示投票生效的票數 當前只有一個哨兵所以寫1

5).修改宕機的時間

6).選舉失敗的時間
說明:如果選舉超過指定的時間沒有結束,則重新選舉.

7).啟動哨兵服務

2.5 Redis哨兵高可用實作
測驗步驟:
1.檢查主機的狀態
2.將redis主服務器宕機 等待10秒 之后檢查從機是否當選新的主機

3.重啟6379服務器., 檢查是否成為了新主機的從.

2.6 哨兵入門案例
/**
* 測驗Redis哨兵
*/
@Test
public void testSentinel(){
Set<String> set = new HashSet<>();
//1.傳遞哨兵的配置資訊
set.add("192.168.126.129:26379");
JedisSentinelPool sentinelPool =
new JedisSentinelPool("mymaster",set);
Jedis jedis = sentinelPool.getResource();
jedis.set("aa","哨兵測驗");
System.out.println(jedis.get("aa"));
}
2.7 SpringBoot整合Redis哨兵 (10分鐘)
2.7.1 編輯pro組態檔
# 配置redis單臺服務器
redis.host=192.168.126.129
redis.port=6379
# 配置redis分片機制
redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381
# 配置哨兵節點
redis.sentinel=192.168.126.129:26379
2.7.2 編輯redis配置類
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {
@Value("${redis.sentinel}")
private String sentinel; //暫時只有單臺
@Bean
public JedisSentinelPool jedisSentinelPool(){
Set<String> sentinels = new HashSet<>();
sentinels.add(sentinel);
return new JedisSentinelPool("mymaster",sentinels);
}
}
2.7.3 修改CacheAOP中的注入項
package com.jt.aop;
import com.jt.anno.CacheFind;
import com.jt.config.JedisConfig;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.ShardedJedis;
import java.lang.reflect.Method;
import java.util.Arrays;
@Aspect //我是一個AOP切面類
@Component //將類交給spring容器管理
public class CacheAOP {
@Autowired
//private Jedis jedis; //單臺redis
//private ShardedJedis jedis; //分片機制
private JedisSentinelPool jedisSentinelPool;
/**
* 切面 = 切入點 + 通知方法
* 注解相關 + 環繞通知 控制目標方法是否執行
*
* 難點:
* 1.如何獲取注解物件
* 2.動態生成key prekey + 用戶引數陣列
* 3.如何獲取方法的回傳值型別
*/
@Around("@annotation(cacheFind)") //引數傳遞變數的傳遞
//@Around("@annotation(com.jt.anno.CacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
//從池中獲取jedis物件
Jedis jedis = jedisSentinelPool.getResource();
Object result = null;
try {
//1.拼接redis存盤資料的key
Object[] args = joinPoint.getArgs();
String key = cacheFind.preKey() +"::" + Arrays.toString(args);
//2. 查詢redis 之后判斷是否有資料
if(jedis.exists(key)){
//redis中有記錄,無需執行目標方法
String json = jedis.get(key);
//動態獲取方法的回傳值型別 向上造型 向下造型
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class returnType = methodSignature.getReturnType();
result = ObjectMapperUtil.toObj(json,returnType);
System.out.println("AOP查詢redis快取");
}else{
//表示資料不存在,需要查詢資料庫
result = joinPoint.proceed(); //執行目標方法及通知
//將查詢的結果保存到redis中去
String json = ObjectMapperUtil.toJSON(result);
//判斷資料是否需要超時時間
if(cacheFind.seconds()>0){
jedis.setex(key,cacheFind.seconds(),json);
}else {
jedis.set(key, json);
}
System.out.println("aop執行目標方法查詢資料庫");
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
jedis.close(); //將使用完成的鏈接記得關閉.
return result;
}
}
作業
1.預習 Redis集群搭建步驟
2.了解redis集群作業原理
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/177050.html
標籤:其他
