面试题答案
一键面试利用缓存机制优化分布式事务的方法
- 库存扣减
- 先操作缓存:在处理库存扣减请求时,首先尝试从缓存(如Redis)中扣减库存。例如,使用Redis的原子操作(如
decr
命令)来减少库存数量。这样可以避免每次都访问数据库,提高系统响应速度。 - 异步更新数据库:在缓存扣减成功后,将库存扣减操作异步发送到消息队列(如Kafka)。由专门的消费者从消息队列中获取库存扣减消息,然后更新数据库中的库存数据。
- 先操作缓存:在处理库存扣减请求时,首先尝试从缓存(如Redis)中扣减库存。例如,使用Redis的原子操作(如
- 订单创建
- 缓存订单信息:在创建订单时,先将订单信息缓存到Redis中,使用订单号作为键,订单详细信息作为值存储。这可以快速响应客户端请求,告知用户订单已成功提交。
- 数据库持久化:同时,将订单创建操作异步发送到消息队列。消费者从队列中取出订单信息,将其持久化到数据库中。
缓存与数据库之间的交互处理
- 缓存更新策略
- 写后更新缓存:在数据库更新成功后,再更新缓存。以库存扣减为例,当数据库中的库存更新成功后,通过消息队列通知相关服务更新缓存中的库存数据。
- 失效缓存:对于订单创建,数据库插入订单成功后,直接删除缓存中对应的订单信息(如果缓存用于临时存储待确认订单等场景)。这样在后续查询订单时,会从数据库中获取最新数据并重新构建缓存。
- 缓存一致性保证
- 重试机制:如果在数据库更新或缓存更新过程中出现失败,通过消息队列的重试机制,多次尝试操作。例如,对于库存扣减,如果数据库更新失败,消息队列的消费者可以在一定时间间隔后重试更新数据库操作。
- 最终一致性方案:利用分布式事务框架(如Seata)来保证最终一致性。在库存扣减和订单创建的分布式事务中,Seata可以协调各个微服务的操作,确保要么所有操作都成功,要么都回滚。同时结合缓存的异步更新,在一定时间内达到缓存与数据库的一致性。
可能遇到的问题及解决方案
- 缓存雪崩
- 问题:缓存中的大量数据同时过期,导致大量请求直接访问数据库,可能使数据库压力过大甚至崩溃。
- 解决方案:设置缓存过期时间时,采用随机过期时间,避免所有数据同时过期。例如,库存缓存的过期时间在一定范围内(如1 - 3小时)随机设置。
- 缓存穿透
- 问题:查询不存在的数据时,每次都绕过缓存直接查询数据库,可能导致数据库压力过大。
- 解决方案:使用布隆过滤器(Bloom Filter)。在缓存之前添加布隆过滤器,当查询数据时,先通过布隆过滤器判断数据是否存在。如果不存在,直接返回,不再查询数据库;如果存在,再查询缓存和数据库。
- 缓存击穿
- 问题:热点数据的缓存过期瞬间,大量请求同时访问数据库,造成数据库压力骤增。
- 解决方案:使用互斥锁(如Redis的
SETNX
命令实现)。当缓存过期时,只有一个请求能获取到锁,去查询数据库并更新缓存,其他请求等待。获取锁的请求更新完缓存后,释放锁,其他请求可以从缓存中获取数据。