RocketMQ------看这一篇就够了

RocketMq详解:一、RocketMQ 介绍及基本概念 Name Server和ZooKeeper的作用大致是相同的,从宏观上来看,Name Server做的东西很少,就是保存一些运行数据,Name Server之间不互连,这就需要broker端连接所有的Name Server,运行数据的改动要发送到每一个Name Server来保证运行数据的一致性(这个一致性确实有点弱),这样就变成了Name Server很轻量级,但是broker端就要做更多的东西了。这种方式优点是数据与服务都没有单点问题,Master 宕机时消息无延迟,服务与数据的可用性非常高。 阅读详情

一、RocketMQ 是什么?

3.3 消息过滤

RocketMQ的消费者可以根据Tag进行消息过滤,也支持自定义属性过滤。消息过滤目前是在Broker端实现的,优点是减少了对于Consumer无用消息的网络传输,缺点是增加了Broker的负担、而且实现相对复杂。

3.4 消息可靠性

RocketMQ支持消息的高可靠,影响消息可靠性的几种情况:

1、2、3、4 四种情况都属于硬件资源可立即恢复情况,RocketMQ在这四种情况下能保证消息不丢,或者丢失少量数据(依赖刷盘方式是同步还是异步)。5、6属于单点故障,且无法恢复,一旦发生,在此单点上的消息全部丢失。RocketMQ在这两种情况下,通过异步复制,可保证99%的消息不丢,但是仍然会有极少量的消息可能丢失。通过同步双写技术可以完全避免单点,同步双写势必会影响性能,适合对消息可靠性要求极高的场合,例如与Money相关的应用。注:RocketMQ从3.0版本开始支持同步双写。

3.5 至少一次

至少一次(At least Once)指每个消息必须投递一次。Consumer先Pull消息到本地,消费完成后,才向服务器返回ack,如果没有消费一定不会ack消息,所以RocketMQ可以很好的支持此特性。

3.6 回溯消费

回溯消费是指Consumer已经消费成功的消息,由于业务上需求需要重新消费,要支持此功能,Broker在向Consumer投递成功消息后,消息仍然需要保留。并且重新消费一般是按照时间维度,例如由于Consumer系统故障,恢复后需要重新消费1小时前的数据,那么Broker要提供一种机制,可以按照时间维度来回退消费进度。RocketMQ支持按照时间回溯消费,时间维度精确到毫秒。

3.7 事务消息

RocketMQ事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。RocketMQ的事务消息提供类似X/Open XA的分布事务功能,通过事务消息能达到分布式事务的最终一致。

3.8 定时消息

定时消息(延迟队列)是指消息发送到broker后,不会立即被消费,等待特定时间投递给真正的topic。broker有配置项messageDelayLevel,默认值为“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”,18个level。可以配置自定义messageDelayLevel。注意,messageDelayLevel是broker的属性,不属于某个topic。发消息时,设置delayLevel等级即可:msg.setDelayLevel(level)。level有以下三种情况:

定时消息会暂存在名为SCHEDULE_TOPIC_XXXX的topic中,并根据delayTimeLevel存入特定的queue,queueId = delayTimeLevel – 1,即一个queue只存相同延迟的消息,保证具有相同发送延迟的消息能够顺序消费。broker会调度地消费SCHEDULE_TOPIC_XXXX,将消息写入真实的topic。需要注意的是,定时消息会在第一次写入和调度写入真实topic时都会计数,因此发送数量、tps都会变高。

3.9 消息重试

Consumer消费消息失败后,要提供一种重试机制,令消息再消费一次。Consumer消费消息失败通常可以认为有以下几种情况:

RocketMQ会为每个消费组都设置一个Topic名称为“%RETRY%+consumerGroup”的重试队列(这里需要注意的是,这个Topic的重试队列是针对消费组,而不是针对每个Topic设置的),用于暂时保存因为各种异常而导致Consumer端无法消费的消息。考虑到异常恢复起来需要一些时间,会为重试队列设置多个重试级别,每个重试级别都有与之对应的重新投递延时,重试次数越多投递延时就越大。RocketMQ对于重试消息的处理是先保存至Topic名称为“SCHEDULE_TOPIC_XXXX”的延迟队列中,后台定时任务按照对应的时间进行Delay后重新保存至“%RETRY%+consumerGroup”的重试队列中。

3.10 消息重投

生产者在发送消息时,同步消息失败会重投,异步消息有重试,oneway没有任何保证。消息重投保证消息尽可能发送成功、不丢失,但可能会造成消息重复,消息重复在RocketMQ中是无法避免的问题。消息重复在一般情况下不会发生,当出现消息量大、网络抖动,消息重复就会是大概率事件。另外,生产者主动重发、consumer负载变化也会导致重复消息。如下方法可以设置消息重试策略:

3.11 流量控制

生产者流控,因为broker处理能力达到瓶颈;消费者流控,因为消费能力达到瓶颈。

生产者流控:

注意,生产者流控,不会尝试消息重投。

消费者流控:

