关于内存缓存与缓存数据(最终)一致性
厘清问题
内存缓存主要探讨的是CPU缓存一致性,业务场景下Redis做缓存
CPU缓存一致性问题:
为了节省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内存写满了,需要触发内存淘汰的情形
综上所述:
在业务场景下,没有借鉴写回策略的思想,更主要是:
- 数据始终是要持久化的,先写缓存不能保证数据的可靠性。即使缓存可以做持久化,但这增加了心智成本
- 业务场景下更多的是做读缓存优化,和内存缓存有部分吻合(内存缓存中,写操作也是用缓存加速了),至于为什么不做写操作的优化,感觉也无需到缓存层去操作,徒增心智成本不说,MySQL这类存储本身对于写操作也是有Buffer Pool来优化的