Redis 面试题总结_举例其中一点,sds中,o(1)时间复杂度,就可以获取字符串长度;而c 字符串,需要遍历整(1)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

在这里插入图片描述

RDB 的优点

  • 适合大规模的数据恢复场景,如备份,全量复制等

RDB缺点

  • 没办法做到实时持久化/秒级持久化。
  • 新老版本存在RDB格式兼容问题

在生成 RDB期间,Redis 可以同时处理写请求么?
可以的,Redis提供两个指令生成RDB,分别是 save 和 bgsave

  • 如果是 save 指令,会阻塞,因为是主线程执行的。
  • 如果是 bgsave 指令,是 fork 一个子进程来写入 RDB 文件的,快照持久化完全交给子进程来处理,父进程则可以继续处理客户端的请求。
AOF(append only file) 持久化

采用日志的形式来记录每个写操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据。它主要解决数据持久化的实时性问题。默认是不开启的。

AOF的工作流程如下
在这里插入图片描述
AOF的优点

数据的一致性和完整性更高
AOF的缺点

AOF记录的内容越多,文件越大,数据恢复变慢。

其实 RDB 和 AOF 两种方式也可以同时使用,在这种情况下,如果 redis 重启的话,则会优先采用 AOF 方式来进行数据恢复,这是因为 AOF 方式的数据恢复完整度更高。

如果你没有数据持久化的需求,也完全可以关闭 RDB 和 AOF 方式,这样的话,redis 将变成一个纯内存数据库。


缓存穿透/缓存雪崩?如何解决?

一个常见的缓存使用方式:读请求来了,先查下缓存,缓存有值命中,就直接返回;缓存没命中,就去查数据库,然后把数据库的值更新到缓存,再返回。

缓存穿透

一般的缓存系统,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去后端系统查找(比如DB 数据库)。一些恶意的请求会故意查询不存在的 key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

缓存穿透一般都是这几种情况产生的:

业务不合理的设计,比如大多数用户都没开守护,但是你的每个请求都去缓存,查询某个userid查询有没有守护。
业务/运维/开发失误的操作,比如缓存和数据库的数据都被误删除了。
黑客非法请求攻击,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。

如何解决?

  • 如果是非法请求,我们在API入口,对参数进行校验,过滤非法值。
  • 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 之后清理缓存。
  • 对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过该Bitmap 过滤。
缓存雪崩

当缓存服务器重启或者大量缓存集中在某一时间段失效,这样在失效的时候,会给后端系统带来很大的压力,导致系统崩溃。

如何解决?

  • 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其它线程等待;
  • 做二级缓存,A1 为原始缓存,A2 为拷贝缓存,A1 失效时,可以访问 A2,A1 缓存失效时间设置为短期,A2 设置为长期;
  • 不同的 key,设置不同的过期时间,让缓存失效的时间尽量均匀;
缓存击穿

指热点 key 在某个时间点过期的时候,而恰好在这个时间点对这个 Key 有大量的并发请求过来,从而大量的请求打到 DB。

缓存击穿和缓存雪崩看着有点像,其实它两区别是,缓存雪奔是指数据库压力过大甚至 down 机,缓存击穿只是大量并发请求到了 DB 数据库层面。可以认为击穿是缓存雪崩的一个子集吧

如何解决?

  • 使用互斥锁方案。缓存失效时,不是立即去加载 DB 数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载 DB 数据库数据和设置缓存。否则就去重试获取缓存。
  • “永不过期”,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间。

怎么保证缓存和数据库数据的一致性?

1、淘汰缓存

数据如果比较复杂,进行缓存的更新操作就会变得异常复杂,因此一般推荐选择淘汰缓存,而不是更新缓存。

2、选择先淘汰缓存,再更新数据库

假如先更新数据库,再淘汰缓存,如果淘汰缓存失败,那么后面的请求都会得到脏数据,直至缓存过期。

假如先淘汰缓存再更新数据库,如果更新数据库失败,只会产生一次缓存穿透,相比较而言,后者对业务则没有本质上的影响。

3、延时双删策略

如下场景:同时有一个请求 A 进行更新操作,另一个请求 B 进行查询操作。

  1. 请求 A 进行写操作,删除缓存
  2. 请求 B 查询发现缓存不存在
  3. 请求 B 去数据库查询得到旧值
  4. 请求 B 将旧值写入缓存
  5. 请求 A 将新值写入数据库
public void write(String key,Object data){
    redisUtils.del(key);
    db.update(data);
    Thread.Sleep(100);
    redisUtils.del(key);
}

这么做,可以将1秒内所造成的缓存脏数据,再次删除。这个时间设定可根据俄业务场景进行一个调节。

4、数据库读写分离的场景

两个请求,一个请求 A 进行更新操作,另一个请求B进行查询操作。

  1. 请求 A 进行写操作,删除缓存
  2. 请求 A 将数据写入数据库了,
  3. 请求 B 查询缓存发现,缓存没有值
  4. 请求 B 去从库查询,这时,还没有完成主从同步,因此查询到的是旧值
  5. 请求 B 将旧值写入缓存
  6. 数据库完成主从同步,从库变为新值
    依旧采用延时双删策略解决此问题。