3.12 死信队列

死信队列用于处理无法被正常消费的消息。当一条消息初次消费失败,消息队列会自动进行消息重试;达到最大重试次数后,若消费依然失败,则表明消费者在正常情况下无法正确地消费该消息,此时,消息队列 不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中。RocketMQ将这种正常情况下无法被消费的消息称为死信消息(Dead-Letter Message),将存储死信消息的特殊队列称为死信队列(Dead-Letter Queue)。在RocketMQ中,可以通过使用console控制台对死信队列中的消息进行重发来使得消费者实例再次进行消费。

四、RocketMQ 设计

消息存储

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

    二、RocketMQ基本概念

    2.1 消息模型(Message Model)

    RocketMQ主要由Producer、Broker、Consumer三部分组成,其中Producer负责生产消息,Consumer负责消费消息,Broker负责存储消息。Broker在实际部署过程中对应一台服务器,每个Broker可以存储多个Topic的消息,每个Topic的消息也可以分片存储于不同的Broker。MessageQueue用于存储消息的物理地址,每个Topic中的消息地址存储于多个MessageQueue中。ConsumerGroup由多个Consumer实例构成。

    2.2 消息生产者(Producer)

    负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。同步和异步方式均需要Broker返回确认信息,单向发送不需要。

    2.3 消息消费者(Consumer)

    负责消费消息,一般是后台系统负责异步消费。一个消息消费者会从Broker服务器拉取消息、并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费、推动式消费。

    2.4 主题(Topic)

    表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。

    2.5 代理服务器(Broker Server)

    消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。

    2.6 名字服务(Name Server)

    名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的BrokerIP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换。

    2.7 拉取式消费(Pull Consumer)

    Consumer消费的一种类型,应用通常主动调用Consumer的拉消息方法从Broker服务器拉消息、主动权由应用控制。一旦获取了批量消息,应用就会启动消费过程。

    2.8 推动式消费(Push Consumer)

    Consumer消费的一种类型,该模式下Broker收到数据后会主动推送给消费端,该消费模式一般实时性较高。

    2.9 生产者组(Producer Group)

    同一类Producer的集合,这类Producer发送同一类消息且发送逻辑一致。如果发送的是事务消息且原始生产者在发送之后崩溃,则Broker服务器会联系同一生产者组的其他生产者实例以提交或回溯消费。

    2.10 消费者组(Consumer Group)

    同一类Consumer的集合,这类Consumer通常消费同一类消息且消费逻辑一致。消费者组使得在消息消费方面,实现负载均衡和容错的目标变得非常容易。要注意的是,消费者组的消费者实例必须订阅完全相同的Topic。RocketMQ支持两种消息模式:集群消费(Clustering)和广播消费(Broadcasting)。

    2.11 集群消费(Clustering)

    集群消费模式下,相同Consumer Group的每个Consumer实例平均分摊消息。

    2.12 广播消费(Broadcasting)

    广播消费模式下,相同Consumer Group的每个Consumer实例都接收全量的消息。

    2.13 普通顺序消息(Normal Ordered Message)

    普通顺序消费模式下,消费者通过同一个消息队列(Topic分区,称作Message Queue)收到的消息是有顺序的,不同消息队列收到的消息则可能是无顺序的。

    2.14 严格顺序消息(Strictly Ordered Message)

    严格顺序消息模式下,消费者收到的所有消息均是有顺序的。

    2.15 消息(Message)

    消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题。RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Key。系统提供了通过Message ID和Key查询消息的功能。

    2.16 标签(Tag)

    为消息设置的标志,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性。

    三、RocketMQ特性(features)

    3.1 订阅与发布

    消息的发布是指某个生产者向某个topic发送消息;消息的订阅是指某个消费者关注了某个topic中带有某些tag的消息,进而从该topic消费数据。

    3.2 消息顺序

    消息有序指的是一类消息消费时,能按照发送的顺序来消费。例如:一个订单产生了三条消息分别是订单创建、订单付款、订单完成。消费时要按照这个顺序消费才能有意义,但是同时订单之间是可以并行消费的。RocketMQ可以严格的保证消息有序。顺序消息分为全局顺序消息与分区顺序消息,全局顺序是指某个Topic下的所有消息都要保证顺序;部分顺序消息只要保证每一组消息被顺序消费即可。

  • 全局顺序
  • 对于指定的一个Topic,所有消息按照严格的先入先出(FIFO)的顺序进行发布和消费。适用场景:性能要求不高,所有的消息严格按照FIFO 原则进行消息发布和消费的场景;
  • 分区顺序
  • 对于指定的一个Topic,所有消息根据 sharding key 进行区块分区。同一个分区内的消息按照严格的FIFO顺序进行发布和消费。Sharding key是顺序消息中用来区分不同分区的关键字段,和普通消息的Key是完全不同的概念。
  • 适用场景:性能要求高,以sharding key作为分区字段,在同一个区块中严格的按照FIFO原则进行消息发布和消费的场景。
  • Broker非正常关闭;
  • Broker异常Crash;
  • OS Crash;
  • 机器掉电,但是能立即恢复供电情况;
  • 机器无法开机(可能是cpu、主板、内存等关键设备损坏);
  • 磁盘设备损坏;
  • level == 0,消息为非延迟消息;
  • 1 <= level <= maxLevel,消息延迟特定时间,例如level == 1,延迟1s;
  • level > maxLevel,则leve l== maxLevel,例如level == 20,延迟2h。
  • 由于消息本身的原因,例如反序列化失败,消息数据本身无法处理(例如话费充值,当前消息的手机号被注销,无法充值)等。这种错误通常需要跳过这条消息,再消费其它消息,而这条失败的消息即使立刻重试消费,99%也不成功,所以最好提供一种定时重试机制,即过10秒后再重试。
  • 由于依赖的下游应用服务不可用,例如db连接不可用,外系统网络不可达等。遇到这种错误,即使跳过当前失败的消息,消费其他消息同样也会报错。这种情况建议应用sleep 30s,再消费下一条消息,这样可以减轻Broker重试消息的压力。
  • retryTimesWhenSendFailed:同步发送失败重投次数,默认为2,因此生产者会最多尝试发送retryTimesWhenSendFailed + 1次。不会选择上次失败的broker,尝试向其他broker发送,最大程度保证消息不丢。超过重投次数,抛出异常,由客户端保证消息不丢。当出现RemotingException、MQClientException和部分MQBrokerException时会重投。
  • retryTimesWhenSendAsyncFailed:异步发送失败重试次数,异步重试不会选择其他broker,仅在同一个broker上做重试,不保证消息不丢。
  • retryAnotherBrokerWhenNotStoreOK:消息刷盘(主或备)超时或slave不可用(返回状态非SEND_OK),是否尝试发送到其他broker,默认false。十分重要消息可以开启。
  • commitLog文件被锁时间超过osPageCacheBusyTimeOutMills时,参数默认为1000ms,返回流控。
  • 如果开启:
  • transientStorePoolEnable == true
  • 并且broker为异步刷盘的主机,且transientStorePool中资源不足,拒绝当前send请求,返回流控。
  • broker每隔10ms检查send请求队列头部请求的等待时间,如果超过waitTimeMillsInSendQueue,默认200ms,拒绝当前send请求,返回流控。
  • broker通过拒绝send 请求方式实现流量控制。
  • 消费者本地缓存消息数超过pullThresholdForQueue时,默认1000。
  • 消费者本地缓存消息大小超过pullThresholdSizeForQueue时,默认100MB。
  • 消费者本地缓存消息跨度超过consumeConcurrentlyMaxSpan时,默认2000。
  • 消费者流控的结果是降低拉取频率。

