RocketMQ

RocketMQ

中间件

消息中间件(Message Queue,MQ)基于队列与消息传递技术,在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。

消息中间件:分布式系统中完成消息的发送和接收的基础工具。消息中间件也可以称消息队列,是指用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息队列模型,可以在分布式环境下扩展进程的通信。
在这里插入图片描述

RPC是远程过程调用(Remote Procedure Call)的缩写形式。SAP系统RPC调用的原理其实很简单,有一些类似于三层构架的C/S系统,第三方的客户程序通过接口调用SAP内部的标准或自定义函数,获得函数返回的数据进行处理后显示或打印。

消息中间件使用场景

应用解耦

在这里插入图片描述

通常写法是左图、用户下单后、订单系统需要分别调用别的系统、支付系统、物流系统和库存系统、假如物流系统无法访问,则订单出库将失败,从而导致订单失败。

处理方式:

引入消息队列机制、在用户下单后、订单系统完成持久化处理、将消息写入消息队列、直接返回用户下单成功、其他三系统分别从消息队列获取任务并执行。

流量削峰

在这里插入图片描述

在秒杀情况下可能会出现、每秒5k请求、但是mysql处理量有限、导致请求阻塞。

引如消息队列后、用户请求被服务器接收后存入消息队列、用户订单请求就结束了、A系统在每秒从队列中拉取200个请求进行持久化操作。就是一种以空间换时间的操作、也就是说如果我们的高峰时间为10S,那么我们对应的处理时间就是250S。

异步处理

在这里插入图片描述

用户注册后,需要发注册邮件和注册短信。
传统的做法有两种 :

  • 串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
  • 并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。

假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)。

如果使用消息队列,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因为写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。

中间件各个角色

在这里插入图片描述

NameServer 角色

注册服务中心 维护Producer 和 Consumer 的配置信息、状态信息

Broker Cluster 角色

主要负责消息的存储、查询消费,支持主从部署

Producer 角色

消息的发送者,它负责产生消息,可以集群部署。它会先和 NameServer 集群中的随机一台建立长连接,得知当前要发送的 Topic 存在哪台 Broker Master上,然后再与其建立长连接,支持多种负载平衡模式发送消息。

Consumer 角色

消息的消费者,也可以集群部署。它也会先和 NameServer 集群中的随机一台建立长连接,得知当前要消费的 Topic 存在哪台 Broker Master、Slave上,然后它们建立长连接,支持集群消费和广播消费消息。

中间件中的基本概念

主题(Topic)

同一类消息的标识,例如某宝电商,衣服、手机、咖啡等都是一个主题,一般我们在生产或者消费时都会指定一个主题,要么生产这个主题的消息,要么订阅这个主题的消息。

分组(Group)

可以对生产者或者消费者分组,一般都针对于消费者的分组,分组是一个很有意义的事情,因为消费者都是对某一类消息的消费,消费的逻辑都是一致的,比如是一个订单主题的消息,我们可以有一个物流组来消费它,同时也可以定位一个通知组来消费这个消息。相互之间是隔离的,有可能会消费重复的消息。

消息队列(Message Queue)

是一个容器的概念,同一个主题有可能根据分组的不同,会产生不同的队列以供不同的消费组别进行消费。

标签(Tag)

更加细分的划分,在消费的时候我们可以根据 Tag 的不同来订阅不同标签消息,类似于 MySQL 查询中的条件。

偏移量(Offset)

message queue 是无限长的数组,一条消息进来下标就会涨1,下标就是 offset,消息在某个 MessageQueue 里的位置,通过 offset 的值可以定位到这条消息,或者指示 Consumer 从这条消息开始向后处理。

普通消息

在这里插入图片描述

同步发送

每一次发送消息 MQ都会进行响应。响应后再发送

异步发送

同样能得到响应,但是却是通过异步监听方式来获取的。所以在异步发送时,并不会阻塞当前线程。消息发送者不需要长时间等待消息的响应,是通过异步监听获取到响应结果。

单向发送

只管发送不管有没响应结果。

三种发送方式区别

