MetaQ(RocketMQ)

1 有什么用

一般常用来进行业务异步解耦、解耦微服务、流量削峰填谷、消息分发、分布式事务的数据一致性等。

1.1 业务异步解耦 : 在正常业务流程中,比较耗时而且不需要即时返回结果的操作。将这些操作可以做为异步处理,这样可以大大的加快请求的响应时间。

最常见的场景就是用户注册之后,需要发送注册短信、邮件通知,以告知相关信息。
正常做法,是要经过三大步处理:用户信息处理、发送邮件、发送短信,等这三步全部都完成之后,才返回前端,告诉你注册成功了。
使用MQ,只需要在处理完用户信息之后,给MQ发送两个消息即可,邮件服务、短信服务监听MQ的任务消息,根据消息进行发送即可。

1.2 解耦微服务

还是用户注册的例子,将用户注册、邮件/短信发送理解为两个独立的微服务,就非常好理解

1.3 流量削峰填谷

控制流量,也是MQ比较常用的一个场景,一般在秒杀、搞活动中使用广泛。这个时候一般用户请求量会激增,可能会远超当前系统的最大处理量,如果不做任何处理,系统可能就会宕掉。
使用MQ,可以将需要处理的消息全部放入其中,系统按照最大处理能力,去获取消息进行消费,这样就可以将一瞬间过来的请求,分散到一段时间内进行处理,避免了系统的崩溃。

1.4 消息分发

多个系统对同一个数据感兴趣,只需要监听同一类消息即可。
例如付款系统,在付款成功之后,正常做法是通知外围系统这个单子付款成功了,或者是外围系统定时来拉取付款结果,使用MQ后,付款系统可以在付款成功之后,将消息放到MQ里面,想知道这个结果的系统订阅这个主题的消息即可,非常方便,也不需要定时去拉取数据了。

2 是什么

MQ(Message Queue)消息队列,是基础数据结构中先进先出的一种数据结构。指把要传递的数据(消息)放到队列中,用队列机制来实现消息传递 - 生产者产生消息并把消息放入队列,然后由消费者去处理。消费者可以到指定队列去拉取消息,或者订阅相应的队列,由MQ服务端给其推送消息。

  • 是一个队列模型的消息中间件,具有高可用,高可靠,高实时,分布式的特点
  • Producer,Consumer,队列都可以分布式
  • Producer向一些队列轮流发送消息,队列集合称为Topic,Consumer如果做广播消费,则一个consumer实例消费这个Topic的所有对应的队列,如果做集群消费,则多个Consumer实例平均消费这个Topic对应的队列集合
  • 能够保证严格的消费顺序
  • 提供丰富的消费拉取模式
  • 高效的订阅者对平扩展能力
  • 实时的消息订阅机制
  • 亿级消息堆积能力

消费关系

MetaQ(RocketMQ)_第1张图片

经典的Producer,Broker,Consumer消费模型,不同类型的消息以不同的Topic来区分。为了解决性能问题,一个Topic下可以根据需求设置为一个或多个消息队列,Message Queue类似数据库中的分区。Producer按照负载均衡策略将消息发送到Topic不同的消息队列中,Consumer可以从队列中取出消息并发的去消费。

物理部署结构(高可用)

MetaQ(RocketMQ)_第2张图片

  • NameServer : 用于服务发现,提供服务名称,NameServer是一个无状态节点,可以集群部署,节点之间无任何信息同步
  • Broker : MetaQ的服务器,负责消息中转,主要职责是存储,转发消息。部署相对复杂,Broker分为Master和Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master。Master和Slave之间的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个,每个Broker与Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有的Name Server。
  • Producer : 消息生产者,负责生产消息,一般是业务系统。Producer与Name Server集群中的一个节点(随机选择)建立长连接,定期从Name Server种获取Topic路由信息,并向提供Topic服务的Master建立长连接,并且定时向Master发送心跳。Producer完全无状态,可集群部署。
  • Consumer : 消息消费者,负责消费消息,一般是后台系统负责异步消费。Consumer与Name Server集群中的一个节点(随机选择)建立长连接,定期从Name Server获取Topic路由信息,并且向提供Topic服务的Master,Slave建立长链接,且定时向Master,Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。

通信协议