消息存储是RocketMQ中最为复杂和最为重要的一部分,接下来分别从RocketMQ的消息存储整体架构、RocketMQ中两种不同的刷盘方式来展开叙述。

消息存储整体架构

消息存储架构图中最重要的三个跟消息存储相关的文件构成

CommitLog 消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容不是定长的。单个文件大小默认1G, 文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件 ConsumeQueue 消息消费队列,引入的目的主要是提高消息消费的性能,由于RocketMQ是基于主题topic的订阅模式,消息消费是针对主题进行的,如果要遍历commitlog文件中根据topic检索消息是非常低效的。Consumer即可根据ConsumeQueue来查找待消费的消息。 其中,ConsumeQueue(逻辑消费队列)作为消费消息的索引,保存了指定Topic下的队列消息在CommitLog中的起始物理偏移量offset,消息大小size和消息Tag的HashCode值。consumequeue文件可以看成是基于topic的commitlog索引文件,故consumequeue文件夹的组织方式如下:topic/queue/file三层组织结构,具体存储路径为:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。

在RocketMQ的消息存储整体架构图中可以看出,RocketMQ采用的是混合型的存储结构,即为Broker单个实例下所有的队列共用一个日志数据文件(即为CommitLog)来存储。RocketMQ的混合型存储结构(多个Topic的消息实体内容都存储于一个CommitLog中)针对Producer和Consumer分别采用了数据和索引部分相分离的存储结构,Producer发送消息至Broker端,然后Broker端使用同步或者异步的方式对消息刷盘持久化,保存至CommitLog中。只要消息被刷盘持久化至磁盘文件CommitLog中,那么Producer发送的消息就不会丢失。正因为如此,Consumer也就肯定有机会去消费这条消息。当无法拉取到消息后,可以等下一次消息拉取,同时服务端也支持长轮询模式,如果一个消息拉取请求未拉取到消息,Broker允许等待30s的时间,只要这段时间内有新消息到达,将直接返回给消费端。这里,RocketMQ的具体做法是,使用Broker端的后台服务线程—ReputMessageService不停地分发请求并异步构建ConsumeQueue(逻辑消费队列)和IndexFile(索引文件)数据。

消息刷盘

