面试题答案
一键面试常见导致数据一致性问题的场景
- 读写并发场景
- 读操作先于写操作完成,新写入的数据未及时更新到缓存,导致读取到旧数据。例如,用户A读取商品价格缓存,此时用户B修改了商品价格并写入数据库,但缓存还未更新,用户A再次读取时还是旧价格。
- 缓存过期场景
- 缓存数据过期后,在新数据未及时加载到缓存期间,可能读取到旧数据或空数据。比如,一个热门文章的缓存过期,在重新从数据库加载数据到缓存的短暂间隔内,用户访问文章看到的是旧版本或无内容。
- 缓存更新失败场景
- 当数据库更新成功,但缓存更新由于网络故障、服务异常等原因失败,导致缓存与数据库数据不一致。例如,订单状态在数据库中已更新为“已完成”,但向缓存更新订单状态时网络中断,缓存中订单状态仍为“进行中”。
缓存更新策略及解决方法
- Cache - Aside Pattern(旁路缓存模式)
- 读操作:先从缓存读取数据,若缓存命中则直接返回;若缓存未命中,从数据库读取数据,将数据写入缓存,并返回数据。
- 写操作:先更新数据库,成功后删除缓存(而不是更新缓存,因为更新缓存可能导致数据不一致,删除缓存则在下一次读取时重新加载最新数据)。例如,更新用户信息,先在数据库中修改,成功后删除用户信息对应的缓存。这样下一次读取用户信息缓存时未命中,会从数据库加载最新数据并更新到缓存。
- Read - Through Pattern(读穿透模式)
- 读操作:读请求先到缓存,若缓存未命中,由缓存服务(如代理)负责从数据库读取数据并更新到缓存,然后返回数据给应用。例如,使用Redis作为缓存,应用向Redis读取数据,Redis未命中时,Redis连接数据库获取数据并写入自身缓存,再返回给应用。
- 写操作:与Cache - Aside Pattern类似,先更新数据库,成功后删除缓存。
- Write - Through Pattern(写穿透模式)
- 写操作:写请求同时更新数据库和缓存,保证两者数据一致。但此模式对性能有一定影响,因为每次写操作都要操作数据库和缓存。例如,更新产品库存,同时更新数据库和缓存中的库存数量。这种模式要求缓存和数据库更新操作的原子性或使用事务机制来确保一致性,否则可能出现部分更新成功部分失败的情况。
- Write - Behind Caching Pattern(写回缓存模式)
- 写操作:先更新缓存,标记缓存为脏数据,然后由专门的异步线程或队列在合适时机将缓存数据批量更新到数据库。这种模式适用于对写入性能要求高,对数据一致性要求相对不那么严格的场景。例如,在一些日志记录场景中,先快速将日志写入缓存,缓存标记为脏数据,后台线程定时将缓存中的日志批量写入数据库。但这种模式可能会因为缓存故障等原因导致部分数据丢失,所以需要考虑数据持久化和恢复机制。