方案引入
分布式缓存Redis为保证我们系统的流畅提供了可靠的保证,但是随着系统规模的扩大,缓存的大规模使用,缓存的治理势在必行,因此我们引用了Canal中间件。通过Canal伪装成MySQL的Slave来消费MySQL的Binlog日志,然后将这些日志分发到RabbitMQ的不同队列中(同一个交换器,不同队列,队列名以数据库表名区分),最后由RabbitMQ的消费者来更新缓存。除了这套架构,我们还约定业务代码中尽量不进行缓存写操作,只需写数据库,然后让这套系统自动同步缓存。如此一来,便可统一缓存的写处理逻辑。
方案实施如何在缓存未命中情况下回写缓存
在业务代码中,如果从缓存中未读到数据,但是在数据中读到数据,此时不直接去写缓存,而是交由消息队列去处理(保证时序性)。考虑如下场景,业务代码1数据库写入一条新的记录,系统开始自动去同步缓存(同步有延迟,未完成同步)
业务代码2此时读缓存,因缓存未同步完成,又去数据库读,读到该条记录
业务代码3直接去数据库更新该条记录(同步有延迟,未完成同步)
步骤1和步骤3相继同步缓存完成
业务代码2写缓存成功
该场景下,业务代码2的缓存覆盖了业务代码3的缓存,这时候缓存数据和数据库数据是不一致的。因此,我们将同一个消息队列的消息分为两类,又B