熟练掌握Redis缓存技术?
那么请问Redis缓存中有几种读写策略,又是如何保证与数据库的一致性问题
今天来聊一聊常用的三种缓存读写策略
首先我们来思考一个问题
服务端到底是先更新db还是先更新cache
如果先更新缓存
写
- 先更新缓存
- 再更新数据库
首先如果缓存更新成功但数据库更新失败,会导致数据不一致的问题
其次当请求A发起写请求,先更新缓存,于此同时请求B发起读请求,返回数据后,数据库被更新,照成了数据不一致的情况
这种概率大吗?
大,因为redis操作比数据库操作快的多,很容易发生
redis为什么那么快?
第一,Redis 的大部分操作在内存上完成,内存操作本身就特别快;
第二,Redis追求极致,选择了很多高效的数据结构,并做了非常多的优化,比如 hash,跳表,有时候一种对象底层有几种实现以应对不同场景。
第三,Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
如果先更新数据库
写
- 先更新数据库
- 再更新缓存
请求A发起写请求,将数据库更新成功,于此同时请求B发起写请求,在A成功修改数据库后也将数据库更新成功,并在请求A之前更新缓存,随后请求A更新缓存
数据库的数据是第二次更新操作的数据,而缓存确还是第一次更新操作的数据,也就是出现了数据库和缓存的数据不一致的问题
都不对,选择删除缓存
不更新缓存,而是删除缓存中的数据。然后,到读取数据时,发现缓存中没了数据之后,再从数据库中读取数据,更新到缓存中,那么到底是先删除缓存,还是先更新数据库呢
如果先删除缓存
假设请求A发起写请求,于是他先删除缓存,于此同时请求B发起读请求,缓存未击中,那么查询数据库,查询成功后将数据写入缓存中,随后请求A修改数据库
数据发生了不一致
如果先更新数据库
假设请求A发起读请求,请求未命中缓存,查询数据库,在未写入缓存时有个请求B发起写请求,修改数据库后删除缓存,随后请求A写入缓存
数据发生了不一致
但我们之前说过,redis的速度快于数据库,几乎不可能发生这种情况
所以最后选择先更新数据库,而这种思想正是我们的Cache Aside
Cache Aside Pattern
Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景,服务端需要同时维系 db 和 cache,并且是以 db 的结果为准
读
- 查询缓存,缓存中查询到了直接返回
- 查询不到时查询数据库,
- 查询完数据库后将数据更新至缓存
写
- 修改数据库
- 删除缓存
那么能不能先删除缓存再更新数据库呢?
答案是 不能,这样会导致数据的不一致性
当请求A 发起写请求,此时删除缓存,同时请求B发起读请求,由于没有缓存查询数据库,随后请求A更新数据库
通常情况下,查询数据库的速度比修改数据库更快。这是因为查询操作通常只涉及对数据库中的数据进行读取和匹配,并且可以使用合适的索引来加速查询过程。相比之下,修改操作需要对数据库中的数据进行写入和更新,可能还需要触发额外的数据库约束、触发器或日志记录等操作,这些都会增加一定的开销和时间。
那么是不是先更新数据库再删除缓存是不是就没有数据不一致的情况呢?
答案是 并不是
当请求A发起读请求,恰巧此时缓存过期,需要查询数据库,此时请求B发起写请求,由于没有缓存,故不会执行删除缓存操作,请求A查询完数据库将数据写入缓存,请求B随后更新数据库
但因为要同时达成读缓存时缓存失效并且有并发写的操作,而操作缓存比操作数据库要快得多,所以概率要小很多
那么如何解决这种情况呢?
更新完数据后的时候同时更新缓存,并且我们需要加一个锁/分布式锁来保证更新 cache 的时候不存在线程安全问题,确保数据库和缓存的强一致问题
那么对于首次请求一定不存在cache的情况如何解决呢?
可以设置定时任务将热点数据提前放入 cache 中
Read/Write Through
原理:Read/Write Through原理是把更新数据库的操作由缓存代理,cache 服务负责将此数据读取和写入 db,从而减轻了应用程序的职责。
Read Through:如果命中缓存则直接返回数据,如果没有命中则查询数据库,随后写入到缓存中并返回
Write Through:当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由缓存自己更新数据库(这是一个同步操作)。
Write Behind
原理:在更新数据的时候,只更新缓存,不更新数据库,而缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作非常快,带来的问题是,数据不是强一致性的,而且可能会丢。
对比Read/Write Through 是同步更新 cache 和 db,而 Write Behind 则是只更新缓存,不直接更新 db,而是改为异步批量的方式来更新 db
非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量