MetaQ通信组件直接使用Netty,在其上做了简单的封装。Netty是一个事件驱动的网络编程框架,它屏蔽了Java底层的复杂细节,具备高性能,高可靠性。
网络协议
在这里插入图片描述

  1. length 4 个字节整数,等于 2、3、4 长度总和
  2. header 4 个字节整数,等于 header data 的长度
  3. 使用 json 序列化数据
  4. 应用自定义二进制序列化数据

数据存储结构

MetaQ(RocketMQ)_第3张图片

目录结构
MetaQ(RocketMQ)_第4张图片

MetaQ消息存储是由CommitLog和ConsumeQueue配合完成的,CommitLog真正存储消息,存储在实际CommitLog物理存储中,ConsumeQueue存储消息在CommitLog上的索引,类似于数据库的索引文件,存储的是消息在实际CommitLog物理存储中的偏移地址。每个Topic下的每个Queue都有一个ConsumeQueue文件,文件地址在{root}/consumequeue/{topicName}/{queueId}

CommitLog以物理文件存储,每个Broker上的CommitLog被该机器上的所有Queue共享(也就是说一个Broker上只有一个CommitLog文件)

  • 所有数据单独存储到一个CommitLog,完全顺序写,随机读
  • 对最终用户展现的队列实际只存储消息在CoomitLog的位置信息,并且串行方式刷盘

优点

  1. 队列轻量化,单个队列数据量非常少
  2. 对磁盘的访问串行化,避免磁盘竞争,不会因为队列增加导致IO等待时间增多

缺点

  1. 顺序写,随机读
  2. 读一条消息,会先读ConsumeQueue,再读CommitLog,增加了kaixiao
  3. 要保证CommitLog和ConsumeQueue完全一致,增加l编程的复杂度

对于缺点的克服

  1. 随机读 : 尽可能让读命中page cache,减少IO读操作,所以内存越大越好。如果系统中堆积的消息过多,**读数据要访问磁盘不会由于随机读导致系统性能急剧下降。**访问page cache时,即使只访问1k的消息,系统也会提前预读出更多的数据,在下次读时就会命中内存。
  2. 随机访问CommitLog磁盘数据,系统IO调度算法设置位NOOP方式,会在一定程度上完全随机,读变成顺序跳跃方式,而顺序跳跃方式读较完全随机读性能高5陪以上
  3. 由于Consume Queue 存储数据极少,而且是顺序读,在page cache预读作用下,Consume Queue的读性能几乎与内存一致,即使堆积情况下。所以可认为Consume Queue完全不会阻碍读性能
  4. CommitLog中存储了所有的元信息,包含消息体,类似于Mysql,Oracle的redolog,所以只要有CommitLog在,Consume Queueu即使数据丢失,仍然可以恢复出来。

消息持久性刷盘策略

metaq的所有消息都是持久化的,先写入系统page cache,然后刷盘,可以保证内存和磁盘都有一份数据
访问时,直接从内存读取。目前,metaq的刷盘策略使用的是异步刷盘等方式
MetaQ(RocketMQ)_第5张图片

异步刷盘
broker节点收到消息之后,将消息写入缓存便返回成功。当收到一定数量的消息条数或一定量大小的消息,再批量刷到磁盘
同步刷盘
broker节点收到消息,将消息写入缓存,并会当缓存中的数据落到磁盘之后,才会返回成功

高级特性

顺序消息
1 全局顺序

对于指定的一个Topic,所有的消息严格按照先入先出的(FIFO)的顺序进行发布和消费
在这里插入图片描述

2 分区顺序

对于指定的一个Topic,所有的消息根据sharding key进行区块分区。同一个分区内的消息严格按照FIFO的顺序发布和消费。
MetaQ(RocketMQ)_第6张图片

将同一个Topic下的多个消息消息队列,进行分区
顺序消息的缺陷

  • 发送顺序消息无法利用集群的FailOver特性
  • 消费顺序消息的并行依赖于队列数量
  • 队列热点问题,个别队列由于哈嘻不均导致消息过多,消费速度跟不上,产生消息堆积问题
  • 遇到消费失败的消息,无法跳过,当前队列消费暂停
事务消息

MetaQ(RocketMQ)_第7张图片

  1. 发送方向MQ服务端发送half消息
  2. MQ Server将消息持久化成功之后,向发送方发送ACK消息,确认消息持久化成功
  3. 发送方开始执行本地事物逻辑
  4. 发送方根据本地事物的执行结果向MQ Server提交二次确认(Commit或Rollback),MQ Server收到Commit状态则将半消息标记为可投递,订阅方最终将收到此消息;MQ Server收到Roolback状态则删除半消息,订阅方将不会收到此消息。
  5. 在断网或应用重启的特殊情况下,上述步骤4提交的二次确认并未到达MQ Server,经过固定的时间之后MQ Server将对未提交的消息发起回查
  6. 发送方收到消息回查之后,需要检查对应消息的本地事物的执行结果
  7. 发送方根据本地事物的回查结果进行二次确认,MQ Server仍按照步骤4对半消息进行操作

