RocketMQ安装以及源码启动

        RocketMQ是一款消息中间件,在我们项目中主要是使用它来进行异步处理业务以及进行解耦,当然还可以用它实现其他业务需求比如流削峰等等,它提供的功能特别多,比如延迟消费、定时消费、消息重试、顺序消费等等。它的整体设计是追求简单和性能高效。

本篇作为开始学习RocketMq的开篇,在本篇主要完成两部分讲解:

1.安装RocketMq以及RocketMq-Console

2.获取源码

安装RocketMQ以及RocketMQ-Console

1.下载RocketMQ压缩包

wget https://archive.apache.org/dist/rocketmq/4.7.1/rocketmq-all-4.7.1-bin-release.zip
//解压
unzip rocketmq-all-4.7.1-bin-release.zip

2.启动NameServer

进入解压目录的bin目录下,修改配置NameServer JVM参数,因为我本身给虚拟机分配的内存比较小,而nameserver默认是占4g,所以我把它改小了。

vim runserver.sh
将:
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
改为:
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

启动NameServer:

nohup ./mqnamesrv &

查看是否启动成功:

tail ~/logs/rocketmqlogs//namesrv.log
//结果 看到如下结果表示已经启动成功
2023-05-03 19:45:16 INFO main - tls.client.keyPassword = null
2023-05-03 19:45:16 INFO main - tls.client.certPath = null
2023-05-03 19:45:16 INFO main - tls.client.authServer = false
2023-05-03 19:45:16 INFO main - tls.client.trustCertPath = null
2023-05-03 19:45:16 INFO main - Using JDK SSL provider
2023-05-03 19:45:17 INFO main - SSLContext created for server
2023-05-03 19:45:17 INFO main - Try to start service thread:FileWatchService started:false lastThread:null
2023-05-03 19:45:17 INFO NettyEventExecutor - NettyEventExecutor service started
2023-05-03 19:45:17 INFO main - The Name Server boot success. serializeType=JSON
2023-05-03 19:45:17 INFO FileWatchService - FileWatchService service started

3.启动broker

修改broker配置文件:

cd ../config
vim broker.conf
//添加配置
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/commitlog
namesrvAddr=127.0.0.1:9876
brokerIP1=192.168.54.128
brokerIP2=192.168.54.128
autoCreateTopicEnable=false

修改JVM启动参数:

cd ../bin
vim runbroker.sh
将:
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
改为:
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn512m" 

启动broker:

nohup ./mqbroker -c ../conf/broker.conf &
//查看启动是否成功
less ~/logs/rocketmqlogs/broker.log
//输出以下结果表示启动成功
2023-05-03 20:00:11 INFO FileWatchService - FileWatchService service started
2023-05-03 20:00:11 INFO main - Try to start service thread:PullRequestHoldService started:false lastThread:null
2023-05-03 20:00:11 INFO PullRequestHoldService - PullRequestHoldService service started
2023-05-03 20:00:11 INFO main - Try to start service thread:TransactionalMessageCheckService started:false lastThread:null
2023-05-03 20:00:11 INFO brokerOutApi_thread_1 - register broker[0]to name server 127.0.0.1:9876 OK
2023-05-03 20:00:11 INFO main - The broker[broker-a, 192.168.54.128:10911] boot success. serializeType=JSON and name server is 127.0.0.1:9876
2023-05-03 20:00:21 INFO BrokerControllerScheduledThread1 - dispatch behind commit log 0 bytes
2023-05-03 20:00:21 INFO BrokerControllerScheduledThread1 - Slave fall behind master: 0 bytes
2023-05-03 20:00:21 INFO brokerOutApi_thread_2 - register broker[0]to name server 127.0.0.1:9876 OK
2023-05-03 20:00:51 INFO brokerOutApi_thread_3 - register broker[0]to name server 127.0.0.1:9876 OK
2023-05-03 20:01:11 INFO TransactionalMessageCheckService - create new topic TopicConfig [topicName=RMQ_SYS_TRANS_HALF_TOPIC, readQueueNums=1, writeQueueNums=1, perm=RW-, topicFilterType=SINGLE_TAG, topicSysFlag=0, order=false]
2023-05-03 20:01:11 INFO brokerOutApi_thread_4 - register broker[0]to name server 127.0.0.1:9876 OK
2023-05-03 20:01:21 INFO BrokerControllerScheduledThread1 - dispatch behind commit log 0 bytes
2023-05-03 20:01:21 INFO BrokerControllerScheduledThread1 - Slave fall behind master: 0 bytes
2023-05-03 20:01:21 INFO brokerOutApi_thread_1 - register broker[0]to name server 127.0.0.1:9876 OK 

 查看是否启动成功:

