redis知识

251 阅读10分钟

redis知识点.png

1. redis的数据类型

五种基本数据类型:string/list/hashmap/set/zset

三种特殊数据类型:
geospatial:geo类型,可以推算出地理位置信息,两地之间的距离
bitmap:0或者1的状态,用户状态,比如是否打卡
hyperloglog:数据集合的元素个数,常用于统计网站的uv

数据类型使用场景与底层数据实现

juejin.cn/post/710892…

redis底层数据结构

底层数据结构概述:

juejin.cn/post/709233…

数据结构底层实现:

juejin.cn/post/684490…

2. redis为什么这么快

1.完全基于内存
2.单线程模型处理客户端的请求
3.IO多路复用
4.基于C语言,更好的优化机制,如动态字符串sds

IO多路复用实现机制--详细

juejin.cn/post/688298…

WX20220623-093416@2x.png

3. redis6.0使用了多线程,不会有线程安全问题吗?

不会
其实redis还是用单线程模型处理客户端请求,只不过用多线程处理数据和协议解析。执行命令还是单线程。

image.png

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文件越来越大怎么解决的

blog.csdn.net/qq_19595957…

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. 哨兵作用?

  1. 监控整个主数据库和从数据库,观察他们是否正常运行
  2. 如果主数据库挂掉了,自动将从数据库升级为主数据库

11. 哨兵选举过程?

  1. 第一个发现master挂了的哨兵,向每个哨兵发送命令,让对方选举自己成为领头哨兵
  2. 其他哨兵如果没有选举过其他人,就会将这一票投给第一个发现该master挂了的哨兵
  3. 第一个发现的哨兵如果发现超过一半投给自己,并且数量也超过了设定的quoram参数,那么选举为领头哨兵
  4. 如果多个哨兵同时参加选举,就会重复过程,直到选出一个
  5. 选出领头哨兵后,开始故障修复,从新选出一个从数据库作为新的master

12. 集群模式是怎么存放数据的

一个cluster集群中总共有16384个节点,集群会将这16384个节点平均分配给每个节点,当然,这里的节点指的是每个主节点,

13. 集群故障恢复怎么做

每个节点都会定期的向其他节点发送ping命令,通过有没有收到回复来判断其他节点是否已经下线。
集群判断故障的逻辑和哨兵类似,每个节点会定期向其他节点发送ping命令,通过有没有收到回府判断其他节点是否已经下线。

  1. 某节点A发现目标节点疑似下线,就会向集群中的其他节点散播信息,其他节点向目标节点发送命令,判断目标节点是否下线
  2. 如果超过半数节点认为目标节点下线,则目标节点在整个集群下线

14. 主从同步原理

1.新的slave启动,会想master发送一个sync命令。master收到后在后台保存快照,就是rdb持久化。保存快照需要时间,在这期间redis收到的命令会缓存起来。
2.快照完成后,一起和缓存命令打包发给slave
3.slave收到后写到内存。这个操作不会堵塞,可以继续执行命令,具体原因其实是fork了一个子进程,用子进程去完成
4.因为不会阻塞,这部分初始化完成后,当主数据执行了改变数据的命令后,会异步给slave,这就是复制同步阶段。
这个阶段贯穿整个主从同步直到结束

主从同步原理.png

15. 无硬盘复制

redis也支持无硬盘复制,直接通过网络传给slave,避免和硬盘交互,

16. 如何实现redis分布式锁,可能哪些问题?

分布式锁的实现方式:数据库/基于redis(原生redis/redisson/redlock)/zookeeper实现

1. 数据库实现分布式锁

实现原理:

通过数据库实现对访问控制的标示和记录

image2022-3-31_21-19-24.png

悲观锁实现:

每次取数据都会加锁,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脚本释放

image.png

WX20220516-163633@2x.png

WX20220516-163608@2x.png

WX20220516-155445@2x.png

常见问题:
1. master挂掉没来得及同步slave(高可用)
2. 超过超时时间不能使用\

注意的问题:

juejin.cn/post/702551…

Redssion实现

WX20220516-163015@2x.png

Redssion分布式锁实现原理

juejin.cn/search?quer…

看门狗逻辑:

客户端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:
删除缓存:先更新数据库+后更新缓存。

先更新数据库再删除缓存.png

解法2:
引入消息队列,异步的失败重试

redis与数据库不一致失败重试.png

解法3:
canal+消息队列异步处理

引入canal.png

反思: 非要做到强一致,需要引入一致性协议,这样性能肯定会变差,违背了引入缓存提高性能的初衷。

redis缓存与本地缓存不一致: 定时任务刷新。

18. redis实际问题与解决

  1. 缓存穿透: 布隆过滤器
    问题现象:数据查询CPU较高,经过分析日志,有约60-70%为空查询,定位缓存穿透。 优化过程:布隆过滤器 思考:必要的业务监控提前暴露问题

  2. 集群CPU接近100%
    问题现象:集群CPU接近100%
    优化过程:
    怀疑连接池耗尽,查看没有
    根据监控找到大key,定位业务代码有循环请求。
    紧急回滚,优化代码逻辑
    思考:
    1> 发生某种异常增加,应先分析redis日志或者业务买点,找到具体的key,快速定位具体位置
    2> 加强业务监控,建立redis命令QPS趋势图
    3> 精准估算集群的吞吐量和业务并发良,合理配置连接池参数

  3. 现象:Redis内存使用率大于80%,超过10分钟,报警
    过程:
    1> 查看redis监控,查看突增的命令
    2> 定位到具体的key和具体接口
    3> 通过分析日志,发现接口请求增加
    4> 根据请求业务标记找到请求方沟通
    5> 确定正常情况:短期快速扩容,之后进行压缩改造
    反思:接口大盘完善

  4. 现象:命中率低的问题37%
    排查解决:命中率低说明没有合理设置过期时间。
    1> 梳理核心key和业务逻辑
    2> 根据业务场景合理设置时间

  5. 现象:在监控报警不完善的情况下,某页面白屏,最后定位为redis连接池耗尽
    过程:查看error日志,定到到连接池问题,调整连接数
    反思:完善监控

    redis要禁用的命令

image.png