面试题答案
一键面试- 消息可靠投递
- 生产者端:
- 本地消息表:在下单服务本地数据库创建消息表。下单操作执行成功后,向本地消息表插入一条待发送消息记录,状态设为“待发送”。同时开启一个定时任务,定期扫描本地消息表中“待发送”状态的消息并尝试发送到消息队列。发送成功后更新消息表状态为“已发送”。若发送失败,根据重试策略进行重试,重试一定次数仍失败则记录详细错误信息并通知运维人员。
- 事务消息(若消息队列支持):以RocketMQ为例,生产者发送半消息(Half Message),此时消息对消费者不可见。下单服务执行本地事务,根据事务执行结果向RocketMQ发送Commit或Rollback指令。若Commit,消息变为可投递状态被消费者消费;若Rollback,消息被丢弃。
- 消息队列端:选择具有高可靠性的消息队列,如Kafka的ISR(In - Sync Replicas)机制,确保消息被多个副本保存,防止数据丢失。同时,消息队列应支持持久化,将消息写入磁盘,保证即使服务器重启,消息也不会丢失。
- 消费者端:消费者从消息队列拉取消息后,先将消息保存到本地的消费日志表中,记录消息状态为“待处理”。处理业务逻辑(如支付、库存扣减),处理成功后更新消费日志表中消息状态为“已处理”。若处理过程中出现异常,根据异常类型进行重试。如果重试多次仍失败,将消息放入死信队列(Dead - Letter Queue),并通知相关人员进行人工处理。
- 生产者端:
- 幂等性处理
- 订单服务:在订单表中添加唯一索引,例如根据订单号创建唯一索引。当收到下单消息时,先尝试插入订单记录,如果因为唯一索引冲突插入失败,说明该订单已经处理过,直接返回成功。
- 支付服务:支付系统可以根据支付订单号维护一个支付状态表。当收到支付消息时,先查询支付状态表,如果该支付订单号对应的支付状态已经是“支付成功”,则直接返回支付成功,不再重复处理支付逻辑。
- 库存扣减服务:库存表记录每次库存扣减操作的流水,流水记录中包含操作的唯一标识(如订单号)。当收到库存扣减消息时,根据唯一标识查询库存流水表,如果该标识对应的扣减操作已经存在,说明库存已经扣减过,不再重复执行扣减操作。
- 最终一致性流程设计
- 下单流程:用户下单,下单服务执行本地数据库操作创建订单记录成功后,向本地消息表插入下单消息记录。通过上述可靠投递机制将下单消息发送到消息队列。
- 支付流程:支付服务从消息队列拉取下单消息,根据幂等性处理逻辑判断是否需要处理支付。若需要,执行支付逻辑,支付成功后向消息队列发送支付成功消息(同样要保证该消息的可靠投递)。
- 库存扣减流程:库存服务从消息队列拉取支付成功消息,根据幂等性处理逻辑判断是否需要扣减库存。若需要,执行库存扣减操作,完成库存扣减后可以向消息队列发送库存扣减完成消息,用于后续可能的业务流程监控或通知。整个过程通过消息的可靠投递和幂等性处理,最终保证下单、支付、库存扣减等操作的一致性。