关于redis和mysql数据一致性的思考

前言

工作中发现偶尔会有redis和mysql的数据不一致的情况,其实我工作中还没有遇到,只是之前看另外一个同事说过这个问题,我就看了我们这边对redis数据一致性的处理,发现处理方式只是简单粗暴的缓存中有就取来用,没有就查mysql返回,再异步更新缓存,这种解法在高并发的情况下必然出现数据不一致的问题,至于原因,细细品。但因为我们的并发很低,所以也就没有出过问题。 自己看了说这个问题的同事提出的解决方案以及本文下面提到的参考博客,篇幅有些长,给我的感觉是太复杂了,对我这种学识浅薄的人不太好理解,于是我就结合自己的理解,总结一下,至于细节方面等以后有时间再来实践一下。当然说的不对的,尽管放马过来~

一、删除缓存还是更新缓存

使用redis的原因众所周知,减少数据库的压力,提高系统性能,但数据仅存redis是无法满足越来越复杂的业务,需要使用mysql一起进行保存,在对数据进行访问时,先访问redis,redis中没有再访问mysql。这个时候需要考虑redis和mysql中数据的一致性。 所谓一致性,我粗鄙的理解为在几乎同一时间,客户访问到的缓存中的数据和mysql中的数据是一样的,但redis和mysql里的数据的处理总要有个先后顺序,所以数据一致性就要考虑是先处理redis还是先处理数据库,redis中的数据是删除还是更新。

结论:删除缓存而不是更新缓存 由于更新redis比删除redis要慢很多,所以要选择删除缓存。 (当然除了时间问题还有并发问题,我这里不做赘述,感兴趣的可以看)

二、先更新数据库还是先删除缓存

那redis和数据库的处理谁先谁后,是先更新数据库还是先删除缓存?

2.1 先删除缓存,再更新数据库

如果先删除缓存,再更新数据库,缓存已经删除了,但是数据库还没更新完,结果有别的线程来访问redis,缓存数据是空的,而数据库还没更新完,就会导致请求的线程拿不到最新的数据,只能从数据库中取旧的数据同步到redis中,而数据库的更新时间远比删除redis的时间更久,就会导致在脏数据的时间更久;

2.2先更新数据库,再删除缓存

采用先更新数据库,在删除缓存。等数据库更新完成之后,再删除缓存,导致的脏数据的时间更短,假如有A线程正在对数据做更新,这个时候缓存数据还是有的,等A线程更新完mysql之后,并删除了缓存,这个时候B线程抢占cpu来访问,发现redis中没有数据了,就会从mysql中同步数据到redis中,所以删除缓存的时间很短就会使得产生脏数据的时间很短。 结论:先更新数据库,再删除缓存 所以我们选择先更新数据库在更新缓存,虽然这依然会导致数据不一致。 (当然除了时间问题还是有并发问题,我这里不做赘述,感兴趣的可以看)

三、数据库更新完成,redis服务宕机该当如何

有了前面的操作后,又如何保证更新完数据库,redis缓存数据一定能够删除呢? 万一mysql更新完之后,redis服务宕机了怎么办,不就还是不一致吗? 重试?那重试多少次可以,间隔多久进行重试?这些都不好界定,那么我们如何可以保证redis缓存数据一定会被删除呢?这个时候消息队列可以粉墨登场了,通过MQ进行解耦,将要删除的这些key放到消息队列中,由消费者进行消费,只有消费了,这个删除缓存的任务的这条消息才不存在了,即便redis当机了,但消息队列服务器还屹立不倒的话,只要没有消费,那么删除的消息就还在,当redis服务恢复了,再开始进行消费,这样就能保证删除操作一定被执行,你可能会说万一MQ的服务器也翘翘了怎么办?我觉得办法总比问题多,总能找到解决的办法。自行脑补~~ 结论:使用消息队列 (也可以再看)

四、天上飞的理念需要地上跑的实践

------------你知道的越多,不知道的越多--------------

经验分享 程序员 微信小程序 职场和发展