sh ./mqadmin clusterList -n 127.0.0.1:9876
//结果 出现以下结果表示启动成功
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
#Cluster Name     #Broker Name            #BID  #Addr                  #Version                #InTPS(LOAD)       #OutTPS(LOAD) #PCWait(ms) #Hour #SPACE
DefaultCluster    broker-a                0     192.168.54.128:10911   V4_7_1                   0.00(0,0ms)         0.00(0,0ms)          0 467532.35 -1.0000

 额外提示:我在使用mqadmin命令时候报了一个错:

Caused by: org.apache.rocketmq.acl.common.AclException: [10015:signature-failed] unable to calculate a request signature. error=Algorithm HmacSHA1 not available
//解决办法:将你的jdk安装目录下的lib/ext目录的绝对路径加到bin/tools.sh

JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/lib:${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext"
修改为
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/lib:${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-1.el7.aarch64/jre/lib/ext"

 4.安装rocketMq-Console

下载解压:

wget https://github.com/apache/rocketmq-externals/archive/rocketmq-console-1.0.0.tar.gz

tar -zxvf rocketmq-console-1.0.0.tar.gz
//进入解压文件夹下的rocketmq-console/src/main/resources修改配置文件
rocketmq.config.namesrvAddr=127.0.0.1:9876
然后回到根目录打包
mvn clean  package -DskipTests
//启动 在target目录下的jar,启动java -jar 启动即可

5.下载源码启动项目

下载源码:Release rocketmq-all-4.7.1 · apache/rocketmq · GitHub

启动NameServer:

在nameServer这个模块启动前先配置环境变量:

这个路径是自己指定的。

distribution/conf/logback_namesrv.xml 拷贝到上一步自己指定目录下的conf目录下。

然后启动,控制台输出:

Connected to the target VM, address: '127.0.0.1:59919', transport: 'socket'
The Name Server boot success. serializeType=JSON

启动broker:

将 distribution/conf/logback_brokerxml、broker.conf 文件拷贝到 上一步设置的目录的conf目录下。

修改 broker.conf 中的配置,主要设置 NameServer 的地址、Broker 的名称等相关属性。

vi broker.conf
# 使用如下配置文件
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
storePathRootDir=/home/dingwpmz/tmp/rocketmq/store
storePathCommitLog=/home/dingwpmz/tmp/rocketmq/store/commitlog
namesrvAddr=127.0.0.1:9876
brokerIP1=192.168.3.10 #自己的主机ip
brokerIP2=192.168.3.10 #自己的主机ip
autoCreateTopicEnable=true

设置broker启动的环境变量和启动参数

启动即可。 

测试:

然后运行 example 中 org/apache/rocketmq/example/quickstart/Producer,这里注意一下,要加下面一行代码

producer.setNamesrvAddr("127.0.0.1:9876");

因为下载的源码默认是没有指定nameServer地址的,我们要手动添加一下。

总结

本篇文章就是介绍了在Linux安装RocketMQ以及源码的下载启动,RocketMQ中有很多好的设计思想值得我们学习。在后面我会介绍RocketMQ的各个模块,包括NameServer、broker以及消息的发送和消费。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RocketMQ的延时消息实现是基于timerWheel的算法,主要包括以下几个步骤: 1. 发送延时消息时,将消息的过期时间与当前时间进行比较,如果过期时间比当前时间早,则直接丢弃消息。 2. 如果消息没有过期,则计算该消息应该被放置在timerWheel的哪个槽中,这个槽的位置是通过将消息的过期时间与timerWheel的时间轮进行计算得出的。 3. 将消息放置在相应的槽中,如果该槽中已经存在消息,则将新的消息插入到该槽中的链表的尾部。 4. 启动一个后台线程,定时遍历timerWheel,查找到期的消息,并将这些消息发送到对应的消费者。 以下是RocketMQ的延时消息源码实现: 1. 发送延时消息时,将消息的过期时间与当前时间进行比较,如果过期时间比当前时间早,则直接丢弃消息。 ``` public SendResult send(Message msg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { long maxTimeout = System.currentTimeMillis() + timeout; if (msg.getDelayTimeLevel() > 0) { long delayTime = calculateDelayTime(msg.getDelayTimeLevel()); if ((msg.getBornTimestamp() + delayTime) < maxTimeout) { msg.setDelayTimeLevel(0); } } //...省略其他代码 } ``` 2. 如果消息没有过期,则计算该消息应该被放置在timerWheel的哪个槽中,这个槽的位置是通过将消息的过期时间与timerWheel的时间轮进行计算得出的。 ``` private static long calculateDelayTimeLevel(long delayTime) { for (int i = 0; i < DELAY_LEVEL.length; i++) { if (delayTime < DELAY_LEVEL[i]) { return i; } } return DELAY_LEVEL.length - 1; } private static long calculateDelayTime(long level) { return DELAY_LEVEL[(int) Math.min(level, DELAY_LEVEL.length - 1)]; } private long computeDeliverTimestamp(final long startDeliverTime, final long delayTimeLevel) { long offset = DELAY_LEVEL[(int) delayTimeLevel]; return startDeliverTime + offset; } ``` 3. 将消息放置在相应的槽中,如果该槽中已经存在消息,则将新的消息插入到该槽中的链表的尾部。 ``` public void scheduleMessage(MessageExt msg) { long now = System.currentTimeMillis(); long deliverTimestamp = msg.getStoreTimestamp() + msg.getDelayTimeLevel(); long delay = deliverTimestamp - now; if (delay < 0) { delay = 0; } if (delay > config.getMaxDelayTime()) { delay = config.getMaxDelayTime(); } int index = (int) (delay / config.getTickTime()); long expireTime = deliverTimestamp - (deliverTimestamp % config.getTickTime()); try { lock.writeLock().lockInterruptibly(); TimerTaskList taskList = timerWheel[index]; if (taskList == null) { taskList = new TimerTaskList(expireTime); timerWheel[index] = taskList; } taskList.add(msg); } catch (InterruptedException e) { log.error("scheduleMessage error, ", e); } finally { lock.writeLock().unlock(); } } ``` 4. 启动一个后台线程,定时遍历timerWheel,查找到期的消息,并将这些消息发送到对应的消费者。 ``` private class TimerTask implements Runnable { private int index; private long currentTime; public TimerTask(int index, long currentTime) { this.index = index; this.currentTime = currentTime; } @Override public void run() { try { lock.writeLock().lockInterruptibly(); TimerTaskList taskList = timerWheel[index]; if (taskList != null) { List<MessageExt> messages = taskList.remove(currentTime); if (messages != null && !messages.isEmpty()) { putMessagesInQueue(messages); } } } catch (InterruptedException e) { log.error("TimerTask error, ", e); } finally { lock.writeLock().unlock(); } } } private class TimerThread implements Runnable { private volatile boolean stop = false; @Override public void run() { long lastExpireTime = 0; while (!stop) { long currentTime = System.currentTimeMillis(); if (currentTime > lastExpireTime) { for (int i = 0; i < config.getWheelSize(); i++) { long expireTime = lastExpireTime + (i + 1) * config.getTickTime(); if (expireTime <= currentTime) { executor.execute(new TimerTask(i, expireTime)); } } lastExpireTime = currentTime; } else { try { Thread.sleep(1); } catch (InterruptedException e) { log.error("TimerThread error, ", e); } } } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值