众所周知的玩笑,计算机科学中只有两个难题:缓存失效和命名。
缓存失效,我理解为是如何保证缓存一致性。
首先说明,所有的方案都是存在问题的,都不能保证100%的一致性,如果严格要求一致性,那么,把缓存干掉吧....
那么到底要不要用缓存?用缓存的目的是什么?你的业务能接受什么样的数据一致性?使用之前至少需要把这些问题搞清楚。
如果没搞清楚需求,就上缓存,只能说明上缓存只是为了PPT好看并且能多卖一些RMB而已吧。
我个人的理解是,一个技术不应该为了用而用,而是服务于业务的。
假如重新设计一个系统,如果不是已经有个很成熟的系统做样板,我会先全部用DB,然后哪里有问题再改进哪里,不会一上来就决定用某一个中间件。
只用数据库的好处在于实现事务很简单,能保证操作的原子性,并且技术很完善。
如果用了缓存,数据不一致的情况会非常多,事务处理的复杂程度远超我们的想象。只能根据自己的业务,选择一种业务上可以容忍的一致性的方案。
其实往往简单的模型才最可靠,如果没有必要,尽量不用缓存,免得出现各种问题,浪费了时间还得不到想要的效果。
同步缓存的策略分好多好多种,什么实时缓存、异步缓存、定时缓存、消息队列缓存,真要是详细说起来,估计能说一本书,主要是我也不会...
这里就说几种简单、好实现、数据一致性也还算说的过去的方式吧。
一、不主动删除redis,等它自己过期。
一致性 ★☆☆☆☆ 实时性 ★★★★★
更新数据库以后,不管redis,等redis中的数据自己过期。查询数据库时,顺便把新值写入redis。好处是:很简单。坏处是:在没到过期时间之前,数据都是不一致的。比较适合放一些对一致性要求不高,但查询比较多的场景。
过期时间也可以设置的短一些,比如就几秒钟,能提高一些一致性,并防止缓存穿透。
二、更新DB -> 删除redis
一致性 ★★☆☆☆ 实时性 ★★★★☆
这种方案的不一致性在于,A更新了DB,A还没有成功删除redis,B又来读redis,这时候B读走的就是旧值。在C读取DB时才会重新将新值放入redis。在配合key的过期时间的使用,数据一致性能比第一种方案好不少。
三、删除redis -> 更新DB -> 删除redis
一致性 ★★★☆☆ 实时性 ★★★☆☆
这种方案的数据不一致性在于,A先删除redis,A在没有完成更新DB时,这时候B读redis,发现没有值,再去读DB,读到了旧值,B还没有把旧值写入redis呢,A就已经完成更新DB的操作并把新值写入redis,等B完成写入redis时,值又被替换成了旧值。
四、删除redis -> 更新DB -> 等待一段时间 ->删除redis
一致性 ★★★★☆ 实时性★★☆☆☆
这种方案是对方案三的改进,A先删除redis,A更新完DB之后,等待一段时间(B读DB并写入redis的时间,这个时间需要自己估一下),然后A再删除redis。其他文章中提到过这种方法被称为“延时双删”,虽然也并不完美,但也能应付大部分的场景了。
还有很多更高级的保持数据一致性的方法,大家可以自行研究,臣妾做不到了,但好像任何方法都不能保证100%的数据一致性。
选择适合自己业务场景的就好。如果严格要求一致性,那么,把缓存干掉吧....
请轻喷.....