事务消息发送对应步骤1,2,3,4 ,事务回查对应步骤5,6,7

负载均衡

1 对于生产者的负载均衡
主要在于生产者发送消息时,会发往broker里面topic分区。多个broker里对同一个topic有多个分区,生产者发送的消息需要确认发往那个分区。此处负载均衡策略是,将所有的broker里面的分区组成一个圈,按从头到位循环遍历选择topic分区发送消息。
2 对于消费者的负载均衡
主要是消费者在消费时,会选择consumer group的哪个consumer进行消费
此处策略是

  • 每个topic分区针对同一个consumer group,只选择一个consumer进行消费
  • 如果consumer group的consumer数量大于topic分区(也就是队列)数量,则多出的consumer不消费
  • 如果同一个consumer group的consumer数量小于topic分区(也就是队列)数量,则有些consumer需要承担更多的消费任务

3 怎么用

引用文章 : https://blog.csdn.net/qq_48607414/article/details/125801014

3.1 发送普通消息

发送普通消息的方式有三种,同步,异步,Oneway
代码示例 : https://help.aliyun.com/document_detail/29547.html?spm=a2c4g.11186623.2.11.56d6783eLPaTwZ#concept-2047086

● 同步发送 : 客户端提交消息到broker之后会等待返回结果,相对常用的方式
● 异步发送 : 调用发送接口时会注册一个callback类,发送线程继续其他业务逻辑,producer在收到消息之后回调。比较适合不想发送结果影响正常业务逻辑的情况
● Oneway : Producer提交消息之后,无论是broker是否真正常收到消息都不关心,适合追求高吞吐,能容忍消息丢失败的情况,比如日志收集

消息发送失败怎么处理?

乱序重试消息
该重试是针对消息乱序消费的情况
何时重试
抛出运行时异常或者返回ConsumerConsurrentlyStatus.RECONSUME_LATER,metaq会自动重试
重试策略
会自动重试16次,超过16次还失败,则消息进入死信队列,不再提供重试机制。死信队列的消息不可以读取,每次消费失败,应用可以设置消息下次重试时间间隔,正常情况下,间隔时间比较准确,在broker压力比较大的情况下,间隔时间可能比设置时间要长
客户端代码(设置间隔时间)
MetaQ(RocketMQ)_第8张图片

重试等级及其对应的间隔:
在这里插入图片描述

如果重试16次还是失败后,先告警,然后可以考虑消息本地落地,然后使用定时任务取出消息然后再发送。

顺序重试消息
该重试是针对消息顺序消费的情况
何时重试
抛出运行时异常或者返回ConsumerOrderlyStatus.SUSPEND_CURRENT_QUWUW_A_MONENT , metaq会自动重试,知道返回成功才停止重试
重试策略
因为要保证消费的顺序性,所以某一个队列的某条消息消费失败,那么这个队列就暂停消费,知道该消息重试成功。其他队列不受影响,重试行为完全在客户端执行,不需要服务器参与
MetaQ(RocketMQ)_第9张图片

注意: 广播消费消息不支持失败重试,广播消费进度会在消费者本地磁盘五秒钟刷盘一次。

3.3 最佳实践

Producer最佳实践

  1. 每个消息在业务层面的唯一标识,要设置keys字段,方便将来定位消息丢失问题。由于是哈希索引,key值尽量保持唯一性,可避免潜在的哈希冲突。
  2. 消息发送成功或失败,要打印日志,务必打印sendResult和key字段
  3. 对于消息不可丢应用,务必要有消息重发机制。例如:消息发送失败,存储到数据库,能有定时程序尝试重发或人工触发重发。
  4. 某些应用如果不关注消息是否是否发送成功,请直接使用sendOneWay方法发送消息

Consumer最佳实践

  1. 消费过程要做到幂等(即消费端去重)
  2. 尽量使用批量方式消费,可以很大程度上提高消费吞吐量
  3. 优化每条消息的消费过程

你可能感兴趣的:(中间件,java-rocketmq,rocketmq,微服务)