由于内存大小的限制,使用一台 Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.
采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.

集群搭建

1.在Redis里准备集群文件夹

Mkdir cluster

2.在cluster文件夹中分别创建7000-7005文件夹

image.png

复制配置文件

说明:

将redis根目录中的redis.conf文件复制到cluster/7000/ 并以原名保存

cp redis.conf cluster/7000/

编辑配置文件

image.png
image.png
image.png
image.png
image.png
image.png

复制修改后的配置文件

image.png

修改端口

说明:分别将7001-7005文件中的7000改为对应的端口号的名称(需要改3处
或者批量修改
image.png

通过脚本编辑启动/关闭指令

创建启动脚本

vim start.sh
image.png

创建关闭的脚本

vim shutdown.sh
image.png

启动脚本

sh start.sh

检查脚本是否启动正常

image.png

创建Redis集群

5.0版本执行

redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005
image.png
image.png

集群测试

@Test
public void testCluster(){
 Set<HostAndPort> nodes=new HashSet<>();
 nodes.add(new HostAndPort("192.168.126.129",7000));
 nodes.add(new HostAndPort("192.168.126.129",7001));
 nodes.add(new HostAndPort("192.168.126.129",7002));
 nodes.add(new HostAndPort("192.168.126.129",7003));
 nodes.add(new HostAndPort("192.168.126.129",7004));
 nodes.add(new HostAndPort("192.168.126.129",7005));
 JedisCluster jedisCluster=new JedisCluster(nodes);
 jedisCluster.set("cluster","集群测试");
 System.out.println(jedisCluster.get("cluster"));
}

SpringBoot整合Redis集群

编写配置文件

image.png

@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {

@Value("${redis.clustesr}")
private String clustesr;

 @Bean
 public JedisCluster jedisCluster(){
 Set<HostAndPort> nodes=new HashSet<>();
 String host=null;
 Integer port=null;
 String[] nodesArray = clustesr.split(",");
 for (String nodeArray:nodesArray
            ) {
 host= nodeArray.split(":")[0];
 port= Integer.valueOf(nodeArray.split(":")[1]);
 nodes.add(new HostAndPort(host,port));
 }
 return new JedisCluster(nodes);
 }
}
自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheFind {
 public String preKey();//用户标识key的前缀
 public int seconds() default 0;//如果用户不写表示不需要超时,如果写了以用户为准
}
使用注解

image.png

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.JedisCluster;
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 JedisCluster 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;
 }
}

Silver
13 声望11 粉丝