最近给接口增加缓存,又思考了一下缓存与db一致的问题。网上很多方案,比较主流的讨论就以下两种:
- 先更新数据库,再删除缓存。
- 先删除缓存,增更新数据库。
大部分的博客也都是推荐使用第一种方案,但是第一种方案也存在一点问题:
时间点 | 线程一 | 线程二 |
---|---|---|
刚好失效 | 读取缓存未读到,读数据库 | |
更新数据库 | ||
删除缓存 | ||
更新缓存 |
这种发生的概率还是比较小的,因为对于缓存的读写操作肯定是比数据库慢的。所以很小的几率才会发生线程二更新缓存在线程一删除缓存后面。但很多人也给出了很多种解法,例如给一个时间再删除一次缓存,或者采取队列再删除等等。这里我有另一种看法,在线程一更新数据库执行,对该缓存数据延长过期时间,expire key 60,具体的时间根据业务场景设置,设置大一些也无所谓,因为更新完就会删除掉,如果返回1则说明该缓存数据设置过期时间成功,返回为0则说明设置过期时间失败,直接更新缓存即可,然后再更新数据库。
总结:
- 先设置过期时间
- 返回值为1,更新数据库,删除缓存。
- 返回值为0,更新缓存,更新数据库,删除缓存。
这样可以减少上述问题发生的几率,但也无法保证完全不发生,例如线程二读完数据库再更新缓存时一直gap几秒钟还是会发生上述问题。如果真的需要强一致,除了其他博客那些复杂的方式,也可以采用多一些计算量,每次缓存时都添加版本号,更新缓存时去查看上次缓存的版本号的方式。