2024 最新Java面试系列——Redis(精简、纯手打)

大家好,我是程序员阿奇。今年找工作确实很难,尤其是对于Java开发者来说,面试中Redis的掌握程度往往成为决定你能否拿到offer的关键因素。Redis作为一个高性能的键值存储系统,已经成为许多公司后端技术栈中不可或缺的一部分。今天,我就来和大家分享一些Redis的面试题目,希望能帮助到正在求职的你。

Redis面试题目

  • Redis有哪些数据类型?

字符串 String、字典 Hash、列表List、集合 Set、有序集合 SortedSet。如果是高级用户,那

么还会有,如果你是 Redis 中高级用户,还需要加上下面几种数据结构 HyperLogLog、

Geo、 Pub/Sube

  • 知道 Redis 的持久化吗?底层如何实现的?有什么优点缺点?

RDB(Redis DataBase: 在不同的时间点将 redis 的数据生成的快照同步到磁盘等介质上):内存到硬盘的快照,定期更新。缺点:耗时,耗性能(fork+io 操作),易丢失数据。
AOF(Append Only File:将 redis 所执行过的所有指令都记录下来,在下次 redis 重启时,只需要执行指令就可以了):写日志。缺点:体积大,恢复速度慢。
bgsave 做镜像全量持久化,aof 做增量持久化。因为 bgsave 会消耗比较长的时间,不够实
时,在停机的时候会导致大量的数据丢失,需要 aof 来配合,在 redis 实例重启时,优先使
用 aof 来恢复内存的状态,如果没有 aof 日志,就会使用 rdb 文件来恢复。Redis 会定期做
aof 重写,压缩 aof 文件日志大小。Redis4.0 之后有了混合持久化的功能,将 bgsave 的全量
和 aof 的增量做了融合处理,这样既保证了恢复的效率又兼顾了数据的安全性。

bgsave 的原理,fork 和 cow, fork 是指 redis 通过创建子进程来进行 bgsave 操作,cow 指的是 copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来

  • Redis 过期策略都有哪些?LRU 算法知道吗?写一下 java 代码实现?

过期策略:
定时过期(一 key 一定时器),惰性过期:只有使用 key 时才判断 key 是否已过期,过期则清
除。定期过期:前两者折中。
LRU:new LinkedHashMap<K, V>(capacity, DEFAULT_LOAD_FACTORY, true);
//第三个参数置为 true,代表 linkedlist 按访问顺序排序,可作为 LRU 缓存;设为 false 代表
按插入顺序排序,可作为 FIFO 缓存
LRU 算法实现:1.通过双向链表来实现,新数据插入到链表头部;2.每当缓存命中(即缓存
数据被访问),则将数据移到链表头部;3.当链表满的时候,将链表尾部的数据丢弃。
LinkedHashMap:HashMap 和双向链表合二为一即是 LinkedHashMap。HashMap 是无序
的,LinkedHashMap 通过维护一个额外的双向链表保证了迭代顺序。该迭代顺序可以是插
入顺序(默认),也可以是访问顺序。

缓存穿透、缓存击穿、缓存雪崩解决方案?

缓存穿透:指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将
导致这个不存在的数据每次请求都要到 DB 去查询,可能导致 DB 挂掉。
解决方案

        1.查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短;

        2.布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。
缓存击穿:对于设置了过期时间的 key,缓存在某个时间点过期的时候,恰好这时间点对
这个 Key 有大量的并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并
回设到缓存,这个时候大并发的请求可能会瞬间把 DB 压垮。

解决方案

        1.使用互斥锁:当缓存失效时,不立即去 load db,先使用如 Redis 的 setnx 去设
置一个互斥锁,当操作成功返回时再进行 load db 的操作并回设缓存,否则重试 get 缓存的
方法。

        2.永远不过期:物理不过期,但逻辑过期(后台异步线程去刷新)。
缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部
转发到 DB,DB 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多 key,击穿是某一个
key 缓存。
解决方案:将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,
比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效
的事件。

使用 Redis 如何设计分布式锁?说一下实现思路?使用 zk 可以吗?如何实现?这两种有什
么区别?

Redis:
        1.线程 A setnx(上锁的对象,超时时的时间戳 t1),如果返回 true,获得锁。
        2.线程 B 用 get 获取 t1,与当前时间戳比较,判断是是否超时,没超时 false,若超时执行第 3 步;
        3.计算新的超时时间 t2,使用 getset 命令返回 t3(该值可能其他线程已经修改过),如果
t1==t3,获得锁,如果 t1!=t3 说明锁被其他线程获取了。
        4.获取锁后,处理完业务逻辑,再去判断锁是否超时,如果没超时删除锁,如果已超时,不用处理(防止删除其他线程的锁)。
zk:
        1.客户端对某个方法加锁时,在 zk 上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点 node1;
        2.客户端获取该路径下所有已经创建的子节点,如果发现自己创建的 node1 的序号是最小的,就认为这个客户端获得了锁。
        3.如果发现 node1 不是最小的,则监听比自己创建节点序号小的最大的节点,进入等待。

        4.获取锁后,处理完逻辑,删除自己创建的 node1 即可。
区别:zk 性能差一些,开销大,实现简单。
 

缓存与数据库不一致怎么办?

假设采用的主存分离,读写分离的数据库,
如果一个线程 A 先删除缓存数据,然后将数据写入到主库当中,这个时候,主库和从库同
步没有完成,线程 B 从缓存当中读取数据失败,从从库当中读取到旧数据,然后更新至缓
存,这个时候,缓存当中的就是旧的数据。
发生上述不一致的原因在于,主从库数据不一致问题,加入了缓存之后,主从不一致的时
间被拉长了
处理思路:
在从库有数据更新之后,将缓存当中的数据也同时进行更新,即当从库发生了
数据更新之后,向缓存发出删除,淘汰这段时间写入的旧数据。

Redis的内存淘汰策略有哪些?

voltile-lru 从已经设置过期时间的数据集中挑选最近最少使用的数据淘汰
voltile-ttl 从已经设置过期时间的数据库集当中挑选将要过期的数据
voltile-random 从已经设置过期时间的数据集任意选择淘汰数据
allkeys-lru 从数据集中挑选最近最少使用的数据淘汰
allkeys-random 从数据集中任意选择淘汰的数据
no-eviction 禁止驱逐数据

由于篇幅有限,上面的只列出了几个高频的题目,如果你想要获取更多的面试题内容,我花了半个月整理的Java面试内容,免费送给大家。

获取Redis相关资料

为了帮助大家更好地准备Redis相关的面试,我整理了一份详细的Redis学习资料。这份资料包含了Redis的基础概念、高级特性、最佳实践以及面试中常见的问题和答案。

想要获取这份资料吗?非常简单,只需关注我的公众号 阿巳杂谈,在后台回复 Redis,即可免费获取这份精心准备的Redis学习资料。这将是你面试准备过程中的一大助力,让你在面试中更加自信。

记住,机会总是留给有准备的人。希望我的分享能够帮助到你,也祝愿每一位正在求职的朋友们都能够顺利找到心仪的工作。如果你有任何问题或者想要交流更多关于Redis的话题,欢迎在评论区留言,我会及时回复大家的。

再次感谢大家的关注,我们下期再见!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员阿奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值