五、RocketMQ 技术架构

  • 同样consumequeue文件采取定长设计,每一个条目共20个字节,分别为8字节的commitlog物理偏移量、4字节的消息长度、8字节tag hashcode,单个文件由30W个条目组成,可以像数组一样随机访问每一个条目,每个ConsumeQueue文件大小约5.72M;
  • IndexFile
  • IndexFile(索引文件)提供了一种可以通过key或时间区间来查询消息的方法。Index文件的存储位置是:{fileName},文件名fileName是以创建时的时间戳命名的,固定的单个IndexFile文件大小约为400M,一个IndexFile可以保存 2000W个索引,IndexFile的底层存储设计为在文件系统中实现HashMap结构,故rocketmq的索引文件其底层实现为hash索引。
  • 同步刷盘
  • 只有在消息真正持久化至磁盘后RocketMQ的Broker端才会真正返回给Producer端一个成功的ACK响应。同步刷盘对MQ消息可靠性来说是一种不错的保障,但是性能上会有较大影响,一般适用于金融业务应用该模式较多。
  • 异步刷盘
  • 能够充分利用OS的PageCache的优势,只要消息写入PageCache即可将成功的ACK返回给Producer端。消息刷盘采用后台异步线程提交的方式进行,降低了读写延迟,提高了MQ的性能和吞吐量。

RocketMQ架构上主要分为四部分,如上图所示:

  • Producer:
  • 消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
  • NameServer:
  • NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。
  • 主要包括两个功能:Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费。NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。
  • Broker是向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer,Consumer仍然可以动态感知Broker的路由的信息。
  • BrokerServer:
  • Broker主要负责消息的存储、投递和查询以及服务高可用保证,为了实现这些功能,Broker包含了以下几个重要子模块。
  • Remoting Module:
  • 整个Broker的实体,负责处理来自clients端的请求。
  • Client Manager:
  • 负责管理客户端(Producer/Consumer)和维护Consumer的Topic订阅信息。
  • Store Service:
  • 提供方便简单的API接口处理消息存储到物理硬盘和查询功能。
  • HA Service:
  • 高可用服务,提供Master Broker 和 Slave Broker之间的数据同步功能。
  • Index Service:
  • 根据特定的Message key对投递到Broker的消息进行索引服务,以提供消息的快速查询。

六、RocketMQ 部署架构

RocketMQ 网络部署特点

  • NameServer是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。
  • Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave 的对应关系通过指定相同的BrokerName,不同的BrokerId 来定义,BrokerId为0表示Master,非0表示Slave。
  • Master也可以部署多个。每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。注意:当前RocketMQ版本在部署架构上支持一Master多Slave,但只有BrokerId=1的从服务器才会参与消息的读负载。
  • Producer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic 服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
  • Consumer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。
  • Consumer既可以从Master订阅消息,也可以从Slave订阅消息,消费者在向Master拉取消息时,Master服务器会根据拉取偏移量与最大偏移量的距离(判断是否读老消息,产生读I/O),以及从服务器是否可读等因素建议下一次是从Master还是Slave拉取。

结合部署架构图,描述集群工作流程:

  • 启动NameServer,NameServer起来后监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心。
  • Broker启动,跟所有的NameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有Topic信息。注册成功后,NameServer集群中就有Topic跟Broker的映射关系。
  • 收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic。
  • Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取当前发送的Topic存在哪些Broker上,轮询从队列列表中选择一个队列,然后与队列所在的Broker建立长连接从而向Broker发消息。
  • Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取当前订阅Topic存在哪些Broker上,然后直接跟Broker建立连接通道,开始消费消息。

七、RocketMQ 集群部署

7.1 集群模式

单Master模式

这种方式风险较大,一旦Broker重启或者宕机时,会导致整个服务不可用。不建议线上环境使用,可以用于本地测试。

  • 优点:本地开发测试,配置简单,同步刷盘消息不会丢失。
  • 缺点:不可靠,如果宕机会导致服务不可用。

多Master模式

一个集群无Slave,全是Master,例如2个Master或者3个Master,这种模式的优缺点如下:

  • 优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;
  • 缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会受到影响。

多Master多Slave模式(异步)

每个Master配置一个Slave,有多对Master-Slave,HA采用异步复制方式,主备有短暂消息延迟(毫秒级),这种模式的优缺点如下:

  • 优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,同时Master宕机后,消费者仍然可以从Slave消费,而且此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样;
  • 缺点:Master宕机,磁盘损坏情况下会丢失少量消息。

多Master多Slave模式(同步)

每个Master配置一个Slave,有多对Master-Slave,HA采用同步双写方式,即只有主备都写成功,才向应用返回成功,这种模式的优缺点如下:

  • 优点:数据与服务都无单点故障,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高;
  • 缺点:性能比异步复制模式略低(大约低10%左右),发送单个消息的RT会略高,且目前版本在主节点宕机后,备机不能自动切换为主机。

DLedger 集群模式

RocketMQ-on-DLedger Group 是指一组相同名称的 Broker,至少需要 3 个节点,通过 Raft 自动选举出一个 Leader,其余节点 作为 Follower,并在 Leader 和 Follower 之间复制数据以保证高可用。

