缓存和数据库,1+1如何大于2?

一、缓存的本质

缓存,简单说就是为了节约对原始资源重复获取的开销,而将结果数据副本存放起来以供获取的方式。

首先,缓存往往针对的是"资源"。我们前面已经多次提到过,当某一个操作是"幂等"的和"安全"的,那么这样的操作就可以被抽象为对"资源"的获取操作,那么它才可以考虑被缓存。有些操作不幂等、不安全,比如银行转账,改变了目标对象的状态,自然就难以被缓存。

其次,缓存数据必须是"重复"获取的。缓存能生效的本质是空间换时间。也就是说,将曾经出现过的数据以占据缓存空间的方式存放下来,在下一次的访问时直接返回,从而节约了通过原始流程访问数据的时间。有时候,某些资源的获取行为本身是幂等的和安全的,但实际应用上却不会"重复"获取,那么这样的资源是无法被设计成真正的缓存的。我们把一批数据获取中,通过缓存获得数据的次数,除以总的次数,得到的结果,叫做缓存的命中率。

再次,缓存是为了解决"开销"的问题。这个开销,可不只有时间的开销。虽然我们在很多情况下讲的开销,确实都是在时间维度上的,但它还可以是CPU、网络、I/O等一切资源。例如我们有时在Web服务中增加一层缓存,是为了避免了对原始资源获取的时候,对数据库资源调用的开销。

二、缓存应用模式

2.1 旁路缓存模式

2.1.1 数据读写策略

读数据时:

  • 先读缓存,若缓存有数据,直接返回
  • 若缓存没有,读数据库。若数据库有,将结果写入缓存,并返回结果
  • 若数据库没有,就返回没有

写数据时:

  • 先写数据库
  • 再令对应的缓存失效

2.1.2 操作关键

  • 写数据时,必须先更新数据库,再令缓存失效

这个很容易理解,如果先令缓存失效了,而数据库还没来得及更新成功,那么假如这个时候有一个请求访问,他会直接击穿到数据库中,带着数据库的陈旧值去更新缓存,就会导致旧数据长期存在于缓存中,导致严重的数据不一致问题。

  • 写数据时,更新完数据库之后,必须是让缓存失效,而不是更新缓存

为什么呢?如果此时更新的策略是更新缓存而不是令缓存失效,此时几乎同时发出的请求分别更新数据库中的值为A和B,结果是A的更新早于B,那么并不能保证这两个请求更新缓存时,顺序就是A早于B,就会导致缓存中的数据可能会长期是A值。

2.1.3 数据异常情形

读操作:

  • 缓存读取异常,直接返回失败,没有数据不一致的情况
  • 数据库读取异常,直接返回失败,没有数据不一致的情况
  • 数据库读取成功,但是缓存写入失败,那么下一次读取同一数据的请求还会继续尝试写入,没有数据不一致的情况发生

写操作:

  • 数据库写入失败,直接返回失败,没有数据不一致的情况
  • 数据库写入成功,但是缓存失效的操作失败,这个问题发生了之后会非常麻烦,需要特殊处理来纠正(比如缓存数据和数据库不一致时配置告警、定期将数据库数据刷缓存)

2.2 缓存代理模式

将缓存系统作为数据库的代理,应用的请求访问只能到缓存,数据库系统对应用来说是透明的。

2.2.1 数据读写策略

读操作:

  • 先读缓存,如果缓存中有数据,返回
  • 如果缓存中没有数据,缓存查询数据库,并将结果写入自己,再返回给应用

写操作:

  • 先写缓存
  • 缓存再更新数据库
  • 通知应用写入成功
    • 这里更新数据库有两种策略
    • 透写(write-through):同步更新数据库完成之后再返回成功
    • 回写(write-back):更新缓存之后就直接返回成功,异步更新数据库(支持批量更新,更新效率高,速率稳定;但是存在数据丢失风险)

2.2.2 操作关键点

  • 缓存系统需要自己内部保证并发场景下,缓存更新的顺序和数据库更新的顺序一致,这个可以用乐观锁来保证

2.2.3 数据异常情形

读操作:

  • 同旁路缓存模式,没有数据不一致情况

写操作:

  • 如果缓存更新失败,直接返回失败,没有数据不一致情况
  • 如果缓存更新成功,数据库更新失败,需要回滚
相关推荐
阿昌喜欢吃黄桃16 小时前
RocketMq事务消息原理
java·中间件·消息队列·rocketmq·mq
半夜修仙2 天前
延迟队列的介绍及常见问题
java·数据库·中间件·rabbitmq
手握风云-2 天前
一条消息的旅程:RabbitMQ 学习与实践(一)
中间件·rabbitmq
RH2312112 天前
2026.6.8Linux
java·数据库·中间件
理人综艺好会3 天前
双Token机制在实际项目中的应用与实践
中间件·token
番茄去哪了4 天前
神领物流面试题(一)
java·大数据·中间件
念何架构之路4 天前
消息中间件
中间件
都说名字长不会被发现4 天前
Spring Boot Starter 中间件账号密码加密方案设计与实现
java·spring boot·后端·中间件
瀚高PG实验室4 天前
java中间件无法连接数据库
java·数据库·中间件·瀚高数据库
之歆5 天前
Day11_Express 深入解析:从中间件到项目实战
中间件·express