Redis 面试必备 X 题
常见面试问题
1. 分布式系统中常用的缓存方案有哪些?
- 客户端缓存:页面和浏览器缓存,app 缓存,h5 缓存,localStorage,sessionStorage
- CDN:内容存储=数据存储,内容分发=负载均衡
- Nginx 缓存: 静态资源
- 服务端缓存:本地缓存,外部缓存
- 数据库缓存:持久缓存(mybatis,hibernate 多级缓存),mysql 查询缓存
- 操作系统缓存:page cache,buffer cache
2. 常见的缓存淘汰算法
- FIFO - 先进先出
- LRU - 最近最少使用
- LFU - 最不经常使用
3. Redis 如何配置 Key 的过期时间?他的实现原理是什么?
- Expire or SETNX
- 原理:
- 定期删除:每隔一段时间,执行一次删除过期 Key 的操作(批量脚本)
- 懒汉式删除:每当使用 get,getset 等指令去获取数据时,判断 key 是否过期,过期的话就先删除再操作
- redis 同时使用两者,平衡执行频率和执行时长
4. Redis 线程模型,单线程为什么快?
- 基于 Reactor 开发了网络时间处理器 - 文件事件处理器,采用 IO 多路复用监听多个 Socket
- 纯内存操作、核心基于非阻塞的 IO 多路复用机制、单线程避免了多线程反复上下文切换的性能问题
5. redis 的常见结构及应用场景
- string
- id/id_info 缓存
- 计数器
- setnx 分布式锁
- setnx 的时候会传入一个随机值
- 解锁:‘if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’, KEYS[1]) else return 0 end’
- lua脚本
- 分布式ID
- sds(动态简单字符串)
- 读取时间复杂度为 O(1)
- 惰性删除,留待下次使用
- 一次分配最大为 128kb
- list
- 当队列用,最近100个购买用户信息
- 当栈用
- 非实时分页列表,比如小时榜,日榜,周榜
- 存储微博、微信公众号等消息流数据
- 等于链表,插入删除 O(1),查找 O(n)
- hash
- 相比string获取单个字段节省 序列化与反序列化操作
- 相当于 HashMap ,由数组加链表组合而成,当一维的 hash 数组碰撞时,用链表串起来
- set
- 取交、并、差集
- 点赞、收藏、关注等…
- kv 模式
- sorted set
- 排行榜功能,实时分页列表,实时榜单等
- set 基础上增加了分数
- 结构上是由一个 dict 和一个跳表组成,dict 保证 key 唯一性
- 插入删除都是 O(log n),查找 O(logn)
- 一大优点是可以对分数进行范围查找
- 少量数据按照 ziplist 存储,大量数据按照跳表存储
redis 大key 问题是什么?怎么查出来?一般怎么解决?
大key问题呢是说 redis 的 kv 存储中,value值过大,一般超过10kb,我们就会认为这是一个大 key 了。
有执行命令,但是没有专门准备这个内容
大 key 的危害主要是:在redis内存中分布不均;操作耗时;取结果的数据量大,容易造成网络io堵塞
解决方式呢:可以逻辑上对于大 key 的 value 进行拆分和重组。其中 string 类型的大 key 一般不建议存到redis。另外的可以采用 hash 将大 key 拆分
6. redis 集群方案
- 主从模式
- 哨兵模式
- 概念
- 集群监控:监控主从是否正常
- 消息通知:故障通知
- 故障转移:主挂了,移到从身上
- 配置中心:通知 client 新的 master 地址
- 本身也是分布式的,具体方案:
- 通常3个哨兵实例来保证健壮性
- 即使哨兵自己挂了,还是可以正常工作
- 不保证数据领丢失,可以说主从结构就不保证
- 判断故障需要用
分布式选举
获得大部分哨兵统一才行
- 概念
- Redis cluster:服务端 Sharding 计数。采用槽的概念,一共16384个槽,请求发送至任意节点
- 方案说明
- 通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据
- 每份数据分片会存储在多个互为主从的多节点上
- 数据先写入主节点,再
阻塞
同步至从节点 - 同一分片之间不保证强一致性
- 扩容时需要把旧节点数据也迁移一部分至新节点
- gossip 协议,多主多从
- 方案说明
- sorted set
- 实时分页列表,如实时榜单
- 一般就是当缓存用
- 单线程模型
- 目的是服务无状态:session,token等;分布式锁
- 无锁化?
2. 单线程还是多线程?
- 工作线程都是单线程:
- 操作是原子的单指令 pipeline
- 事务 vs pipeline :事务执行期间是原子的;执行失败就是失败,其他指令继续执行,没有回滚 –> redis 少使用事务 && 事务内的指令少 + 快
- 6.x+版本出现了 io 多线程
- 详细理解 io 多线程 :内核,网络通信(懂了再说)
- 单线程,满足 redis 的串行原子;io 多线程以后,把输入/输出放到线程中并行,好处是:执行时间快;更好的压榨系统及硬件的资源
3. redis 存在线程安全的问题么?为什么?
- 参考问题2,redis核心是单线程串行,业务使用的时候需要自行保障线程安全
4.
6. 缓存如何淘汰的?
内存空间不足
淘汰机制
lru,lfu,random,ttl
全空间
设置了过期时间的key的集合中
7. 如何进行缓存预热?
提前加载数据(很难判断哪些是真正的热数据,常常会出现缓存失败的情况)
开发逻辑上要应对差集数据造成的 击穿,穿透,雪崩
8. 数据库和缓存不一致如何解决?
恶心点的使用事务,但是意义不大,场景多为读多写极少,仅仅在秀肌肉
业务写db,然后redis更新缓存
业务写到消息队列中,redis和db同时消费数据,同时更新
redis缓存,更倾向于允许稍微的时差
总思路是减少db操作
9. redis 主从不一致如何解决?
redis 默认弱一致性,主从异步同步
分布式锁不能用主从,可以用单实例、分片集群、redlock –> redisson
配置中可以配置同步因子,总趋向于强一致性
10. redis 持久化原理
当前线程阻塞服务
后台异步进程完成持久化
11. 并发超量,redis 崩溃后如何处理?
雪崩击穿穿透处理方案
12. 为啥使用setnx
原子,不存在即创建
分布式锁,用 set k v nx ex 不存在,过期时间,避免死锁
设计短链
base64加密解密。
热url,满了怎么办?对内部?对外部?双方隔离?布隆判存在性?
qps 十几万?保证库存?
分布式事务。看看科科的写法
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Bishop!
评论
GitalkValine