要解决的问题
如何选择合理的缓存更新模式。
由于缓存系统和数据存储系统是俩个独立的系统,所以无法原子性的对俩个系统进行操作,势必会有先后顺序,在并发场景下会造成缓存和原始数据不一致的情况,所以在性能和一致性上的取舍会有不同的更新策略。
解决方案
对缓存性能和一致性的权衡考虑,总结出一些缓存的更新"套路"用于不同场景下的复用。
解决方案案例
Cache Aside
使用非常广泛的策略,该策略下需要维护俩套存储系统:缓存和数据源。
查询:从缓存中取数据,如果没得到,则从数据源取,成功后放到缓存中。
更新的套路比较多:
策略 | 缺点 |
---|---|
先更新数据源,然后更新缓存 | 可能存在写操作结束的时间不一致导致先执行的写操作后写缓存,最终缓存值为第一次写操作的旧数据。 |
先更新数据源,然后删除缓存 | 可能在没有命中缓存的场景下,一个"读数据写缓存”的读操作中包含了另外一个并发过来的写操作,最终缓存值为第一次读操作的旧数据。 |
先删除缓存,然后更新数据源 | 可能在删完缓存写数据的过程中并发过来一个读操作,最终缓存值为第二次读操作的旧数据。 |
三种策略最终都是想保证性能的前提下同时尽可能的保证缓存数据一致性,整体上来看策略 2 是比较好的一种方案,因为它的出现脏数据的概率较低:未命中缓存的同时读操作过程中包含一次完整的写操作。
如果数据源或者缓存操作失败的时候:数据源更新成功,写/删除缓存失败,策略 3 使用一次 cache miss 来保证数据一致性,策略 1 和 2 则无法保证。
ReadRead/Write Through
这类策略就不再需要维护俩套存储系统了,只有一个缓存。
Read Through
直接查缓存,如果缓存没有,则由缓存服务去加载数据,对应用方的使用来说是透明的。
Write Through
同样直接更新缓存,由缓存系统去同步更新数据源。
Write Back
Write Back 也称为 Write Behind Caching, Linux 文件系统的 page cache 算法就是它。
该策略是针对写操作来的,它也是直接更新缓存,但是缓存系统是异步批量的去更新数据源,批量更新可以将一些操作进行合并有助于提高性能,但这种 lazy write 可能会带来数据丢失问题。