栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

项目总结RocketMQ

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

项目总结RocketMQ

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


目录

前言

介绍下RocketMQ?

RocketMQ工作原理:

衍生问题

RocketMQ消费消息是push还是pull?

如何让RocketMQ保证 消息的顺序消费?

如何保证RocketMQ的消息不丢失?

RocketMQ消息堆积如何处理?

         堆积时间过长消息超时了?

        堆积的消息会不会进死信队列?

RocketMQ为什么自研的nameserver而不用zk(zookper)?


前言

项目采用了RocketMQ消息队列实现支付结果的异步通知、延迟消息等需求。

介绍下RocketMQ?

        RocketMQ是MQ的一种,MQ(Message Queue),是一种提供消息队列服务的中间件,提供了消息生产、存储、消费全过程的API的软件系统。其核心功能有解耦、异步、削峰。常见的MQ主要有RabbitMQ、RocketMQ和Kafka。考虑到各个MQ的优缺点和本项目的功能需求,综合考虑选择使用了RocketMQ。RocketMQ是阿里开源的一款分布式,队列模型的消息中间件,支持事务消息、顺序消息、批量消息、延迟消息,并且天然然支持集群、负载均衡,支持指定次数和时间间隔的失败消息重发。并且RocketMQ完全基于java开发,方便二次开发使用。RocketMQ曾经受住了多次双十一这种极致场景的压力。(像2017年的双十一,RocketMQ流转的消息量达到了万亿级,峰值TPS达到了5600万)。其内部组成结构有生产者集群、消费者集群、NameServer集群、Broker集群四部分。分别负责生产消息,消费消息,收集broker的工作情况,看broker有没有宕机之类的,broker是核心,负责消息的接受,存储,发送等。 需要定时发送自身状态 到NameServer,默认10秒发送一次,超时2分钟会认为该broker失效。

本项目主要使用RocketMQ本身的特性来帮助支付渠道代理服务和交易服务之间的通信。 获取支付结果的方案流程如下:         (1)首先支付渠道代理服务调用第三方支付下单接口。(顾客开始输入密码进行支付)         (2)首先支付渠道代理服务发送一条支付结果查询的延迟消息给RocketMQ,消息topic为“订单结果查询”。这个消息的消费方仍然是支付渠道代理服务,目的就是为了实现延迟,防止用户未完成支付。         (3)支付渠道代理服务监听到消息,消费消息,调用支付宝接口查询支付结果。         (4)支付渠道代理服务调用支付宝的订单查询接口查询到订单支付状态,将支付结果发送到MQ。此时生产者是支付渠道代理服务,消费者是交易服务,消息topic是“订单支付结果”。         (5)交易服务监听MQ得到支付结果的消息,更新订单状态。

RocketMQ工作原理:

1) Producer Cluster 消息生产者群 负责发送消息,一般由业务系统负责产生消息。 2) Consumer Cluster 消息费群 负责消费消息,一般是后台系统负责异步消费。         两种消费消息的模式:                 Push Consumer,服务端向消费者端推送消息。当消费方消费速率不足的时候容易导致消费的缓冲区溢出,导致异常。                 Pull Consumer,消费者端向服务定时拉取消息  默认都是pull,虽然有push类,但是实际顶层实现采用的是长轮询机制,即拉取方式。   3) NameServer 名称服务器  集群架构中的组织协调员,相当于注册中心,收集broker的工作情况,不负责消息的处理 4 )Broker 消息服务器 是RocketMQ的核心,负责消息的接受,存储,发送等。 需要定时发送自身状态 到NameServer,默认 10 秒发送一次,超时 2 分钟会认为该 broker 失效。                 