RocketMQ-on-DLedger Group 能自动容灾切换,并保证数据一致。RocketMQ-on-DLedger Group 是可以水平扩展的,也即可以部署任意多个 RocketMQ-on-DLedger Group 同时对外提供服务。

  • 优点:多节点(至少三个)组成集群,其中一个为 Leader 节点,其余为 Follower 节点组成高可用,能够自动容灾切换。
  • 缺点:集群成本增加(同一个group最少新增一台机器)、RocketMQ4.5及以后版本才支持。

7.2 本地测试环境快速搭建(单Master模式)

环境准备

  1. jdk1.8+
  2. rocketmq-all-4.5.0-bin-release

安装步骤

1、解压 rocketmq-all-4.5.1-bin-release.zip 到指定目录,如下:

benchmark:基础测试脚本目录 / lib:运行依赖包

bin:命令运维脚本目录 / conf:配置目录

2、进入bin 目录下编辑 runserver.sh 和 runborker.sh 两个文件,调整一下namesrv和broker的启动的jvm内存参数。具体参数大小根据系统环境配置情况而定:

vim runserver.sh
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn512m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

vim runroker.sh
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn512m"  
ps:broker端本地环境不建议开启堆外内存

3、根据情况配置broker的一些参数

brokerClusterName = DefaultCluster
brokerName = broker-a
# 0表示master >0表示slave
brokerId = 0
# 几点开始删除文件
deleteWhen = 04
# 文件保留时间,默认48小时
fileReservedTime = 48
# Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole = ASYNC_MASTER
#刷盘方式
# ASYNC_FLUSH 异步刷盘
# SYNC_FLUSH 同步刷盘
flushDiskType = ASYNC_FLUSH

备注:
# 存储路径
storePathRootDir=xxx/store
# commitLog存储路径
storePathCommitLog=xxx/store/commitlog
# 消费队列存储路径
storePathConsumeQueue=xx/store/pathconsumequeue
# 消息索引存储路径
storePathIndex=xxx/store/pathindex
# checkpoint 文件存储
storeCheckpoint=xxx/store/checkpoint
# abort 文件存储
abortFile=xxx/store/abort

备注:

xxx 默认等于System.getProperty("user.home") +File.separator+"store" 更多其他配置: MessageStoreConfig、BrokerConfig源码类 根据实际情况配置存储路径,storePathCommitLog占用空间相对最大

4、启动rocketmq, 先启动 namesrv 再启动 broker

--后台启动namesrv  
nohup sh mqnamesrv &  
--后台启动broker  
export NAMESRV_ADDR=localhost:9876  
--如果你在brocker.conf文件中配置了namesrvAddr = localhost:9876就直接用下面的命令  
nohup sh mqbroker -c /xxx/rocketmq-all-4.5.1-bin-release/conf/broker.conf &  
--否则用这个命令  
nohup sh mqbroker -n localhost:9876 -c /xxx/rocketmq-all-4.5.1-bin-release/conf/

5、查看进程和日志看是否启动成功

jps -l  or 查看 namesrv.log 和 broker.log 日志

八、本地源码快速搭建调试

源码获取

https://github.com/apache/rocketmq/releases
该网址可下载source包,也可以fork仓库。

启动 RocketMQ Namesrv

参考NameServerInstanceTest的startup方法,编写main方法,demo如下:

public class NameServerInstanceTest {
    .....
      public static void main(String[] args) throws Exception {
        final NamesrvConfig namesrvConfig = new NamesrvConfig(); 
        final NettyServerConfig nettyServerConfig = new NettyServerConfig();
        nettyServerConfig.setListenPort(9876); //设置端口
        // 创建 NamesrvController,启动
        NamesrvController namesrvController = new NamesrvController(namesrvConfig, nettyServerConfig);
        namesrvController.initialize();
        namesrvController.start();
        Thread.sleep(Long.MAX_VALUE); //挂起
    }
}

备注:

运行main方法, 显示以下关键字说明启动成功

备注:

运行main方法, 发现日志中包含:Receive New Messages...即消费成功

九、总结

rocketMq作为低延迟、高并发、高可用、高可靠的分布式消息中间件,其详细知识点非常多,如需深入,建议源码入坑。

启动 RocketMQ Broker

参考BrokerControllerTest的testBrokerRestart方法,编写main方法,demo如下:

public class BrokerControllerTest {
    .....
 public static void main(String[] args) throws Exception {
        NettyServerConfig nettyServerConfig = new NettyServerConfig();
        nettyServerConfig.setListenPort(10911);
        BrokerConfig brokerConfig = new BrokerConfig();  // BrokerConfig 配置
        brokerConfig.setNamesrvAddr("127.0.0.1:9876"); // 配置nameServer地址
        MessageStoreConfig messageStoreConfig = new MessageStoreConfig();
        // 创建 BrokerController 对象,并启动
        BrokerController brokerController = new BrokerController(//
                brokerConfig,
                nettyServerConfig, 
                new NettyClientConfig(),
                messageStoreConfig);
        brokerController.initialize();
        brokerController.start();
        Thread.sleep(Long.MAX_VALUE); //挂起
    }
}

