RocketMq学习(自用)

整体框架图

在这里插入图片描述

路由中心NameServer

在这里插入图片描述

基本原理

  Broker消息服务器在启动的时候向所有NameServer注册,消息生产者在发送消息之前先从NameServer获取Broker服务器地址列表,然后 根据负载均衡算法从列表中选择一台消息服务器进行消息发送,如果检测到Broker宕机,则从路由注册表中将其移除,但是路由变化不会马上通知消息生产者。
  NameServer本身的高可用可通过部署多台NameServer服务器来实现,但彼此互不通信,也就是NameServer服务器之间在某一时刻的数据并不会完全相同 ,但并不影响消息发送。
  作用:为消息生产者和消息消费者提供Topic的路由信息。因此需要存储路由的信息和管理broker节点的注册和删除

实现原理

路由注册:
  Broker每30s会向NameServer发送心跳包,NameServer收到心跳包后会更新缓存
  若连续120s没有收到心跳包,就会移除Broker的路由信息同时关闭Socket连接。
在这里插入图片描述

发送消息

验证消息
  确保生产者可用,验证消息是否规范

查找路由
  获取发送到的broker节点,先查生产者中有没有缓存topic的路由信息,如果没有就去nameServer中查。

选择消息队列
  不启用故障延迟
    沿着队列轮流往下选,这次是往队列1发,下次就是往队列2发。如果发送异常了,重试的时候就剔除掉该broker下面的所有队列,尝试另一个broker下面的队列。

    这样会带来一个问题,发送消息的时候,我们发现broker-a故障了,重发消息的时候临时剔除了broker-a。但是这个并没有记录下来,发送下一条消息的时候,尝试下个队列,其实有可能还是broker-a下面的队列,这样还是会发送失败一次。
  启用故障延迟
  对于高延迟的、有故障的broker,都会保存下来,并有一个不可用时间段,发送消息的时候都会临时避开这个broker。过了这个时间段,这个broker才可以重新参与选择。判断broker是否可用,就是判断当前时间是否已经超过了那个不可用时间点

消息发送
  根据messageQueue获取broker的网络地址,未缓存就去nameServer里拉
  为消息分配全局唯一ID,并给消息打一个标记(压缩标记、事务标记等)
  构建消息发送请求包,包含各种元数据
  根据消息发送方式,同步、异步、单项方式发消息

消息存储

原理图

在这里插入图片描述
简单流程
1.校验:broker状态异常或消息长度过长
2.延迟处理:延迟级别大于0 放入延迟消息主题
3.获取commitlog文件
4.申请putMessageLock,单机串行写入commitLog
5.设置消息的存储时间,如果没有commit文件,创建一个
6.将消息写入文件,获取消息唯一ID,储存偏移量
7.将消息与写入到文件对应的内存映射中,等待刷写入磁盘
8.数据刷入磁盘

存储文件
Commitlog 文件:消息主体
ConsumeQueue 文件 :消息队列,即关于消息消费的索引文件 ,根据时间戳,使用二分查找。提高主题与消息队列检索消息的速度
Index 索引文件:hash索引机制建立消息索引

文件恢复
  存储文件加载时会进行纠错,然后根据broker是否正常停止 来执行不同的恢复策略
  恢复 正常:从倒数第三个往前遍历直到找到正确的
  非正常:从最后开始遍历
文件冗余需要销毁

主从同步
1.主服务器启动,开始监听从服务器的连接
2.从服务器连接主服务器,主服务器接收,建立TCP连接
3.从服务器从主服务器拉取消息偏移量
4.从服务器持续发送同步请求

读写分离
首先,消息消费者在向 Broker 发送消息拉取请求时,会根据筛选出来的消息队列,判定是从Master,还是从Slave拉取消息,默认是Master。
Broker 接收到消息消费者拉取请求,在获取本地堆积的消息量后,会计算服务器的消息堆积量是否大于物理内存的一定值,如果是,则标记下次从 Slave服务器拉取,计算 Slave服务器的 Broker Id,并响应给消费者。
消费者在接收到 Broker的响应后,会把消息队列与建议下一次拉取节点的 Broker Id 关联起来,并缓存在内存中,以便下次拉取消息时,确定从哪个节点发送请求。