发送方式发送速度发送结果反馈可靠性适用场景
同步发送不丢失重要通知邮件、报名短信通知、营销短信系统等
异步发送不丢失异步发送一般用于链路耗时较长,对响应时间较为敏感的业务场景,例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。
单向发送最快可能丢失适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

消息生产

  1. 创建生产者对象producer、组名
  2. 指定 NameSrv 地址
  3. 开启生产者
  4. 创建消息对象指定Topic(主题)、标签(tag)、主体
  5. 发送消息
  6. 关闭生产者 producer

消息消费

  1. 创建消费者对象、指定组名(与生产者组名无关)
  2. 指定NameSrv地址
  3. 设置订阅主体
  4. 设置消费者方式(默认未集群消费)
  5. 设置回调函数处理消息
  6. 开启消费者

集群消费与广播消费

集群消费

每条消息只处理一次、多个消费者将消息分摊消费。

注意事项

  • 集群消费模式下,每一条消息都只会被分发到一台机器上处理。如果需要被集群下的每一台机器都处理,请使用广播模式。
  • 集群消费模式下,不保证每一次失败重投的消息路由到同一台机器上。

广播消费

消息被集群下所有消费者都处理一次

注意事项

  • 广播消费模式下不支持顺序消息。

  • 广播消费模式下不支持重置消费位点。

  • 广播模式下不支持线下联调分组消息。

  • 每条消息都需要被相同订阅逻辑的多台机器处理。

  • 消费进度在客户端维护,出现重复消费的概率稍大于集群模式。

  • 广播模式下,消息队列保证每条消息至少被每台客户端消费一次,但是并不会重投消费失败的消息,因此业务方需要关注消费失败的情况。

  • 广播模式下,客户端每一次重启都会从最新消息消费。客户端在被停止期间发送至服务端的消息将会被自动跳过,请谨慎选择。

  • 广播模式下,每条消息都会被大量的客户端重复处理,因此推荐尽可能使用集群模式。

  • 广播模式下服务端不维护消费进度,所以消息队列控制台不支持消息堆积查询、消息堆积报警和订阅关系查询功能。

顺序消息

顺序消息(FIFO 消息)是消息队列提供的一种严格按照顺序来发布和消费的消息类型。可以被分为:

  • 全局顺序消息
  • 部分顺序消息

顺序消费的原理解析

  • 默认情况下、消息发送会采取轮询方式发送到不同的queue (分区队列)。而消费消息的时候从多个不同的queue上获取消息、就会导致消费不是有序的。
  • 如果控制发送的顺序消息只发送在一个queue上、消费时只从这个queue上依次拉取消息进行消费、就保证了有序。
  • 当发送和消费参与的queue只有一个、则是全局有序;如果有多个quque参与则是局部有序。即分区有序、每个队列消息有序。

RocketMQ 的 ACK(Acknowledgement) 机制

ACK,即一种消息确认字符,在数据通信中,消息接受站给消息发送站的一种传输类控制符,表示传输过来的数据已经接受无误。

PushConsumer 为了保证消息肯定消费成功,只有使用方明确表示消费成功,RocketMQ 才会认为消息消费成功。中途断电,抛出异常等都不会认为成功——即都会重新投递。

业务实现消费回调的时候,当且仅当此回调函数返回 ConsumeConcurrentlyStatus.CONSUME_SUCCESS,RocketMQ 才会认为这批消息(默认是1条)是消费完成的。

如果这时候消息消费失败,例如数据库异常,余额不足扣款失败等一切业务认为消息需要重试的场景,只要返回 ConsumeConcurrentlyStatus.RECONSUME_LATER ,RocketMQ 就会认为这批消息消费失败了。

为了保证消息是肯定被至少消费成功一次,RocketMQ 会把这批消息重发回 Broker,在延迟的某个时间点(默认是10秒,业务可设置)后,再次投递到这个 ConsumerGroup。而如果一直这样重复消费都持续失败到一定次数(默认16次),就会投递到DLQ死信队列。
urrentlyStatus.RECONSUME_LATER ,RocketMQ 就会认为这批消息消费失败了。

