面试题答案
一键面试确保MySQL与Redis缓存数据一致的方法
- 读写顺序控制:
- 先写MySQL,再删Redis缓存:在数据发生变化时,先更新MySQL数据库,成功后再删除对应的Redis缓存。这样下次读取数据时,会从MySQL中获取最新数据并重新写入Redis缓存。例如,用户修改了个人信息,应用程序先将新信息写入MySQL,然后删除Redis中该用户信息的缓存。
- 先更新Redis,再更新MySQL:先在Redis中更新数据,同时标记为“脏数据”,后台异步任务将数据持久化到MySQL。这种方式能保证读取时获取最新数据,但需要处理好异步任务可能出现的失败情况。比如在电商系统中,商品库存的快速更新场景可以采用这种方式。
- 使用消息队列:在更新MySQL数据后,发送一条消息到消息队列(如Kafka、RabbitMQ),消息消费者接收到消息后删除Redis缓存。这样可以避免直接在业务代码中耦合删除缓存的操作,并且消息队列可以保证消息的可靠投递。例如,订单状态发生变化,系统向消息队列发送订单状态更新消息,消费者监听该消息并删除Redis中与该订单相关的缓存。
可能出现数据不一致的情况及应对方案
- 并发读写导致的不一致:
- 情况:在高并发场景下,可能会出现A线程先读取数据到Redis缓存,然后B线程更新了MySQL数据但还未删除Redis缓存,此时C线程又从Redis缓存读取到旧数据。
- 应对方案:可以使用分布式锁(如Redis分布式锁),在更新MySQL数据前获取锁,确保同一时间只有一个线程能更新数据并删除缓存。例如,在秒杀活动中,对库存数据的更新和缓存处理就可以通过分布式锁来保证一致性。
- 缓存删除失败导致的不一致:
- 情况:更新MySQL数据成功后,删除Redis缓存操作因为网络等原因失败,导致Redis中仍然是旧数据。
- 应对方案:采用重试机制,当删除缓存失败时,应用程序进行多次重试。若多次重试仍失败,可以记录日志并通过人工介入或监控系统来处理。例如,可以使用Spring Retry框架实现重试逻辑。
- 异步更新数据导致的不一致:
- 情况:采用先更新Redis,异步更新MySQL的策略时,如果异步任务失败,会导致MySQL与Redis数据不一致。
- 应对方案:增加异步任务的重试机制和监控,若任务失败,记录失败信息并进行多次重试。同时,监控系统可以定期检查异步任务的执行情况,发现问题及时通知运维人员处理。例如,使用Elastic Job等分布式任务调度框架,对异步更新MySQL的任务进行管理和监控。