os学习,浮想联翩:缓存一致性

150 阅读3分钟

关于内存缓存与缓存数据(最终)一致性

厘清问题

内存缓存主要探讨的是CPU缓存一致性,业务场景下Redis做缓存

CPU缓存一致性问题:

微信图片_20230725001525.png

为了节省CPU时钟,CPU会优先读、写内存缓存。当Cache Line被标记为脏时,说明缓存和内存数据不一致,一般而言使用写回Write Back的策略保证一致性

具体来说:

当我们读取数据时,1. 若数据存在于内存缓存中,则直接读取;2. 若数据不存在于内存缓存中,则定位数据所对应的Cache Line,并且检查这个Cache Line是否为脏,若脏则说明需要保证一致性,将缓存写回主存。若不为脏,则直接加载主存,并写入内存缓存

当我们写入数据时,1. 若数据存在于内存缓存中,则直接写缓存,并标记为脏;2. 若数据不存在于内存缓存中,则定位数据所对应的Cache Line,并且检查这个Cache Line是否为脏,若脏则说明需要保证一致性,将缓存写回主存。若不为脏,则直接写内存缓存。

业务场景下,缓存和存储的一致性问题:

假设我们使用MySQL作为底层存储,使用Redis作为缓存。 一般情况下,我们用Redis作为旁路缓存,并采用先写存储,再删除缓存的策略来保证缓存一致性

业务场景下可以借鉴CPU缓存一致性的写回策略思想来保证缓存一致性吗?

今天在阅读的时候,突然想到这个问题,仔细思考后,感觉两个场景差别较大。

原先我的想法是,在业务场景下,是不是也可以通过标记位(脏页 or 干净页),来减少写存储的次数,但是为什么业界常用的方案并不如此呢?

  • 我认为,内存缓存的主要目标是为了减少读主存的CPU时钟,这一点和“减少写存储的次数”是吻合的。

    但不同之处在于,业务场景下的应用更追求可靠性,写存储是为了保证数据的持久化,而Redis这类缓存应用,更多讲究短平快(即使它也可以做到持久化)

  • 写回策略的优点更多地体现在,内存缓存是有限的,会出现需要写一个脏Cache Line的情况(区别于写直达策略,如果数据不在内存缓存中,则直接写内存)。这大概对应于业务场景的 Redis内存写满了,需要触发内存淘汰的情形

综上所述

在业务场景下,没有借鉴写回策略的思想,更主要是:

  1. 数据始终是要持久化的,先写缓存不能保证数据的可靠性。即使缓存可以做持久化,但这增加了心智成本
  2. 业务场景下更多的是做读缓存优化,和内存缓存有部分吻合(内存缓存中,写操作也是用缓存加速了),至于为什么不做写操作的优化,感觉也无需到缓存层去操作,徒增心智成本不说,MySQL这类存储本身对于写操作也是有Buffer Pool来优化的