一般情况下,缓存是很多领域的概念,在本文中,我们仅讨论常规数据库应用中缓存与数据库的关系。
一般情况下的查询
套路:读: 读缓存 ,成功则返回数据 ,缓存MISS 则读数据库,设置缓存。
写: 写数据库,成功则更新缓存。
应用场景:数据量有限,更新不频繁
允许一段时间内的数据不一致
采用短时间过期缓存,降低数据库访问频次,自动淘汰数据
可能出现的常规问题:如果使用的是外部缓存,则会遇到更新缓存失败的情况,导致用户修改数据后,在过期前一直读取到旧数据(一般可以接受),但用户有可能会看到数据的抖动。
如果使用的内存或本地文件的缓存,则会遇到集群节点间数据差异导致访问出现数据的抖动,同时有可能会遇到内存占用过大的情况。
解决方法(指的是尽可能防止数据抖动并尽可能保证数据修改能被访问缓存时观测到):使用二级缓存,结合会话粘性技术保证同一用户看到的数据不发生抖动。
内存或本地文件缓存,修改时触发全局事件,通知到每个节点淘汰相应缓存数据。
以上两个方法均有失败的可能性,所以这种方法必须结合有限的过期时间才能保证数据的最终一致性,防止灾难的发生。
应对不定时突然的大流量
比如容易出现不定期的热点情况,同时数据量比较大,用户访问频繁,多是用户自己的数据,如果依赖较短时间过期的缓存,缓存命中率低,此时数据库IOPS可能无法应对。
读频繁:
套路(来自58技术文章的分享):结合RPC的负载均衡技术按数据ID进行哈希分片,使同一数据在一段时间内位于一个节点上处理,而后让该数据的写与数据库读互斥。
读: 读缓存 ,成功则返回数据 ,缓存MISS 则读数据库,设置缓存。
写: 淘汰缓存数据,写数据库,成功则更新缓存。
问题:依赖具体的技术细节。
改动频繁:
套路: 写缓存,通过其他手段(如队列)入库,削峰填谷
问题:缓存重启有可能丢数据(使用Redis会好一些),队列服务崩溃或者异常时,可能要设计好同步缓存数据的服务。
可预期范围内短时间内高速大量访问的需求
如每天定时推送给终端客户信息,有可能需要在极短时间内的高QPS数据的查询。
套路:如在N时间需要高QPS数据的查询
计算数据库效率,提前在M时间预热数据到缓存,如10点推送,8点开始预热数据到缓存
从M时间到N时间内对数据的修改触发事件更新缓存内容。
对于写程序这件事儿来说没有万能套路,只有根据具体业务的分析和各种妥协。