衍生问题 RocketMQ延迟消息这么实现的?

  1.producer端设置消息delayLevel延迟级别,消息属性DELAY中存储了对应了延时级别
  2.broker端收到消息后,判断延时消息延迟级别,如果大于0,则备份消息原始topic,queueId,并将消息topic改为延时消息队列特定topic(SCHEDULE_TOPIC),queueId改为延时级别-1
  3.mq服务端ScheduleMessageService中,为每一个延迟级别单独设置一个定时器,定时(每隔1秒)拉取对应延迟级别的消费队列
  4.根据消费偏移量offset从commitLog中解析出对应消息
  5.从消息tagsCode中解析出消息应当被投递的时间,与当前时间做比较,判断是否应该进行投递
  6.若到达了投递时间,则构建一个新的消息,并从消息属性中恢复出原始的topic,queueId,并清除消息延迟属性,从新进行消息投递

RocketMQ消费模式有几种?

        消费模式由Consumer决定,消费维度为Topic。

        (1)集群消费。 当使用集群消费时,每条消息只会被consumer集群的任意一个consumer实例消费一次。举个例子,当一个consumer集群有三个consumer实例时,一条消息投递过来,只会被其中的一个consumer消费。另外,多个集群同时消费一个Topic时,每个Group都会有一个Consumer消费到数据。

        同时集群消费的时候,consumer 的消费进度是存储在 broker 上,consumer 自身是不存储消费进度的。消息进度存储在 broker 上的好处在于,当你 consumer 集群是扩大或者缩小时,由于消费进度统一在broker上,消息重复的概率会被大大降低了。

        (2)广播消费。 当 consumer 使用广播消费时,每条消息都会被 consumer 集群内所有的 consumer 实例消费一次,也就是说每条消息至少被每一个 consumer 实例消费一次。举个例子,当一个 consumer 集群内有 3 个 consumer 实例(假设为 consumer 1、consumer 2、consumer 3)时,一条消息投递过来,会被 consumer 1、consumer 2、consumer 3都消费一次。

        与集群消费不同的是,consumer 的消费进度是存储在各个 consumer 实例上,这就容易造成消息重复。还有很重要的一点,对于广播消费来说,是不会进行消费失败重投的,所以在 consumer 端消费逻辑处理时,需要额外关注消费失败的情况。

        虽然广播消费能保证集群内每个 consumer 实例都能消费消息,但是消费进度的维护、不具备消息重投的机制大大影响了实际的使用。因此,在实际使用中,更推荐使用集群消费,因为集群消费不仅拥有消费进度存储的可靠性,还具有消息重投的机制。而且,我们通过集群消费也可以达到广播消费的效果。

        使用集群模式模拟广播模式:如果业务上需要广播模式,可以创建多个consuumer实例,每个consumer实例属不同的consumer集群,但是都订阅同一个topic。每个 consumer 实例的消费逻辑可以一样也可以不一样,每个consumer集群还可以根据需要增加 consumer 实例,比起广播消费来说更加灵活。

RocketMQ消费消息是push还是pull?         RocketMQ没有真正意义的push,都是pull,虽然有push类,但实际底层实现采用的是长轮询机制,即拉取方式。broker端属性longPollingEnable标记是否开启长轮询。默认开启。 为什么要主动拉取而不是使用时间监听方式?         事件驱动方式是建立好长连接,由事件(发送数据)的方式来实时推送。如果broker主动推送消息的话,有可能出现push的速度快,消费速度慢的情况,那么会造成consumer端堆积果多,同时消息还不能被其他consumer消费的情况。而pull的方式可以根据当前自身情况来pull,不会造成果多的压力。所以采取了pull的方式。

如何让RocketMQ保证消息的顺序消费?         多个queue只能保证单个queue里的顺序,queue是典型的FIFO,天然顺序。多个queue同时消费是无法绝对保证消息的有序性。也就是说同一个topic,同一个queue,发消息的时候一个线程去发送消息,消费的时候一个线程去消费一个queue里的消息。         broker如何处理拉取请求的?

                Consumer首次请求Broker。 判断Broke中是否有满足条件的消息。 有的话就响应Consumer,等待Consumer下次请求。  没有的话就通过一个PullRequestHoldService方法来保持连接,每五秒进行一次检查,看看pullRequestTable中有没有消息,有的话立即推送。每隔1ms还会检查commitLog中是否有新消息,有的话写入到pullRequestTable中。当有新消息的时候返回请求。挂起consumer的请求,即不断开连接,也不返回数据。consumer会提交一个 offset(用来查看消费进度)。

