勾哥:昨天发了一篇翻译,英语水平一般般的我抠了半天字眼,一个 word 一个 word 翻译过来,竟然被举报了?!
哈?举报的那位兄弟你是盐吃多么
今天上一篇缓存的常见问题,对很多开发老哥都能有帮助,尽量没搞难度特别大,写的简单的很!有意见可以正常反馈~
(女神带我避开杠精!)
~~~以下正文~~~
对使用缓存时常遇到几个问题,整理出了一个表格。
1. 缓存更新方式
第一个问题是缓存更新方式,这是决定在使用缓存时就该考虑的问题。
缓存的数据在数据源发生变更时需要对缓存进行更新,数据源可能是 DB,也可能是远程服务。
更新的方式可以是主动更新。
数据源是 DB 时,可以在更新完 DB 后就直接更新缓存。
当数据源不是 DB 而是其他远程服务,可能无法及时主动感知数据变更,这种情况下一般会选择对缓存数据设置失效期,也就是数据不一致的最大容忍时间。
这种场景下,可以选择失效更新,key 不存在或失效时先请求数据源获取最新数据,然后再次缓存,并更新失效期。
但这样做有个问题,如果依赖的远程服务在更新时出现异常,则会导致数据不可用。
改进的办法是异步更新,就是当失效时先不清除数据,继续使用旧的数据,然后由异步线程去执行更新任务。这样就避免了失效瞬间的空窗期。
另外还有一种纯异步更新方式,定时对数据进行分批更新。实际使用时可以根据业务场景选择更新方式。
2. 数据不一致
第二个问题是数据不一致的问题,可以说只要使用缓存,就要考虑如何面对这个问题。
缓存不一致产生的原因一般是主动更新失败,例如更新 DB 后,更新 Redis 因为网络原因请求超时;或者是异步更新失败导致。
解决的办法——如果服务对耗时不是特别敏感可以增加重试。
如果服务对耗时敏感可以通过异步补偿任务来处理失败的更新。
或者短期的数据不一致不会影响业务,那么只要下次更新时可以成功,能保证最终一致性就可以。
3. 缓存穿透
第三个问题是缓存穿透。
产生这个问题的原因可能是外部的恶意攻击,例如,对用户信息进行了缓存,但恶意攻击者使用不存在的用户 ID 频繁请求接口,导致查询缓存不命中,然后穿透 DB 查询依然不命中。这时会有大量请求穿透缓存访问到 DB。
解决的办法——对不存在的用户,在缓存中保存一个空对象进行标记,防止相同 ID 再次访问 DB,不过有时这个方法并不能很好解决问题,可能导致缓存中存储大量无用数据。
使用 BloomFilter 过滤器,BloomFilter 的特点是存在性检测,如果 BloomFilter 中不存在,那么数据一定不存在;如果 BloomFilter 中存在,实际数据也有可能会不存在。非常适合解决这类的问题。
4. 缓存击穿
第四个问题是缓存击穿,就是某个热点数据失效时,大量针对这个数据的请求会穿透到数据源。
解决这个问题有这些办法——可以使用互斥锁更新,保证同一个进程中针对同一个数据不会并发请求到 DB,减小 DB 压力。
使用随机退避方式,失效时随机 sleep 一个很短的时间,再次查询,如果失败再执行更新。
针对多个热点 key 同时失效的问题,可以在缓存时使用固定时间加上一个小的随机数,避免大量热点 key 同一时刻失效。
5. 缓存雪崩
第五个问题是缓存雪崩。产生的原因是缓存挂掉,这时所有的请求都会穿透到 DB。
解决方法——使用快速失败的熔断策略,减少 DB 瞬间压力。
使用主从模式和集群模式来尽量保证缓存服务的高可用。
实际场景中,这两种方法会结合使用。
考察点与加分项
这部分主要面试考察点是对缓存特性的理解,对 MC、Redis 的特点和使用方式的掌握。
1. 要知道缓存的使用场景,不同类型缓存的使用方式,例如:对 DB 热点数据进行缓存减少 DB 压力;对依赖的服务进行缓存,提高并发性能
单纯 K-V 缓存的场景可以使用 MC,而需要缓存 list、set 等特殊数据格式,可以使用 Redis
需要缓存一个用户最近播放视频的列表可以使用 Redis 的 list 来保存、需要计算排行榜数据时,可以使用 Redis 的 zset 结构来保存
2. 要了解 MC 和 Redis 的常用命令,例如:原子增减、对不同数据结构进行操作的命令等
了解 MC 和 Redis 在内存中的存储结构,这对评估使用容量会很有帮助
了解 MC 和 Redis 的数据失效方式和剔除策略,比如主动触发的定期剔除和被动触发延期剔除
3. 要理解 Redis 的持久化、主从同步与 Cluster 部署的原理,例如:RDB 和 AOF 的实现方式与区别
如果想要在面试中获得更好的表现,还应了解下面这些加分项。
1. 要结合实际应用场景来介绍缓存的使用,例如:调用后端服务接口获取信息时,可以使用本地+远程的多级缓存
对于动态排行榜类的场景可以考虑通过 Redis 的 sorted set 来实现等等
2. 最好有过分布式缓存设计和使用经验,例如:项目中在什么场景使用过 Redis,使用了什么数据结构,解决哪类的问题
使用 MC 时根据预估值大小调整 McSlab 分配参数等等
3. 最好可以了解缓存使用中可能产生的问题,例如:Redis 是单线程处理请求,应尽量避免耗时较高的单个请求任务,防止相互影响
Redis 服务应避免和其他 CPU 密集型的进程部署在同一机器
禁用 Swap 内存交换,防止 Redis 的缓存数据交换到硬盘上,影响性能
MC 钙化问题等等
4. 要了解 Redis 的典型应用场景,例如:使用 Redis 来实现分布式锁
使用 Bitmap 来实现 BloomFilter
使用 HyperLogLog 来进行 UV 统计等等
5. 知道 Redis4.0、5.0 中的新特性,例如:支持多播的可持久化消息队列 Stream
通过 Module 系统来进行定制功能扩展等等
~~~以上~~~