如果要修改一个Redis和mysql共存的数据,在Redis中我们到底是修改数据,还是删除原有数据再添加新的数据呢?还有我们到底是先操作Redis缓存还是先操作数据库呢?这些都是和数据的一致性来挂钩的。
因为更新缓存的成本很高,所以我们在Redis中选择先删除、后添加的方式。
正常的过程就是当数据修改时,先删除Redis中的缓存数据,之后再更新mysql数据库,然后后面的线程如果要查询数据,在Redis中查询不到,就会去mysql中查询并放入缓存中。但是如果网络延迟数据库没有及时更新,这样可能会导致后面的线程始终访问的都是脏数据,如下情况:

网络延迟问题的解决方式就是使用延迟双删,就是当数据库数据进行更新之后,如果Redis缓存了旧数据,再对Redis中的数据进行一次延迟删除,延迟的目的就是防止这次延迟删除刚好进行在其他线程将旧数据放到缓存的前面,这样我们就保证了最终一致性。
强一致型的实现需要加锁,但是这样会大大降低吞吐量,所以不采取。
正常的情况是当数据发生修改时,我们先修改mysql数据库,修改完数据库后再删除Redis中的缓存。但是如果在删除Redis缓存前,其他的线程来访问时,都是访问Redis中的脏数据,等到删除Redis中的脏数据时,才会到数据库中查询最新的数据,这样在正常的情况下会保证最终一致性。但是如果极端的情况下,如果删除缓存时出错(延迟双删可能存在此问题),就会出现问题:

解决方法就是利用删除重试机制,要使用消息队列,客户端(项目程序)监听mq,如果Redis那边删除失败,发送异步消息到MQ,然后客户端那边监听到MQ中的消息,重试删除即可,但是采用这种方式会导致业务代码的耦合度比较高。
优化的策略是使用Cannal监听mysql中binlog日志的变化,Cannal相当于把自己伪装为mysql的奴隶,向mysql发送dump协议,mysql收到协议后,会主动向cannal推送binlog日志,Canal如果发现binlog有变化,则通知客户端(项目程序)去删除Redis中的缓存,如果中途Redis删除有问题,也会发送异步信息到MQ中,客户端本来就监听这mq,可以及时读取到消息。