如何保证RocketMQ的消息不丢失?         这个问题需要从三个部分来考虑。         首先在producer端,采用send()同步发消息,发送结果是同步感知的;发送失败后可以重试,设置重试次数。默认三次;  集群部署,比如发送消息失败的原因可能是这台broker宕机啦,那么重试的时候会发送到别的broker上。         其次在broker端。  修改刷盘策略为同步刷盘,默认情况下是异步刷盘的;  集群部署,主从模式,高可用。         最后是Consumer端。 完全消费正常后进行手动ack确认。         (刷盘策略指的是 broker 中消息的 落盘 方式,即消息发送到 broker 内存后消息持久化到磁盘的方式。同步刷盘指消息持久化到broker的磁盘才算写入成功。异步指写入到broker的内存即成功,无需等待消息持久化到磁盘)

RocketMQ消息堆积如何处理?

        MQ消息堆积是指生产者发送的消息短时间内在Broker端大量堆积,无法被及时的消费 ,从而导致了别的业务功能无法正常使用。     首先要看是什么问题导致了消息堆积,是生产者生产了过多的消息还是消费者消费效率不足导致的。然后看看消费速度是否正常,正常的话,可以通过扩容,上线更多的Consumer临时解决消息堆积问题。在扩容 Consumer 的实例数量的同时, 必须同步扩容topic中的分区(也叫队列)数量,确保 Consumer 的实例数和分区数量是相等的。(因为对于消费者来说,在每个分区上实际上只能支持单线程消费)。假如还是没有办法解决,那么只能通过将系统进行降级,关闭一些不重要的业务,减少生产方发送的数据量,最低限度的让系统的热卖业务还能正常运转。

        如果Consumer和Queue不对等,上线了多台在短时间内无法消费完堆积的消息怎么办?

(1)准备一个临时的topic;(2)queue的数量是堆积的几倍; (3)queue分布到多态broker中; (4)上线一台Consumer做消息消费的搬运工,负责把topic中的消息挪到新的topic中,不做业务逻辑处理,只是挪过去; (5)上线n台Consumer同时去消费临时topic的数据; (6)改bug  (7)恢复之前的Consumer,继续消费之前的topic。

         堆积时间过长消息超时了?

        RocketMQ中的消息只有在commitLog被删除后的时候才会消失,不会超时。也就是说未被消费的消息不会存在超时删除的情况。

        堆积的消息会不会进死信队列?

        不会,消息在消费时候后会进入重试队列,有十八个等级,重试16次(默认从三级开始)之后才会进入死信队列。

RocketMQ为什么自研的nameserver而不用zk(zookper)?

        (1)RocketMQ只需要一个轻量级的维护元数据信息的组件,引入zk的话增加维护成本还强依靠另一个中间件了。

        (2)RocketMQ追求的是AP,而不是CP,也就是需要高可用。

                zk是CP,因为zk节点间通过zap协议有数据据共享,每个节点数据会不一致,但是zk集群当挂了一般以上的节点就没法使用了。

                namerserver是AP,节点间不通信,这样会导致节点间数据信息会发生短暂的不一致,但是每个broker都会定时向nameserver上报路由信息和心跳。当broker下线了,namerserver也会延迟30S才知道,而不会通知客户端(生产者和消费者),只能靠客户端自己来拉,rocketMQ是靠消息重试机制解决这个问题的,所以最终一致性。但nameserver集群值要有一个节点就可用。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020863.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号