Redis 有哪些架构模式

单机版

特点:

  • 简单

问题:

  • 内存容量有限
  • 处理能力有限
  • 无法高可用。
主从模式

Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而通过复制创建出来的服务器复制品则为从服务器(slave)。

只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步给 从服务器,从而一直保证主从服务器的数据相同。

特点:

  • master/slave 角色
  • master/slave 数据相同
  • 降低 master 读压力在转交从库

问题:

  • 无法保证高可用
  • 没有解决 master 写的压力
哨兵模式

Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:

  • 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
  • 提醒(Notification):当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
  • 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。

特点:

  • 保证高可用
  • 监控各个节点
  • 自动故障迁移

缺点:

  • 主从模式,切换需要时间丢数据
  • 没有解决 master 写的压力
集群(代理型)

Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器;Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。

特点:

  • 多种 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins
  • 支持失败节点自动删除
  • 后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操作单个 Redis 一致

缺点:

  • 增加了新的 proxy,需要维护其高可用。
  • failover 逻辑需要自己实现,其本身不能支持故障的自动转移可扩展性差,进行扩缩容都需要手动干预
集群(直连型)## 标题

从 redis 3.0 之后版本支持 redis-cluster 集群,Redis-Cluster 采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

特点:

  • 无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。
  • 数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
  • 可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。
  • 高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本
  • 实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色提升。

缺点:

  • 资源隔离性较差,容易出现相互影响的情况。
  • 数据通过异步复制,不保证数据的强一致性
  • 高可用Redis架构分析搭建,可以参考:

Redis 过期键的删除策略?

1.定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时, 立即执行对键的删除操作。

2.惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是 否过期, 如果过期的话, 就删除该键;如果没有过期, 就返回该键。

3.定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至 于要删除多少过期键, 以及要检查多少个数据库, 则由算法决定。

Redis 有哪几种数据淘汰策略?

  1. volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
  2. allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
  3. volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。
  4. allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰
  5. volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;。
  6. allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
  7. volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰;
  8. noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。

热 Key 问题,如何解决

什么是热Key呢?在Redis中,我们把访问频率高的key,称为热点key。

**热点Key是怎么产生的呢?**主要原因有两个:

  • 用户消费的数据远大于生产的数据,如秒杀、热点新闻等读多写少的场景。
  • 请求分片集中,超过单 Redis 服务器的性能,比如固定名称 key,Hash 落入同一台服务器,瞬间访问量极大,超过机器瓶颈,产生热点 Key 问题。

那么在日常开发中,如何识别到热点key呢?

  • 凭经验判断哪些是热Key;
  • 客户端统计上报;
  • 服务代理层上报

如何解决热key问题?

  • Redis 集群扩容:增加分片副本,均衡读流量;
  • 将热 key 分散到不同的服务器中;
  • 使用二级缓存,即 JVM 本地缓存,减少 Redis 的读请求。

MySQL 与 Redis 如何保证双写一致性

  • 缓存延时双删
  • 删除缓存重试机制
  • 读取 biglog 异步删除缓存
延时双删

什么是延时双删呢?流程图如下:
在这里插入图片描述
延时双删流程

  1. 先删除缓存
  2. 再更新数据库
  3. 休眠一会(比如1秒),再次删除缓存。
    这个休眠一会,一般多久呢?都是1秒?

这个休眠时间 = 读业务逻辑数据的耗时 + 几百毫秒。为了确保读请求结束,写请求可以删除读请求可能带来的缓存脏数据。

这种方案还算可以,只有休眠那一会(比如就那1秒),可能有脏数据,一般业务也会接受的。但是如果第二次删除缓存失败呢?缓存和数据库的数据还是可能不一致,对吧?给 Key 设置一个自然的 expire 过期时间,让它自动过期怎样?那业务要接受过期时间内,数据的不一致咯?还是有其他更佳方案呢?

删除缓存重试机制

因为延时双删可能会存在第二步的删除缓存失败,导致的数据不一致问题。可以使用这个方案优化:删除失败就多删除几次呀,保证删除缓存成功就可以了呀~ 所以可以引入删除缓存重试机制
在这里插入图片描述
删除缓存重试流程

  1. 写请求更新数据库
  2. 缓存因为某些原因,删除失败
  3. 把删除失败的key放到消息队列
  4. 消费消息队列的消息,获取要删除的key
  5. 重试删除缓存操作
读取biglog异步删除缓存

重试删除缓存机制还可以吧,就是会造成好多业务代码入侵。其实,还可以这样优化:通过数据库的binlog 来异步淘汰 key。
在这里插入图片描述
以mysql为例吧

  • 可以使用阿里的canal将binlog日志采集发送到MQ队列里面
  • 然后通过ACK机制确认处理这条更新消息,删除缓存,保证数据缓存一致性

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

pic_center)
以mysql为例吧

  • 可以使用阿里的canal将binlog日志采集发送到MQ队列里面
  • 然后通过ACK机制确认处理这条更新消息,删除缓存,保证数据缓存一致性

[外链图片转存中…(img-jZTtDN8u-1715530411921)]
[外链图片转存中…(img-cxG4kDff-1715530411922)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值