数据库与Redis数据一致问题(面试必问)

数据库与Redis数据一致问题(面试必问)
最新回答
晚街

2021-06-30 06:53:39

数据库与Redis数据一致性问题主要指在以MySQL作为存储、Redis作为缓存的架构中,如何保证两者数据最终一致,常见解决方案有四种,各有优缺点,适用不同场景。具体如下:

  • 为什么需要缓存:MySQL等数据库虽支持完整ACID特性,可靠性、持久性高,但性能普遍不高。高并发查询会给其带来压力,造成系统不稳定且易产生延迟。根据局部性原理,80%请求会落到20%热点数据上,在读多写少场景下,增加一层缓存有助于提升系统吞吐量和健壮性。
  • 存在的问题:存储的数据会随时间变化,导致缓存与数据库数据不一致。不同业务对不一致时间的容忍度不同,但通常业务都需要做到最终一致。
  • 解决方案及分析

    方案一:通过key的过期时间,MySQL更新时Redis不更新

    优点:开发成本低,易于实现;管理成本低,出问题概率小。

    不足:完全依赖过期时间,时间太短易使缓存频繁失效,太长则易有长时间更新延迟(不一致)。若读请求频繁且过期时间长,会产生很多长期脏数据。

    方案二:在方案一基础上扩展,通过key的过期时间兜底,更新MySQL时同时更新Redis

    优点:相对方案一,更新延迟更小。

    不足:若更新MySQL成功但更新Redis失败,会退化到方案一;在高并发场景,业务server需同时连接MySQL和Redis,损耗双倍连接资源,易造成连接数过多问题。

    方案三:针对方案二的同步写Redis进行优化,增加消息队列,将Redis更新操作交给Kafka,由消息队列保证可靠性,再搭建消费服务异步更新Redis

    优点:消息队列可用一个句柄,很多消息队列客户端支持本地缓存发送,有效解决方案二连接数过多问题;实现逻辑上解耦;消息队列本身具有可靠性,通过手动提交等手段可至少一次消费到Redis。

    不足:依旧解决不了时序性问题,如多台业务服务器分别处理同一行数据的两条请求,若MySQL中第一条先执行,而进入Kafka的顺序是第二条先执行,数据会产生不一致;引入消息队列需增加服务消费消息,成本较高,还有重复消费风险。

    方案四:通过订阅binlog来更新Redis,把搭建的消费服务作为MySQL的一个slave,订阅binlog,解析出更新内容再更新到Redis

    优点:在MySQL压力不大的情况下,延迟较低;和业务完全解耦;解决了时序性问题。

    不足:要单独搭建一个同步服务,并且引入binlog同步机制,成本较大。

  • 方案选型建议

    首先确认产品对延迟性的要求,若要求极高且数据可能变化,不建议用缓存。

    通常场景下,方案一足够,因其没有开发成本,在读多写少且业务对延迟有一定包容性的场景中比较实用。

    若想增加更新时的即时性,可选择方案二,但没必要做重试保证等。

    方案三和方案四适用于对延时要求比较高的业务,方案三是推模式,方案四是拉模式,方案四可靠性更强,若愿意花功夫处理消息逻辑,可一步到位选择方案四。

  • 结论:一般情况,方案一够用;若延时要求高,直接选择方案四。在面试场景中,可从简单到复杂讲解,根据面试官追问逐步推导。