面试系列笔记之redis篇
面试系列笔记-Redis
本文来自
https://github.com/TrumanDu/knowledge/blob/main/%E7%BC%93%E5%AD%98.md
Redis必知知识点
String
内部编码:int(8字节长整型)/embstr(小于等于44字节字符串)/raw(大于44个字节字符串)
适用场景:共享session、分布式锁,计数器、限流、缓存
List
内部编码:`ziplist(同时满足:所有字符串元素的长度都小于64字节,元素数量小于512个)、quicklist
适用场景:消息队列,文章列表
1 | lpush+lpop=Stack(栈) |
ziplist是一段连续内存,节省内存空间。
quicklist 存储了一个双向列表,每个列表的节点是一个ziplist
,
Set
内部编码:intset(整数集合)、hashtable(哈希表)如果集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码
适用场景:用户标签,生成随机数抽奖、社交需求
Hash
内部编码:ziplist(压缩列表)
哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable(哈希表)
适用场景:
SortSet
内部编码:ziplist(压缩列表)
、skiplist(跳跃表)当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码
适用场景:排行榜,社交需求(如用户点赞)。
其他
- Geospatial 存储地理位置信息
- Hyperloglog 基数统计算法的数据结构,可以用来统计数量
- Bitmap 位图,解决大数据利器
Redis事务
Redis 可以通过 MULTI
,EXEC
,DISCARD
和 WATCH
等命令来实现事务功能。不支持原子性,没法进行rollback。
原理:
MULTI
可以等待输入多个命令进入队列,调用EXEC
命令后,才真正执行所有命令。
DISCARD
命令取消一个事务,它会清空事务队列中保存的所有命令。
WATCH
命令用于监听指定的键,当调用 EXEC
命令执行事务时,如果一个被 WATCH
命令监视的键被修改的话,整个事务都不会执行,直接返回失败。
Redis过期策略和内存淘汰策略
过期策略
- 定时扫描,删除过期数据
- 惰性删除,当访问一个key时,如果该key过期,则删除,返回数据不存在。
定时删除逻辑:
1 | Specifically this is what Redis does 10 times per second: |
内存淘汰策略
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
- volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
- allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
- allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
- no-enviction(驱逐):禁止驱逐数据,这也是默认策略。意思是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失。
热key问题
1.什么是热key?
访问评率高的key
热key带来的危害:可能会导致服务器资源不足,影响正常服务。
2.如何发现?
产生原因:
- 热点新闻,秒杀等场景,读远远大于写的场景
- 请求分片集中
如何发现:
- 客户端统计
- 服务代理层发现
- -hotkeys(4.0+),
redis-cli -h 192.168.0.110 -p 6379 --hotkeys
3.如何避免和解决?
- 使用客户端缓存
- redis集群扩容,增加master分片
- 将热点key分散到不同master节点
大key问题
redis value最大值为512M
避免在 Redis 中存储 bigkey,建议:
- String:大小控制在 10KB 以下
- List/Hash/Set/ZSet:元素数量控制在 1 万以下
我们目前发现这类场景,是使用rct离线分析rdb文件得出,当然官方还有bigkey,debug等命令。
Redis高可用实现
- 主从模式
- 哨兵模式
- Cluster集群模式,通信使用Gossip协议
常用的Gossip消息分为4种,分别是:ping、pong、meet、fail。
Cluster分布式算法是Hash slot算法。整个分为16384个slot。
Redis持久化
- RDB
- AOF
- 混合类型
Redis rehash原理
使用两个hash表,渐进式扩容与rehash。在rehash过程,写操作操作的是新的hash,读是先读新的hash,如果读不到再去读旧的hash。
缓存雪崩/ 缓存穿透/ 缓存击穿
缓存雪崩
什么是缓存雪崩?
缓存雪崩是因为大面积的缓存失效,打崩了DB;原因是由于缓存过期时间一致,导致在一段时间内大量缓存过期,请求全部转发到DB,DB瞬时压力过重雪崩。
如何解决?
原因是因为缓存和DB处理能力不同。大量的请求落在DB,承受不了,进而崩溃。
- 解决办法就是避免同时过期,可以增加在ttl再增加随机值
- 使用集群,将热点数据落在不同节点,避免同时失效
- 设置热点数据永不过期,有更新操作就更新缓存就好了
缓存穿透
什么是缓存穿透?
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。而用户(黑客)不断发起请求,这就是漏洞。
如何解决?
- 对于空数据同样写入缓存,null
- 利用布隆过滤器
- 黑名单、用户鉴权
缓存击穿
什么是缓存击穿?
缓存击穿是指一个Key非常热点,在不停地扛着大量的请求,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发直接落到了数据库上,就在这个Key的点上击穿了缓存。并发的请求可能会瞬间把后端DB压垮。
如何解决?
- 永不过期,然后通过定时job去刷新缓存
- 使用互斥锁(mutex key):这种解决方案思路比较简单,就是只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据就可以了。
分布式锁,Redlock
分布式锁实现原理是set命令+lua脚本。redisson使用watch dog解决锁过期问题