为了保证消息是肯定被至少消费成功一次,RocketMQ 会把这批消息重发回 Broker,在延迟的某个时间点(默认是10秒,业务可设置)后,再次投递到这个 ConsumerGroup。而如果一直这样重复消费都持续失败到一定次数(默认16次),就会投递到DLQ死信队列。

事务消息

在一些对数据一致性有强需求的场景、使用事务消息来解决、从而保证上下游数据一致性。

在这里插入图片描述

以电商交易场景为例,用户支付订单这一核心操作的同时会涉及到下游物流发货、积分变更、购物车状态清空等多个子系统的变更。当前业务的处理分支包括:

  • 主分支订单系统状态更新:由未支付变更为支付成功。
  • 物流系统状态新增:新增待发货物流记录,创建订单物流记录。
  • 积分系统状态变更:变更用户积分,更新用户积分表。
  • 购物车系统状态变更:清空购物车,更新用户购物车记录。

使用普通消息和订单事务无法保证一致的原因,本质上是由于普通消息无法像单机数据库事务一样,具备提交、回滚和统一协调的能力。 而基于 RocketMQ 的分布式事务消息功能,在普通消息基础上,支持二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。

在这里插入图片描述

事务消息的发送分为两个阶段、第一阶段发送一个半事务消息、半事务消息指的是暂不能投递的消息。生产者已经成功将消息发送到了broker、但是Broker 未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,如果发送成功则执行本地事务,并根据本地事务执行成功与否,向 Broker 半事务消息状态(commit或者rollback),半事务消息只有 commit 状态才会真正向下游投递。如果由于网络闪断、生产者应用重启等原因,导致某条事务消息的二次确认丢失,Broker 端会通过扫描发现某条消息长期处于“半事务消息”时,需要主动向消息生产者询问该消息的最终状态(Commit或是Rollback)。这样最终保证了本地事务执行成功,下游就能收到消息,本地事务执行失败,下游就收不到消息。总而保证了上下游数据的一致性。

在这里插入图片描述

RocketMQ 的高可用机制

集群部署模式

  • 单 master 模式
  • 多 master 模式
  • 多 master 多 slave 模式(同步)
  • 多 master 多 slave 模式(异步)
    在这里插入图片描述

RocketMQ分布式集群是通过Master、和Slave的配合达到高可用的。

Master 和 Slave 的区别

在 Broker 的配置文件中,参数 brokerId 的值为0表明这个 Broker 是 Master,大于0表明这个 Broker 是 Slave。

Master 角色的 Broker 支持读和写,Slave 角色的Broker仅支持读,也就是 Producer 只能和 Master 角色的 Broker 连接写入消息;Consumer 可以连接 Master 角色的 Broker,也可以连接 Slave 角色的 Broker 来读取消息。

消费消息高可用

在 Consumer 的配置文件中,并不需要设置是从 Master 读还是从 Slave 读,当 Master 不可用或者繁忙的时候,Consumer 会被自动切换到从 Slave 读。有了自动切换 Consumer 这种机制,当一个 Master 角色的机器出现故障后,Consumer 仍然可以从 Slave 读取消息,不影响 Consumer 程序。这就达到了消费端的高可用性。

消息发送高可用

在创建Topic的时候、把Topic的多个Message Queue创建在多个Broker组上、这样当一个Broker组的Master不可用之后、其他组的Master仍然可用、Producer 仍然可以发送消息。

刷盘与主从同步

  • 同步刷盘与异步刷盘
  • 同步复制与异步复制
    在这里插入图片描述
同步刷盘与异步刷盘

RocketMQ 的消息是存储到磁盘上的,这样既能保证断电后恢复,又可以让存储的消息量超出内存的限制。RocketMQ 为了提高性能,会尽可能地保证磁盘的顺序写。

异步刷盘方式:
在返回写成功状态时,消息可能只是被写入了内存的 PAGECACHE,写操作的返回快,吞吐量大;当内存里的消息量积累到一定程度时,统一触发写磁盘操作,快速写入。

