## 更新策略
缓存更新的策略主要分为三种:
- **Cache Aside Pattern(旁路缓存)**
- **Read/Write Through Pattern(读写穿透)**
- **Write Behind Caching Pattern(异步写入)**
**缓存使用场景**
**分布式系统中要么通过2PC、3PC或Paxos协议保证强一致性,要么就是拼命的降低并发时脏数据的概率**。缓存系统适用的场景就是非强一致性的场景,所以它属于CAP中的AP,只能做到BASE理论中说的**最终一致性**。异构数据库本来就没办法强一致,我们只是**尽可能减少不一致的时间窗口,达到最终一致性**。同时结合设置过期时间的兜底方案。
**缓存场景分析**
- 对于读多写少的数据,请使用缓存
- 为了保持数据库和缓存的一致性,会导致系统吞吐量的下降
- 为了保持数据库和缓存的一致性,会导致业务代码逻辑复杂
- 缓存做不到绝对一致性,但可以做到最终一致性
- 对于需要保证缓存数据库数据一致的情况,请尽量考虑对一致性到底有多高要求,选定合适的方案,避免过度设计
### Cache Aside(旁路缓存)
`Cache Aside(旁路缓存)` 是最广泛使用的缓存模式之一,如果能正确使用 `Cache Aside` 的话,能极大的提升应用性能,`Cache Aside`可用来读或写操作。`Cache Aside`的提出是为了尽可能地解决缓存与数据库的数据不一致问题。
#### Read Cache Aside
`Cache Aside` 的读请求流程如下:
- **读的时候,先读缓存,缓存命中的话,直接返回数据**
- **缓存没有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应**
#### Write Cache Aside
`Cache Aside` 的写请求流程如下:
![Cache-Aside写请求](Cache-Aside写请求.jpg)
- **更新的时候,先更新数据库,然后再删除缓存**
### Read/Write Through(读写穿透)
`Read/Write Through(读写穿透)` 模式中,服务端把缓存作为主要数据存储。应用程序跟数据库缓存交互,都是通过**抽象缓存层**完成的。
#### Read Through
`Read Through` 和 `Cache Aside` 很相似,不同点在于程序不需要再去管理从哪去读数据(缓存还是数据库)。相反它会直接从缓存中读数据,该场景下是缓存去决定从哪查询数据。当我们比较两者的时候这是一个优势因为它会让程序代码变得更简洁。`Read Through`的简要流程如下
- **从缓存读取数据,读到直接返回**
- **如果读取不到的话,从数据库加载,写入缓存后,再返回响应**
该模式只在 `Cache Aside` 之上进行了一层封装,它会让程序代码变得更简洁,同时也减少数据源上的负载。流程如下:
#### Write Through
`Write Through` 模式下的所有写操作都经过缓存,每次向缓存中写数据时,缓存会把数据持久化到对应的数据库中去,且这两个操作都在一个事务中完成。因此,只有两次都写成功才是最终写成功。用写延迟保证了数据一致性。当发生写请求时,也是由**缓存抽象层**完成数据源和缓存数据的更新,流程如下:
![Write-Through](Write-Through.png)
- **向缓存中写数据,并向数据库写数据**
- **使用事务保证一致性,两者都写成功才成功**
当使用 `Write Through `的时候一般都配合使用 `Read Through`。`Write Through `适用情况有:
- **需要频繁读取相同数据**
- **不能忍受数据丢失(相对 `Write Behind` 而言)和数据不一致**
**`Write Through` 的潜在使用例子是银行系统。**
### Write Behind(异步写入)
`Write Behind(异步写入,又叫Write Back)` 和 `Read/Write Through` 相似,都是由 `Cache Provider` 来负责缓存和数据库的读写。它们又有个很大的不同:`Read/Write Through` 是同步更新缓存和数据的,`Write Behind` 则是只更新缓存,不直接更新数据库,通过**批量异步**的方式来更新数据库。
这种方式下,缓存和数据库的一致性不强,**对一致性要求高的系统要谨慎使用**。但是它适合频繁写的场景,MySQL的**InnoDB Buffer Pool 机制**就使用到这种模式。如上图,应用程序更新两个数据,Cache Provider 会立即写入缓存中,但是隔一段时间才会批量写入数据库中。优缺点如下:
- **优点**:是数据写入速度非常快,适用于频繁写的场景
- **缺点**:是缓存和数据库不是强一致性,对一致性要求高的系统慎用