您的位置:首页 > 数据库 > Redis

redis分片缺点及特点,redis主从,哨兵原理,哨兵特点,redis集群及失效情况,redis配置文件

2020-06-26 04:15 555 查看

redis分片:
redis如果采用分片机制,将来如果有一台宕机,则直接影响程序的正常运行

如何解决分片缺点:
1.实现高可用,当redis服务器宕机时可以自动的实现主从切换
2.缓存数据同步是实现高可用的前提
3. 如果没有数据同步,即使实现了高可用,则也可能由于从服务器中没有数据而导致缓存雪崩效应

redis分片特点:
1.redis分片机制可以实现redis内存数据的扩容
2.redis分片机制中,是业务服务器进行一致性hash的`计算,而reids服务器只需要负责数据的存储即可,所以redis分片机制性能更高
3.redis分片机制本身没有实现高可用的效果,如果redis节点缺失,则直接影响用户的使用

redis主从搭建
要求:实现主从同步

主从测试
1.当搭建主从结构之后,用户操作主机,从机可以自动实现数据同步
2.搭建主从结构后,从机只读操作,不能写入
3.不要使用主从结构,测试分片API

主从配置有效期
1.默认条件下通过slaveof指令,制定主从结构只能在内存中有效,如果服务器关机重启,则该结构失效,需要手动修改
2.如需要指定永久配置,则需要修改配置文件redis.conf,但是该文件不能由用户自己操作,最好由哨兵/集群的策略完成

redis哨兵工作原理
1.哨兵启动启动后,首先监控当前redis的主机,并且从主机中其获得从机的信息
2.当redis主机宕机之后,哨兵通过心跳检测机制检测主机是否宕机,如果连续3次都没有获取主机的反馈,则断定主机宕机,之前根据算法筛选出 新的主机
3.当哨兵选举出新的主机后,为了保证主从的关系,则会动态的修改各自的redis.conf文件,并且将其他节点标识为新主机的从机

redis哨兵特点:
1.实现redis节点的高可用
2.redis哨兵机制不能实现内存数据的扩容
3.哨兵本身没有实现高可用,哨兵如果宕机,则直接影响用户使用

为什么要使用redis集群??
1.为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取
2.由于内存大小的限制,使用一台 Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.采用合理的机制,保证用户的正常的访问需求.
3.采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.

如何进行redis集群高可用测试?
将主机宕机,等待15秒后检查是否有从机当选主机,然后重启主机,检查是否成为新主机的从机

如果redis集群搭建失败该怎么操作?
1.关闭redis的所有服务器
2.删除所有的文件,只保留redis.conf文件

[root@localhost cluster]# rm -rf 700*/dump.rdb
[root@localhost cluster]# rm -rf 700*/nodes.conf

3.重启redis
sh start.sh

4.重新搭建集群的指令

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

面试题
1.redis集群中最多存储16384个 错误
解释:redis的hash槽算法,只能判断某个数据属于哪台管理,至于数据存储多少个,取决于redis的内存决定
crc16(“key1”)%16384=1000
crc16(“key2”)%16384=1000
计算只能哪块存储,

2.redis集群中最多有多少台主机??? 16384台主机
一块区域由一个redis管理. 一般工作中使用30-80 够用即可.

编辑redis的properties文件

#配置redis单台
#redis.host=192.168.126.129
#redis.port=6379
​
#配置redis分片机制
#redis.shards=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381

#配置redis集群
redis.cluster=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

编辑配置类(redis集群)

@Configuration  //标识配置类  一般和@Bean注解联用
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {

@Value("${redis.cluster}")
private String nodes;   //node,node,node

//配置redis集群
@Bean
public JedisCluster   jedisCluster() {
//1.定义redis链接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(1000);  //线程存活时间
poolConfig.setMaxIdle(20);  //最大空闲数量

//2.准备redis节点信息
Set<HostAndPort> set = new HashSet<>();
String[] nodeArray = nodes.split(","); //分割节点信息
for (String node : nodeArray) {   //host:port
String host = node.split(":")[0];  //[0] 指的是分隔符之前
int port = Integer.parseInt(node.split(":")[1]); //[1]指的是分隔符之后
set.add(new HostAndPort(host, port));
}
return new JedisCluster(set, poolConfig);
}

编辑CacheAOP(redis集群)

@Aspect   //使该类成为切面类
@Component  //把切面类加入到IOC容器中
public class CacheAOP {

@Autowired(required = false)  //  使用到该依赖注入才起效
private JedisCluster jedis;  //集群
//private ShardedJedis jedis;  //引入分片机制
//private Jedis jedis;  //单台

/**
* 规定:ProceedingJoinPoint  参数必须位于第一位
* 1,利用切入点表达式拦截@CacheFind注解,同时获取CacheFind注解对象
* 2.自定义key
* 3.根据key查询缓存
*   有数据,则返回对象
*   没有数据,则查询数据库,之后保存到缓存
*
*   反射相关:
*
*  Method method =
joinPoint.getTarget()   //获取目标对象
.getClass()    //目标对象的class
.getMethod("findItemCatList", Long.class); //方法
//从方法对象中获取返回值类型
Class returnClass = method.getReturnType();
* @throws Throwable
*/
@SuppressAjWarnings("unchecked")  //压制警告注解  unchecked行了未检查的转换时的警告
//@Around("@annoation(com.jt.anno.cacheFind)")
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
Object result = null;
System.out.println("环绕通知开始");
try {
Object[] ages = joinPoint.getArgs(); //目标方法参数
String key = cacheFind.prekey()+"::"+Arrays.toString(ages);
//根据key查询redis
if(!jedis.exists(key)) {
//如果key不存在,则执行目标方法

result = joinPoint.proceed();
System.out.println("查数据库");

//调用业务方法
//将数据存入缓存中redis
String json = ObjectMapperUtil.toJSON(result);

int seconds = cacheFind.seconds();
if (seconds>0)
//表示用户需要设置超时时间
jedis.setex(key, seconds, json);
else
//表示用户不需要设置超时时间
jedis.setnx(key, json);
}else {
//如果redis中有缓存,则将json串转化为对象之后返回
String json = jedis.get(key);//获取json
//如何获取方法的返回值类型?先获取方法对象
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();//获取对象的方法
result = ObjectMapperUtil.toObj(json, methodSignature.getReturnType());
System.out.println("AOP缓存");
}
}catch(Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知结束");
return result;
}
@Around("@annotation(cacheUpdate)")
//@Around("@annoation(com.jt.anno.cacheUpdate)")
public Object updateAround(ProceedingJoinPoint joinPoint,CacheUpdate cacheUpdate) {
/**
* 缓存更新AOP实现 首选环绕通知
* 要求:
* 执行目标方法
* 将返回值更新redis缓存
*/
try {
//暂时写死
ItemCat itemCat = (ItemCat)joinPoint.proceed();
String key = cacheUpdate.prekey()+"::+["+itemCat.getId()+"]";
String json = ObjectMapperUtil.toJSON(itemCat);
if (cacheUpdate.seconds()>0) {
//表示用户需要设置超时时间
jedis.setex(key, cacheUpdate.seconds(), json);
}else {
jedis.set(key, json);
}
return itemCat;
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: