MQ的应用场景、使用时常见问题以及解决方案都在这啦

MQ基本介绍

MQ(Message Queue): 是一种应用程序间的通信方法。有别于程序之间直接通过远程调用进行通信,应用程序使用MQ进行通信时,通信的发起方将消息(数据)写入队列,接收方通过检 索队列中的消息(数据)来进行的。通常会使用MQ中间件进行信息的中转,而无需在程序之间建立直接的联接。用于接收、存储、分发消息的独立应用程序。常见的MQ中间件有:RabbitMQ 、RocketMQ、Kafka、Redis、ActiveMQ等。

MQ的组成

  1. Broker: 消息服务器,作为Server提供消息核心服务。
  2. Producer:消息生产者,业务的发起方,负责产生消息,并将消息传递给Broker。
  3. Consumer:消息消费者,业务的处理方,负责从Broker获取消息,并进行相关业务处理。
  4. Topic:消息的主题,发布订阅模式下,生产者产生的消息将被发送到Topic后,由Broker分发给所有订阅此Topic的消费者,实现消息的广播。
  5. Queue:消息队列,点对点模式下,生产者产生的消息将发送到Queue,消费者订阅此队列,接收相关消息。
  6. Message:消息体,根据不同消息协议格式,对消息内容进行编码封装,以在网络上进行传输。

主要的MQ协议介绍

  • JMS(Java MessageService):由Sun公司早期提出的消息标准,旨在为java应用提 供统一的消息操作。从使用角度看,JMS和JDBC担任差不多的角色,用户都是根据相 应的接口可以和实现了JMS的服务进行通信,进行相关的操作。
  • AMQP(advanced message queuing protocol):在2003年时被提出,最早用于解决金融 领域,不同平台之间的消息传递交互问题。顾名思义,AMQP是一种协议,更准确的 说是一种binary wire-level protocol(链接协议)。这是其和JMS的本质差别,AMQP不 从API层进行限定,而是直接定义网络交换的数据格式,天然是跨平台的。
  • MQTT(Message Queuing Telemetry Transport):是IBM开发的一个即时通讯协议,该 协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和 致动器。格式简洁、占用带宽小。
  • XMPP(Extensible Messaging and Presence Protocol):基于xml格式的消息协议, 多用于即时通讯及现场控测。协议扩展性好,安全性高、占用带宽大。
  • 其它基于TCP/IP的自定义协议:部分中间件,如:redis、kafka、RocketMQ等根据自 身需要未严格遵循MQ规范,而是基于TCP\IP自行封装了一套协议,通过网络socket接 口进行传输,实现了MQ的功能。

主流MQ中间件的对比

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

MQ中间件的对比

MQ主要应用场景


应用解耦

应用之间通过引入MQ,使 应用之间的交互改为通过MQ消息来触发,降低应用之间的耦合。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

解耦对比图

  1. 消息的生产者和消费者不强制要求了解对方的业务,只需发布和订阅消息即可。
  2. 生产者和消费者不用管对方的状态,无需同时在线。
  3. 最佳实践:引入消息驱 动模式,将业务操作的结果封装成事件消息通过MQ发布出来。

流量消峰

在高并发的场景中,可以通过引入MQ,将同步操作改为异步操作,通过消费者的数量,控制系统处理的并发度。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

 

在秒杀等高并发场景中,短时间内会涌入大量的请求。通过MQ中间件将请求存储到队列中,通过消息消费者来处理业务,从而达到削峰的目的。

处理要点:

  1. 将原来的单个业务处理接口,拆分为业务提交接口与结果查询接口。
  2. 业务提交接口收到请求后,不直接处理相关业务,而是将请求发送给MQ中间件。
  3. 调用方通过轮询或回调的方式,异步获取业务处理结果。

事务最终一致性

使用MQ作为事务的二次提交的中间节点,存储事务状态,事务参与者通过MQ接收事务状态,进行相应的事务操作。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

处理要点:

  1. 通过消息传递事务的状态。
  2. 需要用事务消息,保证业务事务与消息事务的一 致。
  3. 保证消费的幂等。
  4. 利用延时消息或定时任 务进行兜底。

数据同步

数据发生变更时,通过 MQ将数据变更信息,分发到数据库、Redis、Hbase、搜索引擎等同构或异构系统中。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

处理要点:

  1. 接收数据库binlog 并通过MQ将数据库变动信息发布出去。
  2. 消息消费时要注意保证消费的顺序。

使用MQ的常见问题


消息的事务问题

应用程序本身的事务与mq中间件的事务之间状态可能不一致,导致消息多发或漏发。

MQ的事务问题原因

有两个层面:

  1. MQ中间件本身的事务: 大多数的MQ中间件都是支持事务的,但这个事务指的是MQ资源本身的事务。 例如:通过MQ发送多条消息时,由MQ中间件保证多条消息同时发送成功,或同时发送失败。
  2. 业务事务与MQ事务的一致性: 由于业务操作的数据库事务和消息中间件的事务分属于不同的资源,分产生分布式事务问题。除个别MQ中间件外,大部分MQ中间件都不支持分布式事务,无法保证业务事务与MQ事务的一致性。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

  1. 消息事务嵌入到业务事务内: 当消息已发出,而业务事务由于各种原因失败回滚,会造成不该发送的消息发出去了。
  2. 消息事务在业务事务外: 当消息发送失败时,会造成消息的漏发。

常见解决方案

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

消息表

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

将消息的发送过程拆分两步:

  1. 在业务事务中将消息内容记录到消息表中。
  2. 通过定时任务,扫描消息表中未完成的消息记录,执行消息发送操作。

RocketMQ事务消息

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

事务消息发送步骤如下:

  1. 发送方将半事务消息发送至 RocketMQ ,RocketMQ 将消息持久化成功之后,向发送方返回Ack 确认消息已经发送成功,此时消息为半事务消息。
  2. 发送方开始执行本地事务逻 辑并根据本地事务执行结果向服务端提交二次确认 (Commit 或是 Rollback), 服务端收到Commit 状态则将半事务消息标记为可投递,订阅方最终将收到该消息;服务端收到Rollback状态则删除半事务消息,订阅方将不会接受该消息。

自研事务消息

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

  1. 将消息持久 化到数据库中,以保持与业务事务的一致。
  2. 利用spring事务同步器获得spring事务的状态。
  3. 异常重试时,需要调用确认接口,确认业务状态。

MQ的顺序问题

在数据同步等对顺序要求高的场景,要保证从消息发送、消息存储、消息消费的全链路的顺序一致。

顺序错乱的常见原因

消息发送:多线程并行发送,有顺序的消息被写入到不同的分区,异常重试。

消息消费:多消费者并行消费,或消费者内部启用多线程消费。异常重试。

为什么要保证消息的顺序?

如果业务上通过消息发送的数据是有前后顺序关系时,则必须保证消息的顺序。 例如:通过MQ同步数据时,如果增、改、删的顺序在同步时变为删、改、增,数据将不被删除。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

常见解决方案

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

RocketMQ的顺序消息

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

  1. RocketMQ中的顺序消息分为:全局顺序消息 和分区顺序消息。
  2. 全局顺序消息:所有消息存在同一个topic的同一个分区下,消费时同一时刻只有一个消费者消费。
  3. 分区顺序消息:消息按分片键拆分到不同分 区上,消费时,同一分区,同一时刻只有一个消费者。

自研分区顺序消息

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

  1. 通过ZK协调生产者与消 费者。
  2. 生产者在启动时,将队列的分片信息注册到zk上发送消息时按分片键将消息拆分到不同队列上。
  3. 生产者发送消息时,根据分片键,将消息发送到不同的队列上。
  4. 消费者启动时从zk拉取队列分片信息,选择无消费者的分片进行监听,并将监听状态注册到zk上。

存在问题

  1. 热点消息问题 由于消息的分片键选择不合理,造成各分区的消息不平衡。
  2. 消息的异常处理 当消费出现异常时,如果跳过此消息,会导致后续的消息顺序不正确,如果不跳过此消息,则会造成消息积压。
  3. 消息消费的并行度取决于topic的分区数。 有多少个分区,就有多少个消费者并行消费。

利用版本号保证顺序

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

  1. 消息的顺序需要选定一个分组键,消息的顺序基于此分组键来进行分组排序。
  2. 消息发送时,附加上消息的版本号或顺序号。
  3. 消息消费时,查询消息所在分组当前的版本号,并与当前消息的版本号比对。如果当前消息的版本号<=分组的版本号,则丢弃此消息。否则消费此消息。
  4. 消息消费成功,更新分组的当前版本号。

消息的防重与幂等

当同一消息被重复投递或消费时,能保证消息消费的幂等性。那什么是防重与幂等呢?

防重:保证相同的消息只最多只执行一次 。

幂等:保证相同的消息,每次执行时结果相同。

为什么需要做消息的防重或幂等

  1. 主流的消息中间件都只保证消息最少被投递一次,不保证只投递一次。
  2. 消息发送时重复发送当消息已被服务器持久化,但因网络闪断、服务器宕机等原因导致消息生产者认为消息发送失败,尝试再次发送消息。
  3. 中间件投递消息时重复投递消息中间件在对集群做缩、扩容时触发Rebalance,消费者可能收到重复消息 网络闪断、客户端重启时消息中间件在网络恢复后,会对消息尝试重新投递。

常见解决方案

  1. 通过数据库唯一索引防重: 可使用消息的id或业务id做为数据库中表的主键或唯一索引,通过数据库进行防重。
  2. 通过redis防重: 使用消息的id或业务id作为redis的防重key,通过redis防重。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

  1. 通过业务状态控制做到消费幂等。 通过在sql语句中加入状态过滤条件,只执行指定状态的sql语句,达到幂等性。
  1. 使用redis防重时,由于redis与数据库之间可能 存在状态不一致,无法做到绝对的防重。如对防重 要求高,可使用数据库进行防重。

如何安全的对消息业务进升级?

当系统中同时存在新老消息时,或消费逻辑发生变化时,需要设计版本机制保证消息的兼容性。

升级时的问题

通常基于性能和高可用的考虑,同一队列的消费者会有多个。当消息的内容或消息处理逻辑发生变 化,消费者需要升级时,会产生以下问题:

  1. 无法保证新消息由新消费者处理,实现不了线上的灰度验证。
  2. 由于在程序升级期间会同时存在新老消息和消费者,造成新消息被老消费者消费,或老消息被新 消费者消费。这两种情况都可能造成问题。

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

如何安全的升级消费逻辑

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

注册消费者

「超全面」MQ的应用场景、使用时常见问题以及解决方案都在这啦

消费者流程图

如上图所示,需要将消息增加上具体的版本号,并将生产者的ip和端口号注册到zk上,这样消费者在接收到与自己版本不同到消息时,可以在zk中获取到对应版本到消费者,并将消息内容通过rest等请求方式发送给对应版本号的消费者进行处理,来保证消息的正确处理。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值