1. 业界读写Redis cache 的方式
- Cache aside:由应用层保证cache和数据库的数据一致性。
- Read through: 当缓存失效的时候(过期或LRU换出),由cache服务去读取数据库,对应用方是透明的。
- Write through:当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache同步更新数据库
- Write behind caching:类似Linux的Page Cache方式,这种方式是更新时,只更新cache,然后缓存异步写数据库。 这种方式性能好,但一致性差,有可能丢失数据。
2. Cache Aside操作流程
2.1 读请求操作
- 先查cache,命中cache就从cache中读。
-
cache没命中的话就去读数据库,并回写到cache中
图片
2.2 写请求操作
在写请求操作上,有以下四种实现方式,不过它们都存在着一些不一致的问题。
-
先写cache后写数据库
这种方式,显而易见,当更新cache后,写数据库失败时,就会导致cache数据和数据库不一致。
-
先写数据库后写cache
两个并发写操作,可能导致脏数据。一个线程先写数据库,而比另外一个线程较慢写到cache,另一个线程后写数据库的进程先写到cache中,这种方式,导致cache数据落后数据库一个版本。
-
先失效cache后写数据库
当有一个读操作和一个写操作并发时,可能导致redis存旧数据。写操作先失效cache后,并发读操作发现redis没有存储该数据,即从数据库中读取数据,这时可能拿到旧数据,并把旧数据存储到redis中。这时更新操作才写最新的数据到数据库中,这时会导致redis的数据落后于数据库。
-
先写数据库后失效cache
这种方式也会有不一致性的问题,不过概率比较小。
- 第一种情况:一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,这时会造成脏数据。
但这个case理论上会出现,实际上出现的概率可能非常低,因为这个条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢一些,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大。 - 第二种情况:当写数据库后,失效cache时,失效操作失败,这会导致cache数据是旧数据。
这种在读写cache操作时失败的情况无法避免(网络原因等,BDRP SLA 99.99%),所以会有0.01%的概率存在Cache和数据库的不一致的问题。为了避免这种极端条件下造成的缓存与数据库之间的数据不一致,缓存需要设置一个失效时间。时间到了,缓存自动被清理,达到缓存和数据库数据的“最终一致性”。
- 第一种情况:一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,这时会造成脏数据。
综上四种方式的讨论,在写cache时,需要使用第四种方式,“先写数据库后失效cache的方式”。 这种方式对刚更新的数据,有一次cache miss。
图片
网友评论