消息消费

整体流程

负载:
  消息队列负载由Rebalance线程默认每隔20s进行一次消息队列负载,获取主题队列信息mqSet与消费组当前所有消费者cidAll,然后按照某一种负载算法进行队列分配,分配原则为同一个消费者可以分配多个消息消息队列,同一个消息消费队列同一时间只会分配给一个消费者。

拉取:
  pullMessageService根据上面负载好的拉取任务进行拉取,默认一批拉取32条消息。

消费:
  并发地对同一个消息消费队列进行消费。如果需要重试,将消息放入一个新的主题的固定名称格式的消息队列中。

定时:
  不支持任意精度的定时消息。将定时消息放入与延迟级别对应的消息消费队列中,主题固定。到时后,将消息转发如相应的消息队列以便拉取

顺序消费:
  串行消费消息,消费消息时必须锁定消费消息队列,broker端会检查锁占用情况

消息负载

分配算法
1.平均分配:
  c1: q1,q2,q3
  c2: q4,q5,q6
  c3: q7,q8
1.平均轮询分配
  c1: q1,q4,q7
  c2: q2,q5,q8
  c3: q3,q6
3. 一致性 hash。 不推荐使用
4.根据配置,为每一个消费者配置固定的消息队列
5.根据 Broker部署机房名,对每个消费者分配
在这里插入图片描述

消息拉取

1.客户端封装请求
  从processQueue(消息的读取偏移量)获取消息内容
  获取主题订阅消息
  构建标记位
  与服务端交互获取broker地址
  异步向broker拉取消息
2.服务器查找并返回消息
  根据订阅消息构建消息过滤器
  获取消息消费队列
  根据消息偏移量获取消息
3.客户端处理返回的消息
  根据相应结果填充相应对象,方便解析
  将偏移量存入客户端 将消息放入消费队列后提交给消费者线程

拉取轮询机制
  rocketMQ是主动拉取,因此有长轮询模式
   5s查看一次消息是否可达(是否连通)
   1毫秒轮询一次

  PullMessageService负责对消息队列进行消息拉取,从远端服务器拉取消息后将消息存入ProcessQueue消息队列处理队列中,然后调用ConsumeMessageService.submitConsumeRequest方法进行消息消费,使用线程池来消费消息,确保了消息拉取于消息消费的解偶

消息消费

1.对消息条数划分,超过最大32条会分页
2.有参数限制,如果该消息被重新分配,停止消费,消费前后都有校验
3.调用监听器 listener.consumeMessage()方法执行具体消费
4.成功消费返回ack

消费未返回ack,重试
  确定配置了重试功能,即允许重试
  创建重试主题,%RETRY%+消费组名称,创建重试topic
  设置重试次数,超过次数会进入只写队列,不再重试,需要人工干预
  一般5s重试一次

定时消息

  rocketMQ的定时消息只支持特定时间的延迟消息,比如 1s 5s 10s 30s lm 2m 3m 4m 5m 6m 7m 8m 9m 这种

流程
  生产者发送消息,如果是定时,放入专门的topic
  每隔1s拉取消息
  到时将消息放入原topic,持久化入磁盘等待消费

与Kafka的区别

转载自:https://blog.csdn.net/damacheng/article/details/42846549
数据可靠性

  RocketMQ支持异步实时刷盘,同步刷盘,同步Replication,异步Replication
  Kafka使用异步刷盘方式,异步Replication
  总结:RocketMQ的同步刷盘在单机可靠性上比Kafka更高,不会因为操作系统Crash,导致数据丢失。 同时同步Replication也比Kafka异步Replication更可靠,数据完全无单点。另外Kafka的Replication以topic为单位,支持主机宕机,备机自动切换,但是这里有个问题,由于是异步Replication,那么切换后会有数据丢失,同时Leader如果重启后,会与已经存在的Leader产生数据冲突。开源版本的RocketMQ不支持Master宕机,Slave自动切换为Master,阿里云版本的RocketMQ支持自动切换特性。

性能对比
  Kafka单机写入TPS约在百万条/秒,消息大小10个字节
  RocketMQ单机写入TPS单实例约7万条/秒,单机部署3个Broker,可以跑到最高12万条/秒,消息大小10个字节
  总结:Kafka的TPS跑到单机百万,主要是由于Producer端将多个小消息合并,批量发向Broker。

