首页 >> 大全

1、Redis 怎么保证高可用、有哪些集群模式?

2024-01-08 大全 36 作者:考证青年

1、Redis 怎么保证高可用、有哪些集群模式?

Redis 保证高可用可以通过:主从复制、哨兵模式、集群模式。

① 主从复制 ② 哨兵

1)哨兵故障检测

在默认情况下, 会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他 在内)发送 PING 命令,并通过实例返回的 PING 命令回复来判断实例是否在线。

如果一个实例在 down-after- 毫秒内,连续向 返回无效回复,那么 会修改这个实例所对应的实例结构,在结构的 flags 属性中设置 标识,以此来表示这个实例已经进入主观下线状态。

当 将一个主服务器判断为主观下线之后,为了确定这个主服务器是否真的下线了,它会向同样监视这一服务器的其他 进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。

当 从其他 那里接收到足够数量(,可配置)的已下线判断之后, 就会将服务器置为客观下线,在 flags 上打上 标识,并对主服务器执行故障转移操作

2)哨兵故障转移流程:

当哨兵监测到某个主节点客观下线之后,就会开始故障转移流程。核心流程如下:

发起一次选举,选举出领头 领头 在已下线主服务器的所有从服务器里面,挑选出一个从服务器,并将其升级为新的主服务器。领头 将剩余的所有从服务器改为复制新的主服务器。领头 更新相关配置信息,当这个旧的主服务器重新上线时,将其设置为新的主服务器的从服务器。 ③ 集群模式

哨兵模式最大的缺点就是所有的数据都放在一台服务器上,无法较好的进行水平扩展。

为了解决哨兵模式存在的问题,集群模式应运而生。在高可用上,集群基本是直接复用的哨兵模式的逻辑,并且针对水平扩展进行了优化。

2、Redis 事务的实现

一个事务从开始到结束通常会经历以下3个阶段:

1)事务开始:multi 命令将执行该命令的客户端从非事务状态切换至事务状态,底层通过 flags 属性标识。

2)命令入队:当客户端处于事务状态时,服务器会根据客户端发来的命令执行不同的操作:

3)事务执行:当一个处于事务状态的客户端向服务器发送 exec 命令时,服务器会遍历事务队列,执行队列中的所有命令,最后将结果全部返回给客户端。

不过 redis 的事务并不推荐在实际中使用,如果要使用事务,推荐使用 Lua 脚本,redis 会保证一个 Lua 脚本里的所有命令的原子性。

3、Redis 如何实现分布式锁? ① 加锁

加锁通常使用 set 命令来实现,伪代码如下:

set key value PX milliseconds NX

几个参数的意义如下:

② 解锁

解锁需要两步操作:

由于当前 Redis 还没有原子命令直接支持这两步操作,所以当前通常是使用 Lua 脚本来执行解锁操作,Redis 会保证脚本里的内容执行是一个原子操作。

脚本代码如下,逻辑比较简单:

if redis.call("get",KEYS[1]) == ARGV[1]
thenreturn redis.call("del",KEYS[1])
elsereturn 0
end

两个参数的意义如下:

4、Redis 分布式锁过期了,还没处理完怎么办?

集群保证数据一致_redis集群如何保证高可用_

为了防止死锁,我们会给分布式锁加一个过期时间,但是万一这个时间到了,我们业务逻辑还没处理完,怎么办?

首先,我们在设置过期时间时要结合业务场景去考虑,尽量设置一个比较合理的值,就是理论上正常处理的话,在这个过期时间内是一定能处理完毕的。

之后,我们再来考虑对这个问题进行兜底设计。

关于这个问题,目前常见的解决方法有两种:

守护线程“续命”:额外起一个线程,定期检查线程是否还持有锁,如果有则延长过期时间。 里面就实现了这个方案,使用“看门狗”定期检查(每1/3的锁时间检查1次),如果线程还持有锁,则刷新过期时间。超时回滚:当我们解锁时发现锁已经被其他线程获取了,说明此时我们执行的操作已经是“不安全”的了,此时需要进行回滚,并返回失败。 5、缓存穿透

解决方案:

6、缓存击穿

解决方案:

使用 redis 分布式锁的伪代码,仅供参考:

public Object getData(String key) throws InterruptedException {Object value = redis.get(key);// 缓存值过期if (value == null) {// lockRedis:专门用于加锁的redis;// "empty":加锁的值随便设置都可以if (lockRedis.set(key, "empty", "PX", lockExpire, "NX")) {try {// 查询数据库,并写到缓存,让其他线程可以直接走缓存value = getDataFromDb(key);redis.set(key, value, "PX", expire);} catch (Exception e) {// 异常处理} finally {// 释放锁lockRedis.delete(key);}} else {// sleep50ms后,进行重试Thread.sleep(50);return getData(key);}}return value;
}

