消息队列是怎么实现的?
1 个回答
浪漫固然重要,但真诚更胜一筹。法相消息队列(Message Queue, MQ)是一种跨应用的异步通信机制,用于在分布式系统中传递消息,实现系统之间的解耦和异步处理。消息队列的实现有多种方式,其中常见的有本地消息表和 MQ 事务消息。 #### 1. 本地消息表(异步确保) 本地消息表是一种常见的实现方式,其核心思想是将分布式事务拆分为本地事务处理。该方法来源于 eBay。具体流程如下: **基本思路**: 1. **消息生产方**: - 生产方需要额外创建一个消息表,用于记录消息发送状态。消息表和业务数据要在一个事务里提交,即它们要在同一个数据库中。 - 当业务操作执行时,消息和业务数据同时写入数据库。 - 随后,消息通过消息队列(MQ)发送到消息的消费方。如果消息发送失败,会进行重试发送。 2. **消息消费方**: - 消费方接收到消息后,处理消息并完成自己的业务逻辑。 - 如果本地事务处理成功,表明消息处理成功。如果处理失败,则重试执行。 - 如果是业务上的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。 3. **定时扫描和重试**: - 生产方和消费方需要定时扫描本地消息表,把未处理完成的消息或者失败的消息再发送一遍。 - 通过自动对账补账逻辑,确保最终一致性。 **优点**: - 经典实现,避免了分布式事务,实现了最终一致性。 - 简化了复杂的分布式事务,实现相对简单。 **缺点**: - 消息表耦合到业务系统中,增加了系统复杂度。 - 如果没有封装好的解决方案,会有很多杂活需要处理。 **示例代码**(伪代码): ```java public class MessageService { private MessageRepository messageRepository; private BusinessService businessService; public void processMessage(Message message) { // 开启本地事务 try { // 保存消息到消息表 messageRepository.save(message); // 处理业务逻辑 businessService.processBusinessLogic(message); // 发送消息到MQ sendMessageToMQ(message); // 更新消息状态为已发送 message.setStatus("SENT"); messageRepository.update(message); // 提交事务 } catch (Exception e) { // 回滚事务 } } private void sendMessageToMQ(Message message) { // 发送消息到消息队列 } } ``` #### 2. MQ 事务消息 一些第三方的 MQ 支持事务消息,例如 RocketMQ。事务消息的方式类似于二阶段提交。 **基本思路**: 1. **第一阶段(Prepared 消息)**: - 生产方发送 Prepared 消息,拿到消息的地址。 2. **第二阶段(本地事务)**: - 生产方执行本地事务。 3. **第三阶段(确认消息)**: - 生产方通过第一阶段拿到的地址去访问消息,并修改状态。 如果确认消息发送失败,RocketMQ 会定期扫描消息集群中的事务消息,并向消息发送者确认。生产方需要实现一个 `check` 接口,RocketMQ 根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样保证了消息发送与本地事务的同时成功或同时失败。 **优点**: - 实现了最终一致性,不需要依赖本地数据库事务。 **缺点**: - 实现难度大,主流 MQ(如 RabbitMQ 和 Kafka)不支持事务消息。 - 部分 MQ(如 RocketMQ)的事务消息功能未开源,且没有 .NET 客户端。 **示例代码**(伪代码): ```java public class TransactionalMessageService { private RocketMQProducer producer; public void processTransactionalMessage(Message message) { // 开启本地事务 try { // 发送 Prepared 消息 producer.sendPreparedMessage(message); // 执行本地事务 processLocalTransaction(message); // 发送确认消息 producer.sendCommitMessage(message); } catch (Exception e) { // 发送回滚消息 producer.sendRollbackMessage(message); } } private void processLocalTransaction(Message message) { // 处理本地事务逻辑 } } ```发布于 2024-08-06 19:31 •IP属地 吉林举报评论收藏
公众号进入网站体验更佳

