Redis分片机制
三台Redis当做一台Redis来用,就叫做分片机制
如果需要存储海量的内存数据,如果只使用一台Redis,无法保证Redis工作的效率,大量的时间都浪费到了寻址当中,可以采用分片机制
分片的搭建
创建新的文件夹
在文件夹中创建3个配置文件
更改端口号(三个端口号改成不一样)
启动3个Redis服务器
注意说明
目前当启动多台服务器 多台之间是互不影响的,各自都是独立的实体
如果将分片通过程序的方式进行操作,要把3台Redis当做一台来用
分片入门案例
/**
* 测试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","分片机制");
System.out.println(shardedJedis.get("shards"));
}
只存储到了其中一台
一致性hash算法
是一种特殊的算法,目的是在移除或添加一个服务器时,能够更小地改变已存在的服务请求与处理请求服务器之间的映射关系
一般的hash是多少位的多少进制数?
8位16进制数
如果对相同的数据进行hash运算 问结果是否相同?
结果相同
一个数据1M 与数据 1G的hash运算的速度是否相同?
相同(任何数据用hash计算,不以它的量为标准,计算的速度几乎都是相同的)
特性1-平衡性
概念:平衡性是指hash的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题 [4] 。(大致平均)
问题描述: 由于节点都是通过hash方式进行算计.所以可能出现如图中的现象.,导致负载严重不平衡
解决方法: 引入虚拟节点
特性2-单调性
特点: 单调性是指在新增或者删减节点时,不影响系统正常运行
特性3-分散性
谚语: 鸡蛋不要放到一个篮子里.
③分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据
SpringBoot整合Redis分片
编写配置文件
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {
@Value("${redis.nodes}")
private String nodes;
@Bean
public ShardedJedis shardedJedis(){
nodes=nodes.trim();//去除多余空格
List<JedisShardInfo> shards=new ArrayList<>();
String[] strings = nodes.split(",");
for (String str:strings
) {
String host = str.split(":")[0];
Integer port= Integer.valueOf(str.split(":")[1]);
JedisShardInfo info=new JedisShardInfo(host,port);
shards.add(info);
}
return new ShardedJedis(shards);
}
}
自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheFind {
public String preKey();//用户标识key的前缀
public int seconds() default 0;//如果用户不写表示不需要超时,如果写了以用户为准
}
使用注解
AOP代码切入
package com.cn.jt.aop;
import com.cn.jt.annotation.CacheFind;
import com.cn.jt.util.ObjectMapperUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.ShardedJedis;
import java.util.Arrays;
/**
* @program: jt
* @description:
* @author: zhu Xia
* @create: 2020-10-14 09:32
**/@Aspect //我是一个aop的切面类
@Component//将类交给spring容器管理
public class CacheAOP {
@Autowired
private ShardedJedis jedis;
/**
* 1.动态生成key preKey+用户参数数组
* @param joinPoint
* @return
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
System.out.println("注解拦截");
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 signature = (MethodSignature) joinPoint.getSignature();
Class type = signature.getReturnType();
result = ObjectMapperUtil.toObject(json,type);
}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);
}
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
}
Redis哨兵机制
如果Redis分片中有一个节点出现了问题,则整个Redis分片机制用户访问必然有问题 ,直接影响用户的使用,那就需要实现Redis的高可用
配置Redis主从结构
实现从机挂载
检查主机状态
可以在主机写 ,同步到从机
从机只能读,不能写
哨兵机制
心跳检测机制
如果主机宕掉了,哨兵会在从里面选出主,主 修好的话 ,回来的话只能当从
用户将来连的是哨兵
哨兵原理说明
1.配置redis主从结构
2.哨兵服务启动时,会监控当前的主机 ,同时获取主机的详情信息(主从的结构)
3.当哨兵利用心跳检测机制(PING-PONG)连续3次都没有收到主机的反馈信息则判定主机宕机
4.当哨兵发现主机宕机之后,则开启选举机制,在当前的从机中挑选一台Redis当做主机
5.将其他的Redis节点设置为新主机的从
编辑哨兵配置文件
创建sentinel文件夹 并把sentinel.conf 配置文件移至其下
1.修改保护模式
2.
3.其中的1表示投票生效的票数
启动哨兵
redis-sentinel sentinel.conf
测试哨兵
/**
* 测试Redis哨兵
*/
@Test
public void sentinel(){
Set<String> set=new HashSet<>();
//传递哨兵的配置信息
set.add("192.168.126.129:26379");
JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("mymaster",set);
Jedis jedis=jedisSentinelPool.getResource();
jedis.set("aa","哨兵测试");
System.out.println(jedis.get("aa"));
}
SpringBoot整合Redis哨兵
编辑配置文件
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {
@Value("${redis.sentinel}")
private String sentinel;
@Bean
public JedisSentinelPool sentinel(){
Set<String> set=new HashSet<>();
set.add(sentinel);
JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(100);
jedisPoolConfig.setMaxIdle(40);
jedisPoolConfig.setMinIdle(10);
return new JedisSentinelPool("mymaster",set,jedisPoolConfig);
}
}
自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheFind {
public String preKey();//用户标识key的前缀
public int seconds() default 0;//如果用户不写表示不需要超时,如果写了以用户为准
}
使用注解
AOP切入
@Aspect //我是一个aop的切面类
@Component//将类交给spring容器管理
public class CacheAOP {
@Autowired
private JedisSentinelPool jedisSentinelPool;
/**
* 1.动态生成key preKey+用户参数数组
* @param joinPoint
* @return
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
Jedis jedis = jedisSentinelPool.getResource();//从池中取Redis
System.out.println("注解拦截");
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 signature = (MethodSignature) joinPoint.getSignature();
Class type = signature.getReturnType();
result = ObjectMapperUtil.toObject(json,type);
}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);
}
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
jedis.close();//用完记得关掉
return result;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。