面试题答案
一键面试- 两阶段提交(2PC)变体方案
- 第一阶段(准备阶段):
- 下单服务收到用户下单请求后,先向库存服务发送扣减库存的预扣减请求。库存服务在内存中预扣减库存,并记录操作日志,返回预扣减结果给下单服务。
- 下单服务向消息队列服务发送一条准备发送订单消息的请求,消息队列服务将该消息标记为待确认状态并返回确认结果给下单服务。
- 下单服务向数据库发起插入订单记录的预操作,数据库执行预插入操作(例如使用事务隔离级别,将数据暂时标记为待提交),并返回预操作结果给下单服务。
- 第二阶段(提交阶段):
- 如果第一阶段所有预操作都成功,下单服务向库存服务、消息队列服务和数据库发送正式提交请求。库存服务正式扣减库存并持久化操作,消息队列服务将待确认消息正式发送,数据库正式提交订单记录。
- 如果第一阶段任何一个预操作失败,下单服务向库存服务、消息队列服务和数据库发送回滚请求。库存服务回滚预扣减操作,消息队列服务删除待确认消息,数据库回滚预插入操作。
- 异常处理:
- 网络故障:如果在第一阶段某个服务未收到预操作请求,下单服务可设置重试机制,在一定时间间隔后重新发送请求。若重试多次仍失败,则放弃操作并进行回滚。
- 节点崩溃:对于库存服务、消息队列服务和数据库,都需要具备故障恢复机制。例如数据库在重启后,可根据日志恢复到崩溃前的事务状态,进行提交或回滚操作。
- 第一阶段(准备阶段):
- 基于可靠消息最终一致性方案
- 消息发送:
- 下单服务收到用户下单请求,先在本地数据库创建一条订单记录,并将该订单记录状态标记为“待处理”,同时记录一个与订单关联的消息记录,标记为“待发送”。
- 下单服务通过本地事务确保订单记录和消息记录的原子性写入。
- 启动一个定时任务或消息发送服务,从数据库中读取状态为“待发送”的消息记录,尝试发送到消息队列。发送成功后,更新消息记录状态为“已发送”。
- 消息消费:
- 库存服务监听消息队列,收到订单消息后,先根据订单信息检查库存是否足够。若足够,则扣减库存,并更新库存缓存。
- 库存服务消费消息成功后,向数据库发送一个确认消息已处理的请求,下单服务收到确认后,更新订单记录状态为“已完成”。
- 异常处理:
- 消息发送失败:定时任务或消息发送服务在发送消息失败时,根据失败次数进行不同处理。次数较少时,可进行重试;次数过多时,可记录异常日志并通知管理员。
- 消息消费失败:库存服务消费消息失败时,将消息重新放回消息队列(设置一定的重试策略,避免死循环),或记录消费失败日志,由人工介入处理。
- 消息发送:
- TCC(Try - Confirm - Cancel)方案
- Try阶段:
- 下单服务收到下单请求,调用库存服务的try接口,库存服务检查库存并冻结库存(类似预扣减),返回冻结结果。
- 下单服务调用消息队列服务的try接口,消息队列服务进行消息预发送准备(如分配消息ID等),返回准备结果。
- 下单服务在本地数据库进行订单记录的预插入,返回预插入结果。
- Confirm阶段:
- 如果Try阶段所有操作成功,下单服务调用库存服务的confirm接口,库存服务正式扣减库存。
- 下单服务调用消息队列服务的confirm接口,消息队列服务正式发送订单消息。
- 下单服务更新本地数据库订单记录状态为已完成。
- Cancel阶段:
- 如果Try阶段有任何操作失败,下单服务调用库存服务的cancel接口,库存服务解冻冻结的库存。
- 下单服务调用消息队列服务的cancel接口,消息队列服务取消消息预发送操作。
- 下单服务删除本地数据库的预插入订单记录。
- 异常处理:
- 网络故障:在每个阶段调用其他服务接口失败时,设置重试机制。对于Confirm和Cancel阶段,可通过幂等性设计,确保重试不会产生重复操作。
- 节点崩溃:各服务需要记录操作日志,在节点恢复后,根据日志和当前事务状态进行相应的Confirm或Cancel操作。
- Try阶段: