基于源码搭建运行 RocketMQ 主从架构

news2024/11/20 8:39:49

前言

上一篇 基于 IDEA 搭建 RocketMQ-4.6 源码环境 我们搭建并跑通了 rocketmq 的源码环境 .

本文我们紧接上文, 继续基于源码搭建并运行 broker 主从架构.

  • 1 个 NameServer 节点 (与前文一样)
  • 2 个 Broker 节点, 一个作为 Master, 一个作为 Slave
  • 1 个 Producer 生产者 (与前文一样)
  • 1 个 Consumer 消费者 (与前文一样)

broker 主从架构只需要修改 broker.conf 文件即可, 其他地方与单节点没有差异.

第四章节主要是描述搭建过程中遇到的问题, 以及处理过程, 可以选择性跳过.

正文

一、回顾 RocketMQ 的主从部署架构

在这里插入图片描述

  • Broker 部署相对复杂,Broker 分为 Master 与 Slave

  • master 与 slave 之间同步数据既支持同步(sync), 也支持异步(async)

  • 一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,

  • Master 与 Slave 的对应关系通过指定相同的 BrokerName,

  • 不同的BrokerId 来定义,BrokerId为0表示Master,非0表示Slave。

  • Master也可以部署多个。

  • 每个 Broker 与 NameServer 集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。

    注意:当前RocketMQ版本在部署架构上支持一Master多Slave,但只有BrokerId=1的从服务器才会参与消息的读负载。

二、官方提供的 两主两从 架构

RocketMQ 官方提供了 两主两从 (异步 和 同步)的配置文件( rocketmq/distribution/conf/ ).

在这里插入图片描述

三、基于官网的配置搭建一主一从架构

我们可以从官网提供的异步模式中提取两个现成的配置文件, 比如 broker-a.confbroker-a-s.conf 文件, 将他们放在 rocketmq/conf/ 目录下

在这里插入图片描述

然后启动 broker 程序时, 需要指定对应的配置文件.

在这里插入图片描述

这里有个细节:

当我们把两个 broker 节点部署在两台不同的机器时, 可以直接采用官网提供的配置, 无需进行修改.

但是我们是在同一台机器, 启动两个 broker 节点. 那么我们就需要注意 默认的配置文件 中缺少了包括但不限于以下配置:

  • broker 节点的监听端口(如果不配置, 那么启动第二个节点就会提示端口已占用.)

    关于端口的配置, 这里还有另外一个大坑!!! 后面详细说

  • broker 保存数据的存储路径.(如果不配置, 那么两个节点的存储路径会冲突.)

    java.lang.RuntimeException: Lock failed,MQ already started
    	at org.apache.rocketmq.store.DefaultMessageStore.start(DefaultMessageStore.java:222)
    	at org.apache.rocketmq.broker.BrokerController.start(BrokerController.java:853)
    	at org.apache.rocketmq.broker.BrokerStartup.start(BrokerStartup.java:64)
    	at org.apache.rocketmq.broker.BrokerStartup.main(BrokerStartup.java:58)
    

    关于以上两点, 我们放在第四章节详细说.

四、搭建过程中遇到的问题

4.1 问题一

一开始, 我直接把官方提供的两个配置文件, 直接丢到了 rocketmq/conf 目录下, 然后启动 namesrv 成功, 启动 broker-a 成功.

当启动 broker-a-s 时, 提示如下:

在这里插入图片描述

这个错误提示大致意思是: broker-a-s 节点已经启动了. 说明他跟 broker-a 哪里冲突了, 就类似于端口占用冲突一样.

然后根据错误提示的代码入口(org.apache.rocketmq.store.DefaultMessageStore#start), 开始打断点调试:

在这里插入图片描述

从图中可以看出, lockFile 对象中有个 path 字段, 它指向的是 /Users/用户名/store/lock 文件.

此时我的猜想如下:

broker 节点启动时, 会在指定目录(/Users/用户名/store/)写入一个名字为 lock 的文件, 表示 broker 节点已经启动了.(这只是猜想, 实际情况虽然不一定如此, 但是不会偏离很远.)

然后我们查看 broker-a.conf 的配置文件, 文件中并没有 哪个配置 指定了 /Users/用户名/store/lock 这个路径

继续跟踪源码 org.apache.rocketmq.store.DefaultMessageStore#DefaultMessageStore, 看看 lockFile 是在哪里初始化的(也就是 path 属性是什么时候赋值的).

File file = new File(StorePathConfigHelper.getLockFile(messageStoreConfig.getStorePathRootDir()));
MappedFile.ensureDirOK(file.getParent());
lockFile = new RandomAccessFile(file, "rw");
public class MessageStoreConfig {
    // 用户目录 + "/" + store
    private String storePathRootDir = System.getProperty("user.home") + File.separator + "store";
  
}

由上可知, storePathRootDir 字段默认存储的就是 /Users/用户名/store/, 但是至此, 我们还不知道怎么配置这个属性.

所以我们需要借助 IDEA 找到 MessageStoreConfig 是在哪里实例化的.

org.apache.rocketmq.broker.BrokerStartup#createBrokerController

在这里插入图片描述

从上图可知, broker 启动时, 会读取命令行参数. 然后把参数重新赋值给 messageStoreConfig 对象中的字段, 此时立马就想到, 我们程序运行时通过 -c 指定 broker.conf 配置文件.

在这里插入图片描述

因此可以得知, 我们可以把 storePathRootDir 属性配置到 broker-a-s.conf 文件中, 而 broker-a.conf 修改与否都不影响.

storePathRootDir = /Users/xxxx/store-a-s 

4.2 问题二

问题一 解决后, 我们继续启动 broker-a-s 节点, 就会引发如下问题:

在这里插入图片描述

当有了上面的经验后, 立马就想到, 因为 broker-a-s 节点没有配置监听端口, 所以导致它跟 broker-a 节点的 端口冲突 了.

所以, 我们只需要找到对应的配置项是哪个就行.

继续 debug 源码

org.apache.rocketmq.broker.BrokerStartup#createBrokerController

nettyServerConfig.setListenPort(10911);
if (commandLine.hasOption('c')) {
   String file = commandLine.getOptionValue('c');
   if (file != null) {
	// 把 broker-a-s.conf 的配置覆盖掉 nettyServerConfig 中原有的配置
      MixAll.properties2Object(properties, nettyServerConfig);             
               
   }
}

默认 netty server 的端口是 10911, 如果 broker-a-s.conf 中配置了 listenPort 属性, 那么会进行覆盖.

所以, 直接在 broker-a-s.conf 中重新定义一个监听端口即可:

listenPort = 10912 // 默认端口 + 1

继续启动程序, 依然提示端口占用的报错. 下意识以为 10912 端口也被哪个应用占用了, 然后继续配置成 10913. 直到配置成 10915 才运行成功 (这里说来也巧, 当时比较头铁, 一直在尝试端口 + 1.)

此时当两个 broker 节点都启动后, 我通过 端口查看命令, 去验证 10911 - 10915 端口是否真的被占用了.

结果如下:

可以看到除了 10911 - 10915 之外, 我还额外标注了几个端口(这是在我明白问题所在后总结的, 可以先忽略).

=============broker-a

10909 (被占用)(pid:77589)

10910

10911 (被占用)(pid:77589)

10912(被占用)(pid:77589)

==============broker-a-s

10913(被占用)(pid:93439)

10914

10915(被占用)(pid:93439)

10916(被占用)(pid:93439)

10917

此时得出的结论是, broker-a 启动时, 它不仅打开了一个 netty server 的 10911(listenPort) 端口, 还打开了一个 10912 (listenPort + 1 )的端口(作用未知.)

既然如此, 那为什么启动 broker-a-s 时, 10914不行呢?

讲道理,如果配置 netty server 占用端口是 10194, 那个也只会再额外占用一个 10915 端口. (启动前已验证 10914, 10915 未被占用) . 理论上不影响 broker-a-s 不会因为端口占用而运行不起来的.

继续追踪源码

org.apache.rocketmq.broker.BrokerStartup#createBrokerController

如果一行行分析源码很浪费时间, 于是我们可以先大胆猜想(更多是经验而言), 10912 端口可能是根据 10911 计算 来的,

于是再次借助 IDEA 的分析工具, 查看代码的使用情况.

在这里插入图片描述

从上面可以看出, 有两个地方是基于 listenPort 属性计算的, 于是有了如下推论:

已知 broker-a 至少占用了 10911(listenPort), 10912 两个端口,

当 broker-a-s 用 10914 当 listenPort 时, 10915 自然也会被占用, 同时 listenPort - 2= 10912 也要被占用.

但是 10912 已经被 broker-a 占用了, 于是 IDEA 控制台抛出了 “端口占用的异常信息”.

于是, 我们再回过头来看, broker-a(10911) , broker-a-s (10915) 都启动时的端口占用情况, 就很合理了.

=============broker-a

10909 (listenPort-2)(被占用)(pid:77589)

10910

10911 (listenPort)(被占用) (pid:77589)

10912(listenPort+1)(被占用) (pid:77589)

==============broker-a-s

10913(listenPort-2)(被占用) (pid:93439)

10914

10915(listenPort)(被占用) (pid:93439)

10916(listenPort+1)(被占用)(pid:93439)

10917

到此为止, 我们终于把 问题 二 分析明白了, 至于除了 listenPort 之外的端口被哪些功能占用了, 并非本文的重点, 会放在后面的文章再去分析.

五、单机一主一从的最终配置

官网提供的配置

在这里插入图片描述

修改后的配置

broker-a.conf

brokerClusterName = DefaultCluster
brokerName = broker-a // Master 与 Slave 的对应关系通过指定相同的 BrokerName,
brokerId = 0 // 不同的 BrokerId 来定义,BrokerId 为 0 表示 Master,非 0 表示 Slave。
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER // 角色
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = true
storePathRootDir = /Users/xxxx/store-a // 存储路径
namesrvAddr = localhost:9876 // namesrv 的地址
listenPort = 10911 // broker 节点监听端口, 这个很重要

Broker-a-s.conf

brokerClusterName = DefaultCluster
brokerName = broker-a // Master 与 Slave 的对应关系通过指定相同的 BrokerName
brokerId = 1 // 不同的 BrokerId 来定义,BrokerId 为 0 表示 Master,非 0 表示 Slave。
deleteWhen = 04
fileReservedTime = 48
brokerRole = SLAVE // 角色
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = true
namesrvAddr = localhost:9876 // namesrv 的地址
storePathRootDir = /Users/xxxx/store-a-s // 存储路径
listenPort = 10921 // broker 节点监听端口, 这个很重要

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10855.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

元强化学习 论文理解 MAESN

论文理解 MAESN主要思想具体实现元学习框架带有隐层状态的策略元学习更新小结主要思想 这篇文章主要关注于如何加强对于新任务的探索性。 动机: 以往探索策略在很大程度上是任务无关的,因为它们旨在提供良好的探索,而不利用任务本身的特定结…

MySQL 经验集总结(更新ing)

文章目录1. 函数使用方法1.1 时间差函数-timestampdiff()1.2 datediff()函数1.3 date_format()函数-日期格式化1.4 substring()函数-截取字符串1.4.1 两个参数1.4.2 三个参数1. 函数使用方法 1.1 时间差函数-timestampdiff() 语法: timestampdiff(unit…

一种能把前端恶意代码关在“笼子”里的技术方案

日新月异的新一代信息化技术使企业信息技术都发生了翻天覆地的变化,推动企业App迈向了“智慧化”“数字化”。 在企业应用数字化转型的推动过程中,数据集中共享、IT(信息技术)/0T(操作技术)融合、物联网终…

RDD调用机制、数据流在RDD中的流通

问题 一直很疑惑spark中数据的流向是如何的,网上的文章基本上都是在讲述RDD的基本概念,看来看去都是些RDD直接相互依赖、Spark构造DAG、RDD计算只能由行动算子触发等一些基础概念,没有解开我的疑惑,因此自己点击源码查看&#xf…

《InnoDB引擎》 Master Thread、IO Thread、Purge Thread

后台线程 后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB能恢复到正常运行的状态。 InnoDB存储引擎是多线程的模型,因此…

用键盘传输小数据,破除解决多层远程访问或防火墙限制不能粘贴复制的问题

经常在项目上遇到这样的问题,由于vpn或者防火墙限制远程连接到服务器时不能进行粘贴复制文本。本机改好的代码还需要在远程机上在敲一遍,并且不能传输文件,每次传输东西都要找管理员给传输文件很麻烦,所以想到了这样一个又蠢又灵活…

ME60单板加载故障维护经验

ME60单板加载故障维护经验 加载是设备管理中重要的模块。它完成系统软件和逻辑软件从主控板的 CFcard下载到接口板或者交换网板的存储区域。接口板或者交换网板的存储区域有以下三种: 1 单板 CFcard存储区域 2 单板 bootrom存储区域 3 单板逻辑芯片内部存储区…

数字先锋 | 教育资源乘云而来!46万城乡学子共享名师课堂

城乡学生同上“一堂课”,是一种怎样的体验?在淄博市张店区重庆路小学的教室里,正在进行着这样一节特殊的数学课。 数学老师演示着手里的教具,将抽象的教材讲解得生动精彩,班级内的同学听得聚精会神。黑板上方的一块屏幕…

聚水潭对接金蝶云星空数据方案

01 系统说明: 聚水潭:是由上海聚水潭网络科技有限公司基于SaaS模式开发的商家ERP软件系统,公司创始团队聚集了一群来自阿里、麦包包等知名企业的技术、仓管、市场营销精英,具有近二十年传统及电商企业的ERP实践经验。秉承互联网开…

软件开发 23个设计模式收集

从基础的角度看,设计模式是研究类本身或者类与类之间的协作模式,是进行抽象归纳的一个很好的速成思路。后面阅读设计模式后,为了加深理解,对相关图片进行了描绘和微调。 从技术的角度已经有很多好的总结,本文会换一种角…

基于docker部署redis多主多从集群

在docker中部署redis多主多从集群,准备部署三对一主一从服务,共6个 首先获取镜像 这里使用的是6.0.8版本 docker pull redis:6.0.8 启动六个容器 docker run -d --name redis-node1 --net host --privilegedtrue -v /usr/local/redis/node1:/data red…

Vue实现点击按钮或者图标可编辑输入框

博主介绍 📢点击下列内容可跳转对应的界面,查看更多精彩内容! 🍎主页:水香木鱼 🍍专栏:后台管理系统 文章目录 简介:这是一篇有关【Vue - 实现点击按钮(笔图标&#xff…

VS五子棋大战

本项目里面只是浅述了一下基本实现步骤,很多细节的地方都在注释中标注了,如需完整代码请去博主码云哦。zqy (zhang-qinyang1) - Gitee.com 目录 一、用到的关键技术点 二、主要模块 1.使用mybatis操作连接数据库 1.1修改spring配置文件 1.2创建实体…

json.converter

爬虫组件分析目录概述需求:设计思路实现思路分析1.ActivityProcessor2.AssociationJsonConverter3.BaseBpmnJsonConverter4.BoundaryEventJsonConverter5.BpmnJsonConverter拓展实现参考资料和推荐阅读Survive by day and develop by night. talk for import biz , …

【出人意料】一种基于Vue2监听器(watch)和定时器(setInterval)的轨迹播放方法实现方案

1、需求 数据库中有设备的经纬度记录,前端需要实现从数据库中取到数据后在地图上显示轨迹,显示轨迹的方式就是一个一个点地有序显示。点与点之间用线段连接,最终构成一条轨迹线。 2、场景过程 前端定义一个播放暂停按钮;点击播…

【Flutter】【package】auto_size_text 文字自动适配大小

文章目录前言一、auto_size_text 是什么?二、使用1.简单的使用2.参数说明3.group4.rich text总结前言 auto_size_text :https://pub.flutter-io.cn/packages/auto_size_text 一、auto_size_text 是什么? 第三方的插件,能够自动适…

DDD的落地,需要基础设施的大力支持

1. 概览 对于复杂业务,DDD 绝对是一把神器,由于它过于复杂,很多人望而却步。因为太过严谨,形成了很多设计模式、规范化流程,这些爆炸的信息已经成为 DDD 落地的重大阻力。 但,如果我们将这些规范化的流程…

1.4_28 Axure RP 9 for mac 高保真原型图 - 案例27【中继器 - 后台管理系统5】功能-弹窗修改数据

相关链接 目录Axure中文学习网AxureShopAxureShop-QA 案例目标1. 了解使用中继器,弹窗修改数据的实现方式 一、成品效果 Axure Cloud 案例27【中继器 - 后台管理系统5】功能-弹窗修改数据 版本更新一、修改功能   1.1 点击修改按钮,标记该条数据&am…

国产软件Bigemap与国产在线地图源<星图地球数据云>推动国内新GIS应用

自星图地球数据云(GEOVIS Earth Datacloud)图源成为国产基础软件Bigemap的在线地图数据服务平台之一以来,其日均地图瓦片请求调用量目前已经超过2亿。 “星图地球数据云"是中科星图(股票代码[688568])旗下子公司——星图地球倾力打造的在线时空数据云服务平台…

基于约束的装配设计【CadQuery】

本教程介绍在CadQuery中如何使用装配约束功能来构建逼真的模型,我们将组装一个由 20x20 V 型槽型材制成的门组件。 1、定义参数 我们希望从定义模型参数开始,以便以后可以轻松更改尺寸: import cadquery as cq# Parameters H 400 W 200…