关于redis分片说明
优点:实现内存数据的扩容。
缺点:如果redis分片中有一个节点出现了问题,则整个redis分片机制用户访问必然会出现问题,直接影响用户的使用。
解决方案:实现redis的高可用。
配置redis主从结构
策略划分:1主2从 6379主 6380/6381从
1.将分片的目录复制 改名为sentinel
2.重启redis服务器
3.检查redis节点的主从状态
4.实现主从挂载
5.检查主机状态
哨兵的工作原理
原理说明:
1.配置redis主从的结构。
2.哨兵服务启动时,会监控当前的主机,同时获取主机的详情信息(主从的结构)。
3.当哨兵刘勇心跳检测机制(PING-PANG)连续3次都没有收到主机的反馈信息则断定主机宕机。
4.当哨兵发现主机宕机后,则开启选举机制,在当前的从机中挑选一台Redis当做主机。
5.将其他的redis节点设置为新主机的从。
编辑哨兵配置文件
1.复制配置文件
cp sentinel.conf sentinel/
2.修改保护模式
3.开启后台运行
4.设定哨兵的监控
其中的1表示投票生效的票数,当前只有一个哨兵所以写1
5.修改宕机时间
6.选举失败的时间
说明:如果选举超过指定的时间没有结束,则重新选举
7.启动哨兵服务
Redis哨兵高可用实现
测试步骤:
1.检查主机的状态
2.将redis主服务器宕机等待10秒,之后检查从机是否当选新的主机。
3.重启6379服务器,检查是否成为了新主机的从
哨兵入门案例
/**
* 测试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"));
}
SpringBoot整合Redis哨兵
编辑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
编辑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);
}
}
修改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;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。