一致性
- 缓存一致性,指的是缓存中的数据,与数据库中的数据是否一致
可以理解为数据的快照与实时数据是否相等,在实时数据变动的过程中以及数据快照同步中产生的问题,即缓存一致性问题(也可以归类于数据双写问题)
业务场景
生产中面临数据的高频读取,为了降低数据库压力,就可以考虑将数据放入缓存中,缓存又可分为本地缓存与分布式缓存
本地缓存 & 分布式缓存
- 本地缓存指的是机器上的缓存,如Guava和Ehcache,此类缓存多受限于机器内存与分布式部署同步困难等问题
- 分布式缓存指的是数据存放在服务端,使用方访问同一份数据,如Redis,MemCache,此类缓存存在丢数据,数据延时,服务宕机等问题
本地缓存一致性问题
若硬要比较本地缓存与分布式缓存的优劣,那么本地缓存最大的优势就在于不需要与云端缓存服务器交互,减少了网络和IO消耗,但是本人目前感知来看,差距其实非常小;
且本地缓存最大的难题就是如何做到不同实例之间的同步,现有的做法是使用MQ或RPC广播模式,一台实例更新数据库后通知其他实例进行刷新,但无法解决的就是通知过程中新启动的实例,以及通知失败的情况,在强一致性场景下,这样的异常是无法接受的
分布式缓存一致性问题
承接上述,分布式缓存的本质则是将数据库的数据写入到缓存服务端,当数据库发生变更,将变更同步至缓存服务端的过程中,缓存与数据库的数据是不一致的,就涉及到了缓存一致性问题,下文将继续讲解缓存一致性方案
解决方案
- 读数据
面临强一致性场景时,可以考虑将数据放入缓存(过期或永不过期都可),服务端只能从缓存读取数据,当发现缓存中没有数据时,服务端加锁读取数据库,此时只有一个请求可以访问数据库,查询结束后将结果写入缓存,其他请求阻塞至缓存写入完成,再从缓存中读取数据
- 服务端处理查询请求,尝试从缓存中查询数据
- 缓存中存在数据,则直接返回
- 缓存中不存在数据,则加锁查询数据库,查库结束将数据放入缓存
- 其他请求直接读取缓存
- 写数据
写数据时可先行修改数据库,再将缓存更新或删除(删除时,直到下一次查询请求到来时,新数据才会写入缓存),此方案在数据写入到缓存更新的过程中,其他查询请求依然将访问到旧的数据,无法保证绝对的一致性
若需要强一致性方案,则可直接将缓存删除,并阻塞所有读取请求,然后加锁写数据,再将数据放入缓存中,类似于读写锁的概念,读写互斥,此方案由于强一致性约束,相上述方案性能会差一些,需要结合具体场景使用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。