前言
相关系列
- 《Redis & 目录》
- 《Redis & 实战 & 源码》
- 《Redis & 实战 & 总结》
- 《Redis & 实战 & 问题》
什么缓存击穿?怎么避免?
所谓缓存击穿是指请求因缓存失效而直接访问数据库的情况,由于热点数据访问者众多的原因,该情况会有很大概率导致数据库压力在短时间内骤增,从而影响程序的性能乃至令其崩溃…避免缓存击穿的常用解决方案如下:
- 设置热点数据永不过期;
- 对向数据库请求的过程加互斥锁。
什么是缓存雪崩?怎么避免?
所谓缓存雪崩是缓存击穿的并发情况,即短时间内有大量缓存失效而导致更大数量的请求直接访问数据库…避免缓存雪崩的常用解决方案如下:
- 设置热点数据永不过期;
- 为热点数据设置不同的存活时间;
- 使用惰性缓存方案,确保热点数据只在使用时才被缓存,从而分散热点数据的缓存时间;
- 对向数据库请求的过程加互斥锁;
- 将热点数据的缓存更新交由专属的后台线程处理,而后台线程则需频繁检查缓存是否失效,并在失效时及时加载缓存(不推荐)。
什么是缓存穿透?怎么避免?
所谓缓存穿透是指在缓存&数据库都不存在指定数据的情况下请求持续向数据库访问而导致数据库压力增大的情况…避免缓存传统的常用解决方案如下:
- 对向数据库请求的过程加互斥锁;
- 在数据库不存在热点数据的情况下缓存标识不存在的默认数据。不建议存null,因为存null存在两意性,建议存空对象;
- 在程序层面对不合法的数据键进行拦截;
- 采用布隆过滤器缓存所有已存在数据键的哈希值,从而过滤掉键不存在的请求。
什么是缓存预热?
所谓缓存预热是指在程序上线时便将热点数据加载至缓存中,从而避免请求向数据库访问的情况发生。注意!预热的数据通常不设置过期时间,因为其失效会因为难以“快速”恢复而导致程序不可用。也因此如果程序使用了缓存预热,那么Redis的淘汰策略也要注意不要覆盖到永久存活的数据上…缓存预热的常用解决方案如下:
- 编写相应的数据预热接口,并在程序上后手动调用;
- 在程序自动调用数据预热接口;
- 定时器定时调用数据预热接口。
什么是缓存降级?
所谓缓存降级是指在缓存服务器宕机时直接返回默认数据的情况。在高并发环境中,缓存服务器宕机会在无异常处理的情况下导致程序直接崩溃;或是在有异常处理的情况下导致请求直接向数据库访问,并进一步造成程序性能骤降乃至崩溃的情况发生。而为了避免上述情况程序则可以使用缓存降级的方式对之进行处理,即在服务器宕机时直接返回默认数据。
需要注意的是!缓存降级这种处理方案并不具备通用性,即并非所有程序/业务在遭遇缓存服务器宕机时都可以使用缓存降级来处理。这是因为缓存降级对程序/业务的影响是有损的,即其大概率会导致程序的运行结果错误。因此开发者在使用缓存降级前必须要先确保错误的运行结果造成的各方面影响是可控的,否则就会给自身/公司带来诸多麻烦。这其中的典型就是涉及到金钱的业务是绝对不能使用缓存降级的。
如何保证缓存与数据库双写时的数据一致性?
保证数据一致性的通用方案是先写数据库再写缓存,因为数据只有在被持久化后才能为缓存的首次/再次构建提供可靠基础。而由于缓存具备多种构建方式的原因,数据在具体写入缓存时的行为也会有所变化。缓存通常由两种构建方式:一是在插入/更新时永久缓存;二是在查询时定时缓存。对于前者数据通常会在写入数据库后直接写入缓存,这是为了避免读线程对数据库的查询;而后者则会在数据写入数据库中后删除原缓存,从而令新缓存得以在查询时重新构建。
需要注意的是!在不加锁的情况下,想要保证数据的强一致性是不可能的。但又因为“绝对完善”的加锁会对程序的性能造成严重损失,因此出于性能/开销/安全等多方面考量我们通常只追求数据的弱/最终一致性。
如何优化Redis大量数据的导入/导出?
- 使用管道技术向/令Redis服务器一次性发送/执行多个指令,从而避免网络多次传输指令/数据所造成的性能损耗;
- 向/令服务端发送/执行包含所有指令的Lua脚本,从而避免网络多次传输指令/数据的同时增强执行指令的执行效率。
如何找出Redis中指定前缀的所有键?
- 使用{KEYS}指令进行同步查询,但可能阻塞Redis的内存读/写,因此不推荐;
- 使用{SCAN}指令进行异步查询,不会阻塞Redis的内存读/写,推荐。但查询结果可能重复,因此需要视情况进行去重。
如何使用Redis实现队列?
- 采用列表类型,并令生产者/消费者使用{RPUSH}/{LPOP/BLPOP}指令向尾部插入/从头部移除数据。{LPOP/BLPOP}指令用于实现移除的特殊值/阻塞形式;
- 直接使用Redis的发布/订阅功能,但数据不会被持久化,因此消费者下线时数据会丢失。
如何使用Redis实现延时队列?
使用有序集合类型,将数据的score @ 分数用来保存实际的可移除时间,并令消费者只移除已到移除时间的数据或先查看分数最小的数据是否可被移除。消息内容作为key,调用zadd来生产消息,消费者使用zrangbyscore获取n秒之前的数据做轮询处理。