备注:

运行main方法,不报错即可,但是在:NameServerInstanceTest(nameServer)中,发现以下关键字日志,表明broker注册nameServer成功:new topic registered...等

启动 RocketMQ Producer

参考:org.apache.rocketmq.example.quickstart.Producer

public class Producer {

    public static void main(String[] args) throws MQClientException, InterruptedException, IOException {

        DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
        /*
         * Launch the instance.
         */
        producer.setNamesrvAddr("127.0.0.1:9876"); // 配置nameServer地址
        producer.start();

        for (int i = 0; i < 1; i++) { // i 可以随便配置
            try {

                /*
                 * Create a message instance, specifying topic, tag and message body.
                 */
                Message msg = new Message("abc" /* Topic */,
                    "TagA" /* Tag */,
                    ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
                );
//                msg.setDelayTimeLevel(10);
/*
* Call send message to deliver message to one of brokers.
*/
SendResult sendResult = producer.send(msg);

                System.out.printf("%s%n", sendResult);
            } catch (Exception e) {
                e.printStackTrace();
                Thread.sleep(1000);
            }
        }
        /*
         * Shut down once the producer instance is not longer in use.
         */
        producer.shutdown();
    }
}

备注:

运行main方法, 发现日志中包含:

SendResult [sendStatus=SEND_OK...即发送成功

启动 RocketMQ Consumer

参考:

org.apache.rocketmq.example.quickstart.Consumer

public class Consumer {

    public static void main(String[] args) throws InterruptedException, MQClientException {
        /*
         * Instantiate with specified consumer group name.
         */
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_1");

        /*
         * Specify name server addresses.
         * <p/>
         *
         * Alternatively, you may specify name server addresses via exporting environmental variable: NAMESRV_ADDR
         * <pre>
         * {@code
         * consumer.setNamesrvAddr("name-server1-ip:9876;name-server2-ip:9876");
         * }
         * </pre>
         */

        /*
         * Specify where to start in case the specified consumer group is a brand new one.
         */
        consumer.setNamesrvAddr("127.0.0.1:9876"); // 配置nameServer地址
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        /*
         * Subscribe one more more topics to consume.
         */
        consumer.subscribe("abc", "*");

        /*
         *  Register callback to execute on arrival of messages fetched from brokers.
         */
        consumer.registerMessageListener(new MessageListenerConcurrently() {

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                ConsumeConcurrentlyContext context) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        /*
         *  Launch the consumer instance.
         */
        consumer.start();

        System.out.printf("Consumer Started.%n");
    }
}

  • NettyEventExecutor service started
  • FileWatchService service started
RocketMQ控制台安装教程 RocketMQ安装教程一文中,详细探讨了如何搭建RocketMQ,这一节来搭建RocketMQ控制台,RocketMQ的可视化管理界面。 一、下载代码 # 方式一、git下载,执行如下命令 git clone https://github.com/apache/rocketmq-externals.git # 方式二、直接下载,访问如下地址即可 https://github.co... 阅读详情

相关推荐

RocketMQ详解(持续更新)

一、MQ阐述 简单图示 [注] 消息队列是一种"先进先出"的数据结构 不使用队列的情况下生产者与消费者之间是通过RPC交互的 应用场景 应用解耦 问题描述 系统的耦合性越高,容错性就越低,以电商应用为例,用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常 解耦含义 使用消息队列解耦,系统的耦合性就会...

Ferao的博客 6万+

RocketMQ 详解

RocketMQ 详解1. 基础概念2.RocketMQ 消费模式2.1 广播模式2.2 集群模式3. 基础架构3.1 Broker 的存储结构3.2 存储文件简介3.3 Consumer 端的负载均衡机制3.4 消息刷盘机制3.5 Mmap + pageCache3.5.1 传统IO 和 Mmap3.5.2 pageCache3.5.3 预映射机制 + 文件预热机制3.6 push/pull/pop3.7 Topic 分片3.8 查漏补缺3.8.1 消息的全局顺序和局部顺序3.8.2 零拷贝(Zero-c

weixin_44981707的博客 3万+

消息中间件-RocketMQ(基础、实战、源码、原理看这一篇就够了)

消息中间件和消息队列是同一个概念的两种名称,是分布式系统中的一个重要组件。举个例子:比如现在有一个商城系统使用的是微服务架构,其中有订单服务、库存服务、物流服务、积分服务。业务场景是如果下单了一个商品需要调用库存服务减库存、需要调用物流服务发送商品、需要调用积分服务添加响应的积分。通过RPC框架(也就是http请求)通过消息中间件消息中间件就是生产者只需要将需要处理的消息丢进来即可不需要等到消息执行完成的回调,然后其他服务再去监听消息,有消息来了就执行消息消息中间件的应用场景异步解耦。

m0_73311735的博客 3521

RocketMQ(看这一篇就够了)

RocketMQ是一个纯Java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里参考Kafka特点研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache的顶级开源项目,具有高性能、高可靠、高实时、分布式特点。应用场景RocketMQ在阿里集团也被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理,binglog分发等场景。所拥有的功能是一个队列模型的消息中间件,具有高性能、高可靠、高实时、分布式特点;Producer、Consumer、队列都可以分布式;

m0_74436895的博客 3573

【微服务】微服务集成Rocketmq,一篇文章就够了

我们都知道,不管是单体项目也好,微服务分布式项目也罢,都逃不脱mq的使用,那么什么是mq?MQ的应用场景有哪些?消息消费有哪些要注意的细节问题?微服务中如何接入MQ?相信大家都会有或多或少的困惑点和不懂点,那这篇文章就带领大家了解Rocketmq-消息驱动。

热爱技术,享受生活 2万+

apm软件仿真+QGC地面站 环境搭建

本教程使用场景:apm软件仿真运行于虚拟机 ubuntu环境。qgc地面站位于windows 系统。两个环境在同一台电脑上。 一.apm仿真环境搭建 1.安装vm虚拟机及ubuntu 18。 2.ubuntu下 下载Ardupilot 飞控源码 并配置环境。 下载源码: git clone https://github.com/ArduPilot/ardupilot cd ardupilot git submodule update --init --recursive 配置所需运行的环境:

qthello 6111

学会RocketMQ这一篇就够了

RocketMQ简介 RocketMQ是由阿里捐赠给Apache的一款低延迟、高并发、高可用、高可靠的分布式消息中间件。经历 了淘宝双十一的洗礼。RocketMQ既可为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备 互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性。 官方文档: https://rocketmq.apache.org/docs/quick-start/ github中文主页:https://github.com/apache/rocketmq/tree/master/docs/c

yiqiu1959的博客 1411

synopsys工具安装系列(一)安装installer

synopsys为eda工具安装,提供了一个安装器,名叫installer。所以,首先要先安装installer这个工具,之后才能安装其他的eda工具。 首先从官网下载该installer工具。我这里下载的是5.2版本 下载之后,有如下安装文件。 将该安装包,拷贝到linux服务器中。 首先给SynopsysInstaller_v5.2.run赋予可执行权限。 chmod a+x SynopsysInstaller_...

weiqi7777的博客 8394

rocketmq面试,有这一篇就够了~~~

rocketmq高级面试题汇总

程序员ZZ的源码 1799

平面变压器PCB绕组设计实战:从原理到布局的工程考量

本文深入探讨了平面变压器PCB绕组设计的工程实践,从基础原理到布局优化,涵盖了电流密度、层间绝缘、绕组拓扑结构等关键参数。通过实战案例分享,解析了高频应用中的集肤效应、邻近效应等挑战,并提供了热管理和EMC优化的实用技巧,助力工程师在服务器电源、车载充电器等空间敏感场景实现高效设计。

weixin_42666036的博客 458

XGBoost原生接口和Sklearn接口参数详解

XGBoost原生接口和Sklearn接口参数详解

算法工程师 2656

RocketMq详解 读这一篇就够了

fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;mmap PageCache 或 DirectByteBufferReputMessageService (~1ms 异步分发)ReputMessageService (~1ms 异步分发)定位 → commitLogOffsetProducer 发送CommitLog 顺序写磁盘。

cmnetmerge的博客 381

rv1126如何切换720p和1080p

切换720p和1080p可以使用modetest,但是需要将这两种模式都添加到connector中去 添加一个新的mode到connector中去,其实内核中已经有相关接口了,需要做一些小改动。 1.不采用设备树的方式去配置,将720p和1080p的timing参数配置放在数组中。 2.这里的printer和设备树中的.compatible = "printer"一致。 3.将其添加到connector中去 static int panel_simple_get_fixed_modes(struct

weixin_42097108的博客 865

关于RocketMQ的基础API操作——这一篇就够了

关于RocketMQ的基础操作一、基础API操作1、 普通消息1.1、消息生产端1.2、消息消费端2、顺序消息2.1、消息生产端2.2、消息消费端3、广播消息3.1、消息生产端3.2、消息消费端4、延迟消息4.1、消息生产端4.2、消息消费端4.3、实现原理5、批量消息5.1、消息生产端——普通版5.2、 消息生产端——分割过大消息版5.3、消息消费端6、过滤消息6.1、消息生产端——Tag过滤6.2、消息消费端——Tag过滤6.3、消息生产端——SQL过滤6.4、消息消费端——SQL过滤7、事务 消息7.

持续Java学习中 2801

【头歌】链栈的基本操作及应用

另外,在算法的开始和结束时,栈都应该是空的,所以匹配到最后还要判断栈是否为空,若空,则说明匹配成功,返回1。其中表达式只包含三种括号,花括号{}、中括号[]、圆括号(),即它仅由 (、)、[、]、{、}六个字符组成。预期输出: 栈中元素依次为:12 47 5 8 6 92 45 63 75 38 4 29 弹出的栈顶元素 e=29 栈空否:0(1:空 0:否) 栈顶元素 e=4 栈的长度为11 清空栈后,栈空否:1(1:空 0:否)// 若栈不空,则用e返回S的栈顶元素,并返回OK;

qq_39977056的博客 4384

服务器搭建原神私服教程

项目的稳定版分支提供了编译好的服务端程序,但是博主觉得还是用dev版本的比较好。dev版本需要自己编译的,不要听到编译这两个字就头大,相反,这个服务端的编译相当简单。把文件中的两个IP地址127.0.0.1修改为你服务器的地址,修改完成后按 esc 输入 :wq。Mongodb作为服务端的数据库使用,我们这里安装最新版的Mongodb5。注意:如果想要使用最新版的服务端,必须安装>=17版本的java。tmux可以保证你关掉控制台的时候,程序依然继续运行。至此,服务端所需要的运行环境全部配置完成。

用最简单的方式说最重要的事!服务器、存储、云计 算、A智能的大数据产品、游戏开发技术。致力于广 大开发者、政企用户、各项机构等,构建云上世界提供全方位云计算解决方案。旨在打造差异化的开放式闭环生态系统帮助用户快速构建稳定、安全的云计算环境。 1万+

RocketMQ部署运维,看这一篇就够了

运维管理 1 集群搭建 1.1 单Master模式 这种方式风险较大,一旦Broker重启或者宕机时,会导致整个服务不可用。不建议线上环境使用,可以用于本地测试。 1)启动 NameServer ### 首先启动Name Server $ nohup sh mqnamesrv & ### 验证Name Server 是否启动成功 $ tail -f ~/logs/rocketmq...

cjdjcdj的博客 638

SSD |(二)SSD主控

控制器作为一个片上系统,处理来自用户端的命令并负责管理闪存颗粒。

知识库搭建ing 1966

实战:RocketMQ削峰,这一篇就够了

文章目录前言rocketmq-spring-boot-starter 用法简介业务案例环境配置添加maven依赖application.yml配置点赞接口PraiseListener:点赞消息消费者上线了但消费效率预估失误如何动态更改消费效率 ?如何使用RocketMQ批量消费 ?附本文相关信息 前言 MQ的主要特点为解耦、异步、削峰,该文章主要记录与分享个人在实际项目中的RocketMQ削峰用法...

z28126308的专栏 7689

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

实战:RocketMQ 削峰,这一篇就够了

点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 8:55 更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2020 超神之路,很肝~...

芋艿V 600

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

rocketmq还要eventbus_EventBus源码详解,看这一篇就够了

之前写过一篇关于EventBus的文章,大家的反馈还不错(EventBus3.0使用详解),如果你还没有使用过EventBus,可以去那篇文章看看。当时刚接触EventBus,对它的理解也仅仅是停留在表面,写那篇文章也是记录下EventBus的一个简单的使用的过程,而如今随着EventBus在项目中的多次运用,个人感觉,会用一个框架跟知道它的原理这是两码事,所以下定决心写这篇文章来帮助自己更好的理...

weixin_34966468的博客 554

想了解 Kafka, RabbitMQ, ZeroMQ, RocketMQ, ActiveMQ 之间的差异?这一篇文章就够了!

本文将从,Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ 17 个方面综合对比作为消息队列使用时的差异。 一、资料文档 Kafka:中。有kafka作者自己写的书,网上资料也有一些。 rabbitmq:多。有一些不错的书,网上资料多。 zeromq:少。没有专门写zeromq的书,网上的资料多是一些代码的实现和简单介绍。 rocketmq:少。没有专门...

码农Robin的博客 1648

Android面试从新手到架构师,一篇解析就够(2),rocketmq原理面试

============================================== volatile 关键字 只能用来修饰变量,适用修饰可能被多线程同时访问的变量 相当于轻量级的 synchronized,volatitle 能保证有序性(禁用指令重排序)、可见性 变量位于主内存中,每个线程还有自己的工作内存,变量在自己线程的工作内存中有份拷贝,线程直接操作的是这个拷贝 被 volatile 修饰的变量改变后会立即同步到主内存,保持变量的可见性 双重检查单例,为什么要加 vio

m0_60607609的博客 613

想了解Kafka,RabbitMQ,ZeroMQ,RocketMQ,ActiveMQ之间的差异?这一篇文章就够了!

本文将从,Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ 17 个方面综合对比作为消息队列使用时的差异。 内容目录 一、资料文档 二、开发语言 三、支持的协议 四、消息存储 五、消息事务 六、负载均衡 七、集群方式 八、管理界面 九、可用性 十、消息重复 十一、吞吐量TPS 十二、订阅形式和消息分发 十三、顺序消息 十四、消息确认 十...

qq_42575330的博客 212
上一篇: HTTP1.0、HTTP1.1、HTTP2.0的关系和区别
下一篇: valid注解
杜引强
博客等级 码龄13年 806粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值