7、缓存雪崩

解决方案:

8、布隆过滤器

布隆过滤器的特点是判断不存在的,则一定不存在;判断存在的,大概率存在,但也有小概率不存在。并且这个概率是可控的,我们可以让这个概率变小或者变高,取决于用户本身的需求。

布隆过滤器由一个 和 一组 Hash 函数(算法)组成,是一种空间效率极高的概率型算法和数据结构,主要用来判断一个元素是否在集合中存在。

在初始化时, 的每一位被初始化为0,同时会定义 Hash 函数,例如有3组 Hash 函数:hash1、hash2、hash3。

写入流程

当我们要写入一个值时,过程如下,以“”为例:

1)首先将“”跟3组 Hash 函数分别计算,得到 的下标为:1、7、10。

2)将 的这3个下标标记为1。

假设我们还有另外两个值:java 和 ,按上面的流程跟 3组 Hash 函数分别计算,结果如下:

java:Hash 函数计算 下标为:1、7、11

:Hash 函数计算 下标为:4、10、11

查询流程

当我们要查询一个值时,过程如下,同样以“”为例:

1)首先将“”跟3组 Hash 函数分别计算,得到 的下标为:1、7、10。

2)查看 的这3个下标是否都为1,如果这3个下标不都为1,则说明该值必然不存在,如果这3个下标都为1,则只能说明可能存在,并不能说明一定存在。

其实上图的例子已经说明了这个问题了,当我们只有值“”和“”时, 下标为1的有:1、4、7、10、11。

当我们又加入值“java”时, 下标为1的还是这5个,所以当 下标为1的为:1、4、7、10、11 时,我们无法判断值“java”存不存在。

redis集群如何保证高可用__集群保证数据一致

其根本原因是,不同的值在跟 Hash 函数计算后,可能会得到相同的下标,所以某个值的标记位,可能会被其他值给标上了。

这也是为啥布隆过滤器只能判断某个值可能存在,无法判断必然存在的原因。但是反过来,如果该值根据 Hash 函数计算的标记位没有全部都为1,那么则说明必然不存在,这个是肯定的。

降低这种误判率的思路也比较简单:

布隆过滤器的误判率还有专门的推导公式,有兴趣的可以去搜相关的文章和论文查看。

9、如何保证数据库和缓存的数据一致性

由于数据库和缓存是两个不同的数据源,要保证其数据一致性,其实就是典型的分布式事务场景,可以引入分布式事务来解决,常见的有:2PC、TCC、MQ事务消息等。

但是引入分布式事务必然会带来性能上的影响,这与我们当初引入缓存来提升性能的目的是相违背的。

所以在实际使用中,通常不会去保证缓存和数据库的强一致性,而是做出一定的牺牲,保证两者数据的最终一致性。

如果是实在无法接受脏数据的场景,则比较合理的方式是放弃使用缓存,直接走数据库。

保证数据库和缓存数据最终一致性的常用方案如下:

1)更新数据库,数据库产生 。

2)监听和消费 ,执行失效缓存操作。

3)如果步骤2失效缓存失败,则引入重试机制,将失败的数据通过MQ方式进行重试,同时考虑是否需要引入幂等机制。

兜底:当出现未知的问题时,及时告警通知,人为介入处理。

人为介入是终极大法,那些外表看着光鲜艳丽的应用,其背后大多有一群苦逼的程序员,在不断的修复各种脏数据和bug。

10、为什么是让缓存失效,而不是更新缓存

1)更新缓存

案例如下,有两个并发的写请求,流程如下:

分析:数据库中的数据是请求B的,缓存中的数据是请求A的,数据库和缓存存在数据不一致。

2)失效(删除)缓存

案例如下,有两个并发的写请求,流程如下:

分析:由于是删除缓存,所以不存在数据不一致的情况。

结论:通过上述案例,可以很明显的看出,失效缓存是更优的方式。

文章参考:全网最硬核 Redis 高频面试题解析(2021年最新版)

总结的面试题也挺费时间的,文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支持一下,后续会亿点点的更新!

为了帮助更多小白从零进阶 Java 工程师,从CSDN官方那边搞来了一套 《Java 工程师学习成长知识图谱》,尺寸 870mm x 560mm,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,有兴趣的小伙伴可以了解一下,当然,不管怎样博主的文章一直都是免费的~

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了