RocketMQ为什么没有这么做?
  Producer通常使用Java语言,缓存过多消息,GC是个很严重的问题
  Producer调用发送消息接口,消息未发送到Broker,向业务返回成功,此时Producer宕机,会导致消息丢失,业务出错
Producer通常为分布式系统,且每台机器都是多线程发送,我们认为线上的系统单个Producer每秒产生的数据量有限,不可能上万。
  缓存的功能完全可以由上层业务完成。

单机支持的队列数
  Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长
  RocketMQ单机支持最高5万个队列,Load不会发生明显变化

队列多有什么好处?
  单机可以创建更多Topic,因为每个Topic都是由一批队列组成
  Consumer的集群规模和队列数成正比,队列越多,Consumer集群可以越大

消息投递实时性
  Kafka使用短轮询方式,实时性取决于轮询间隔时间
  RocketMQ使用长轮询,同Push方式实时性一致,消息的投递延时通常在几个毫秒。

消费失败重试
  Kafka消费失败不支持重试
  RocketMQ消费失败支持定时重试,每次重试间隔时间顺延
  总结:例如充值类应用,当前时刻调用运营商网关,充值失败,可能是对方压力过多,稍后在调用就会成功,如支付宝到银行扣款也是类似需求。
  这里的重试需要可靠的重试,即失败重试的消息不因为Consumer宕机导致丢失。

严格的消息顺序
  Kafka支持消息顺序,但是一台Broker宕机后,就会产生消息乱序
  RocketMQ支持严格的消息顺序,在顺序消息场景下,一台Broker宕机后,发送消息会失败,但是不会乱序
  Mysql Binlog分发需要严格的消息顺序

定时消息
  Kafka不支持定时消息
  RocketMQ支持两类定时消息
  开源版本RocketMQ仅支持定时Level
  阿里云ONS支持定时Level,以及指定的毫秒级别的延时时间

分布式事务消息
  Kafka不支持分布式事务消息
  阿里云ONS支持分布式定时消息,未来开源版本的RocketMQ也有计划支持分布式事务消息

消息查询
  Kafka不支持消息查询
  RocketMQ支持根据Message Id查询消息,也支持根据消息内容查询消息(发送消息时指定一个Message Key,任意字符串,例如指定为订单Id)
  总结:消息查询对于定位消息丢失问题非常有帮助,例如某个订单处理失败,是消息没收到还是收到处理出错了。

消息回溯
  Kafka理论上可以按照Offset来回溯消息
  RocketMQ支持按照时间来回溯消息,精度毫秒,例如从一天之前的某时某分某秒开始重新消费消息
  总结:典型业务场景如consumer做订单分析,但是由于程序逻辑或者依赖的系统发生故障等原因,导致今天消费的消息全部无效,需要重新从昨天零点开始消费,那么以时间为起点的消息重放功能对于业务非常有帮助。

消费并行度
  Kafka的消费并行度依赖Topic配置的分区数,如分区数为10,那么最多10台机器来并行消费(每台机器只能开启一个线程),或者一台机器消费(10个线程并行消费)。即消费并行度和分区数一致。
  RocketMQ消费并行度分两种情况
  顺序消费方式并行度同Kafka完全一致
  乱序方式并行度取决于Consumer的线程数,如Topic配置10个队列,10台机器消费,每台机器100个线程,那么并行度为1000。

消息轨迹
  Kafka不支持消息轨迹
  阿里云ONS支持消息轨迹

开发语言友好性
  Kafka采用Scala编写
  RocketMQ采用Java语言编写

Broker端消息过滤
  Kafka不支持Broker端的消息过滤
  RocketMQ支持两种Broker端消息过滤方式
  根据Message Tag来过滤,相当于子topic概念
  向服务器上传一段Java代码,可以对消息做任意形式的过滤,甚至可以做Message Body的过滤拆分。

消息堆积能力
  理论上Kafka要比RocketMQ的堆积能力更强,不过RocketMQ单机也可以支持亿级的消息堆积能力,我们认为这个堆积能力已经完全可以满足业务需求。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值