1. redis的数据类型
五种基本数据类型:string/list/hashmap/set/zset
三种特殊数据类型:
geospatial:geo类型,可以推算出地理位置信息,两地之间的距离
bitmap:0或者1的状态,用户状态,比如是否打卡
hyperloglog:数据集合的元素个数,常用于统计网站的uv
数据类型使用场景与底层数据实现
redis底层数据结构
底层数据结构概述:
数据结构底层实现:
2. redis为什么这么快
1.完全基于内存
2.单线程模型处理客户端的请求
3.IO多路复用
4.基于C语言,更好的优化机制,如动态字符串sds
IO多路复用实现机制--详细
3. redis6.0使用了多线程,不会有线程安全问题吗?
不会
其实redis还是用单线程模型处理客户端请求,只不过用多线程处理数据和协议解析。执行命令还是单线程。
redis线程模型
4. redis持久化机制,说说优缺点
数据丢失/性能/数据恢复/文件大小
AOF: redis每执行完一次命令,就会把命令原本的语句记录到一个.aof文件中,然后通过fsync策略将命令执行后的数据持久化到磁盘(不包括读命令)
优点:
1.更好的保护数据不丢失:aof一般会每隔1s,通过后台的线程执行一次fsync操作,即使redis进程挂掉,最多丢失1秒的数据---
2.写入性能高:aof是直接将命令追加到文件末尾
3.适合做灾难性的误删除恢复
缺点:
1.文件很大,一般aof文件比rdb文件大的多
2.需要消耗的性能多:每次命令都要写入
3.数据恢复比较慢,不适合做冷备
RDB:
周期性备份数据,某个时间点redis内存中的数据以二进制的形式写到.rdb文件中,这是redis默认的持久化方式,也就是我们说的快照,采用fork子进程的方式写时同步
优点:
1.fork子进程,对读写性能影响很小
2.能够快速进行大型数据恢复
缺点:
1.可能会丢失较长时间的数据
2.可能有长时间停顿,fork进程这个过程和redis数据量有关,如果redis数据量大,可能导致redis停顿几秒
.aof文件越来越大怎么解决的
5. redis过期删除策略
定时删除: 每一个设置过期时间的key都需要创建一个定时器,到过期时间立即删除。对内存优化,但是需要消耗CPU,影响缓存的影响时间和吞吐量
惰性删除: 只有当访问一个key时才判断是否过期,过期则删除。不影响CPU但是影响内存,可能导致大批量没被访问的key占内存
定期删除: 折中方案,每隔一段时间扫描一定数量expires字典的一定数量的key,可以使CPU和内存达到一个平衡。
6. redis内存淘汰策略
lru:最长时间没有使用,lfu:最不经常使用
1.no-eviction:永不淘汰,直接返回错误
2.allkeys-lru:所有key使用lru算法淘汰
3.volatile-lru:有过期时间的使用lru算法淘汰
4.allkeys-random:所有key随机删除
5.volatile-random:随机删除有过期时间的key
6.volatile-ttl:删除快过期的key
7.volatile-lfu:根据lfu算法从有过期时间的键删除
8.allkeys-lfu:根据lfu算法从所有键删除
7. redis热key怎么解决
1> 结果写到本地缓存
2> 分布到不同机器
3> key设置悠久存储
8. 缓存穿透、击穿、雪崩是什么,怎么解决?
缓存穿透: 缓存和数据库的结构都为空
解决:1.布隆过滤器(待实战) 2.缓存空对象,可以把缓存时间设置的较短些\
缓存击穿: 某个热点key失效,瞬间打爆数据库
解决:1.互斥锁,排队 2.热点key永不过期
缓存雪崩: 短时间内大量key失效,导致大量请求直接查询数据库
解决:1.加锁排队 2.随机缓存时间 3.二级缓存
9. redis有哪些部署方式?
单机、主从复制、集群、哨兵模式
哨兵是一个独立的进程,独立运行。通过命令实现对redis的自动故障转移、集群监控、消息通知等功能
10. 哨兵作用?
- 监控整个主数据库和从数据库,观察他们是否正常运行
- 如果主数据库挂掉了,自动将从数据库升级为主数据库
11. 哨兵选举过程?
- 第一个发现master挂了的哨兵,向每个哨兵发送命令,让对方选举自己成为领头哨兵
- 其他哨兵如果没有选举过其他人,就会将这一票投给第一个发现该master挂了的哨兵
- 第一个发现的哨兵如果发现超过一半投给自己,并且数量也超过了设定的quoram参数,那么选举为领头哨兵
- 如果多个哨兵同时参加选举,就会重复过程,直到选出一个
- 选出领头哨兵后,开始故障修复,从新选出一个从数据库作为新的master
12. 集群模式是怎么存放数据的
一个cluster集群中总共有16384个节点,集群会将这16384个节点平均分配给每个节点,当然,这里的节点指的是每个主节点,
13. 集群故障恢复怎么做
每个节点都会定期的向其他节点发送ping命令,通过有没有收到回复来判断其他节点是否已经下线。
集群判断故障的逻辑和哨兵类似,每个节点会定期向其他节点发送ping命令,通过有没有收到回府判断其他节点是否已经下线。
- 某节点A发现目标节点疑似下线,就会向集群中的其他节点散播信息,其他节点向目标节点发送命令,判断目标节点是否下线
- 如果超过半数节点认为目标节点下线,则目标节点在整个集群下线
14. 主从同步原理
1.新的slave启动,会想master发送一个sync命令。master收到后在后台保存快照,就是rdb持久化。保存快照需要时间,在这期间redis收到的命令会缓存起来。
2.快照完成后,一起和缓存命令打包发给slave
3.slave收到后写到内存。这个操作不会堵塞,可以继续执行命令,具体原因其实是fork了一个子进程,用子进程去完成
4.因为不会阻塞,这部分初始化完成后,当主数据执行了改变数据的命令后,会异步给slave,这就是复制同步阶段。
这个阶段贯穿整个主从同步直到结束
15. 无硬盘复制
redis也支持无硬盘复制,直接通过网络传给slave,避免和硬盘交互,
16. 如何实现redis分布式锁,可能哪些问题?
分布式锁的实现方式:数据库/基于redis(原生redis/redisson/redlock)/zookeeper实现
1. 数据库实现分布式锁
实现原理:
通过数据库实现对访问控制的标示和记录
悲观锁实现:
每次取数据都会加锁,select for update ,数据库会在查询的时候给表加上排他锁
select * from distributed_lock where client_info ='asdfb12345' and resource_name = 'order_in_stock' for update;
乐观锁实现:
每次去拿数据的时候不去加锁,而是在更新的时候判断⼀下在此期间客户端有没有去更新这个数据,可以使⽤版本号机制实现。
优点: 逻辑简单,只需要写sql
不足: 性能一般,并发高就会有问题,尤其是悲观锁
2. redis实现分布式锁
原生redis实现
需要考虑setnx+lua脚本释放
常见问题:
1. master挂掉没来得及同步slave(高可用)
2. 超过超时时间不能使用\
注意的问题:
Redssion实现
Redssion分布式锁实现原理
看门狗逻辑:
客户端1加锁的锁key默认⽣存时间才10秒,如果超过了10秒,客户端的业务逻辑还没执⾏完,怎么办呢?那就⽤到watch dog⾃动延期机制
定时任务会定期检查去续期renewExpirationAsync(threadId).通过源码我们知道,默认情况下,加锁的时间是30秒。如果加锁的业务没有执⾏完,那么到 30-10 = 20秒的时候,就会进⾏⼀次续期,把锁重置成30秒
优点:
实现成本低
支持锁类型较多,可重入锁、公平锁、红锁、读写锁
不足: 安全性不是很高,master挂掉未即使同步slave
3. zookeeper实现分布式锁
实现原理: 通过操作节点来实现
优点: 可靠性高,能解决强一致性问题。即使zk临时宕机,也会自动删除临时节点从而释放锁。
不足: 实现成本高,性能差,需要手动实现。
17. 数据库与redis数据不一致问题?redis与本地缓存不一致问题?
参考文章:mp.weixin.qq.com/s/D4Ik6lTA_…
出现不一致的情况:
通常情况下,更新数据库和更新缓存需要一起进行,但是这就存在谁先谁后的问题。
假如先更新数据库,再更新缓存,数据库更新成功,缓存更新失败,在缓存不失效的情况下,查询的是原来的结果。
假如先更新缓存,再更新数据库,缓存更新成功,数据库更新失败,在这时候缓存失效,查询到的也是原来的结果。
并发情况下同样的道理都会导致数据不一致的问题。
解法1:
删除缓存:先更新数据库+后更新缓存。
解法2:
引入消息队列,异步的失败重试
解法3:
canal+消息队列异步处理
反思: 非要做到强一致,需要引入一致性协议,这样性能肯定会变差,违背了引入缓存提高性能的初衷。
redis缓存与本地缓存不一致: 定时任务刷新。
18. redis实际问题与解决
-
缓存穿透: 布隆过滤器
问题现象:数据查询CPU较高,经过分析日志,有约60-70%为空查询,定位缓存穿透。 优化过程:布隆过滤器 思考:必要的业务监控提前暴露问题 -
集群CPU接近100%
问题现象:集群CPU接近100%
优化过程:
怀疑连接池耗尽,查看没有
根据监控找到大key,定位业务代码有循环请求。
紧急回滚,优化代码逻辑
思考:
1> 发生某种异常增加,应先分析redis日志或者业务买点,找到具体的key,快速定位具体位置
2> 加强业务监控,建立redis命令QPS趋势图
3> 精准估算集群的吞吐量和业务并发良,合理配置连接池参数 -
现象:Redis内存使用率大于80%,超过10分钟,报警
过程:
1> 查看redis监控,查看突增的命令
2> 定位到具体的key和具体接口
3> 通过分析日志,发现接口请求增加
4> 根据请求业务标记找到请求方沟通
5> 确定正常情况:短期快速扩容,之后进行压缩改造
反思:接口大盘完善 -
现象:命中率低的问题37%
排查解决:命中率低说明没有合理设置过期时间。
1> 梳理核心key和业务逻辑
2> 根据业务场景合理设置时间 -
现象:在监控报警不完善的情况下,某页面白屏,最后定位为redis连接池耗尽
过程:查看error日志,定到到连接池问题,调整连接数
反思:完善监控redis要禁用的命令