即消息只是写在了缓冲区、然后给生产者返回成功信息、当缓冲区消息达到一定量时再写入磁盘;

优点:性能高
缺点:Master宕机,磁盘损坏的情况下,会丢失少量的消息, 导致MQ的消息状态和生产者/消费者的消息状态不一致

同步刷盘方式

在返回应用写成功状态前,消息已经被写入磁盘。具体流程是,消息写入内存的 PAGECACHE 后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,给应用返回消息写成功的状态。

即消息写入缓冲区后、立即执行刷盘、等待消息写入磁盘。刷盘成功后才向生产者返回成功消息。

优点:可以保持MQ的消息状态和生产者/消费者的消息状态一致
缺点:性能比异步的低

同步复制和异步复制

同步复制

Master和Slave都写成功后返回给客户端写成功状态。

同步复制方式下、如果Master发生故障、 Slave 上有全部的备份数据,容易恢复,但是同步复制会增大数据写入延迟,降低系统吞吐量。

异步复制

只要 Master 写成功 即可反馈给客户端写成功状态,在异步复制方式下,系统拥有较低的延迟和较高的吞吐量,但是如果 Master 出了故障,有些数据因为没有被写入 Slave,有可能会丢失。

RocketMQ 存储结构

CommitLog 文件

commitLog 是存储消息的主体。Producer 发送的消息都会顺序写入 commitLog 文件,所以随着写入的消息增多,文件也会随之变大。单个文件大小默认1G, 文件名长度为20位,左边补零,剩余为起始偏移量,比如 00000000000000000000 代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。

commitLog 以物理文件的方式存放,每台 Broker 上的 commitLog 被本机器所有 consumeQueue 共享。在 commitLog,一个消息的存储长度是不固定的,RocketMQ 采用了一些机制,尽量向 commitLog 中顺序写,但是随即读。

ConsumeQueue 文件

ConsumeQueue (逻辑消费队列)可以看成基于 topic 的 commitLog 的索引文件。因为 CommitLog 是按照顺序写入的,不同的 topic 消息都会混淆在一起,而 Consumer 又是按照 topic 来消费消息的,这样的话势必会去遍历 commitLog 文件来过滤 topic,这样性能肯定会非常差,所以 RocketMQ 采用 ConsumeQueue 来提高消费性能。即每个 Topic 下的每个 queueId 对应一个 ConsumeQueue,其中存储了单条消息对应在 commitLog 文件中的物理偏移量 offset,消息大小 size,消息 Tag 的 hash 值。

IndexFile 文件

因为所有的消息都存在 CommitLog 中,如果要实现根据 key 查询 消息的方法,就会变得非常困难,所以为了解决这种业务需求,有了 IndexFile 的存在。用于为生成的索引文件提供访问服务,通过消息 Key 值查询消息真正的实体内容。在实际的物理存储上,文件名则是以创建时的时间戳命名的,固定的单个 IndexFile 文件大小约为400M,一个 IndexFile 可以保存 2000W个索引。

为什么要顺序写,随机读?

[ 磁盘存储的“快”——顺序写 ]
    磁盘存储,使用得当,磁盘的速度完全可以匹配上网络的数据传输速度,目前的高性能磁盘,顺序写速度可以达到600MB/s,超过了一般网卡的传输速度。
        
[ 磁盘存储的“慢”——随机写 ]
    磁盘的随机写的速度只有100KB/s,和顺序写的性能差了好几个数量级。
        
[ 存储机制这样设计的好处——顺序写,随机读 ]
     CommitLog 顺序写,可以大大提高写入的效率;虽然是随机读,但是利用 package 机制,可以批量地从磁盘读取,作为 cache 存到内存中,加速后续的读取速度。
    为了保证完全的顺序写,需要 ConsumeQueue 这个中间结构,因为 ConsumeQueue 里只存储偏移量信息,所以尺寸是有限的。

    在实际情况中,大部分 ConsumeQueue 能够被全部读入内存,所以这个中间结构的操作速度很快,可以认为是内存读取的速度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值