RocketMQ:搭建记录

286 阅读3分钟

配置文件

warson_demo.properties

brokerClusterName=warson_cluster
# 单Master架构
brokerName=broker-1
# master的brokerId为0 
brokerId=0
# 指定删除消息存储过期文件的时间为凌晨4点
deleteWhen=04
# 指定未发生更新的消息存储文件的保留时长为48小时,48小时后过期,将会被删除 
fileReservedTime=48
# 异步复制master
brokerRole=ASYNC_MASTER
# 指定刷盘策略为异步刷盘 
flushDiskType=ASYNC_FLUSH
# 指定nameserver的地址,这里写云服务器的公网ip,因为这里的信息直接写入到nameserver
# 如果直接写127.0.0.1或者服务器内网ip,本地程序的producer就无法连接到broker了,因为nameserver返回的就是这里写的地址给客户端!
namesrvAddr=公网ip:9876
#是否允许 Broker 自动创建Topic,建议生产环境中关闭 
autoCreateTopicEnable=true 
#是否允许 Broker 自动创建订阅组,建议生产环境中关闭 
autoCreateSubscriptionGroup=true
#Broker对外提供服务的端口,即Broker与producer与consumer通信的端口 
listenPort=10911
#HA高可用监听端口,即Master与Slave间通信的端口,默认值为listenPort+1 
haListenPort=10912
#指定commitLog目录中每个文件的大小,默认1G
#这里指定为100M 
mapedFileSizeCommitLog=104857600
#指定ConsumeQueue的每个Topic的每个Queue文件中可以存放的消息数量,默认30w条 
mapedFileSizeConsumeQueue=1000
#在清除过期文件时,如果该文件被其他线程所占用(引用数大于0,比如读取消息),此时会阻止 此次删除任务,同时在第一次试图删除该文件时记录当前时间戳。该属性则表示从第一次拒绝删除 后开始计时,该文件最多可以保留的时长。在此时间内若引用数仍不为0,则删除仍会被拒绝。不过 时间到后,文件将被强制删除 
destroyMapedFileIntervalForcibly=120000
#指定commitlog、consumequeue所在磁盘分区的最大使用率,超过该值,则需立即清除过期文件
diskMaxUsedSpaceRatio=88
#指定store目录的路径,默认在当前用户主目录中 
storePathRootDir=/usr/local/rocketmq-all-4.5.0/store
#commitLog目录路径 
storePathCommitLog=/usr/local/rocketmq-all-4.5.0/store/commitlog
#consumeueue目录路径 
storePathConsumeQueue=/usr/local/rocketmq-all-4.5.0/store/consumequeue
#index目录路径
storePathIndex=/usr/local/rocketmq-all-4.5.0/store/index
#checkpoint文件路径 
storeCheckpoint=/usr/local/rocketmq-all-4.5.0/store/checkpoint
#abort文件路径 
abortFile=/usr/local/rocketmq-all-4.5.0/store/abort
#指定消息的最大大小 
maxMessageSize=65536
#发消息线程池数量 
sendMessageThreadPoolNums=128 
#拉消息线程池数量 
pullMessageThreadPoolNums=128 
#强制指定本机IP,需要根据每台机器进行修改。官方介绍可为空,系统默认自动识别,但多网卡 时IP地址可能读取错误,我这里
brokerIP1=公网ip

启动:

命令均在解压的rocketMQ目录下执行

# 启动nameserver
nohup sh bin/mqnamesrv &
# 启动broker
nohup sh bin/mqbroker -c conf/warson_demo.properties &

关闭:

sh bin/mqshutdown broker
sh bin/mqshutdown namesrv

debug:

# 云服务器要记得开放端口,虚拟机的话要开放防火墙
# 查看broker端口是否有监听
netstat -anp | grep 10911
# 查看topic是否存在
cat ~/logs/rocketmqlogs/broker.log  | grep topicName=test

改成公网IP: 图片.png

查看日志:

tail -f ~/logs/rocketmqlogs/namesrv.log
tail -f ~/logs/rocketmqlogs/broker.log

依赖

module rocketMQ_demo

go 1.16

require github.com/apache/rocketmq-client-go/v2 v2.1.0-rc3

consumer

package main

import (
   "context"
   "fmt"
   "github.com/apache/rocketmq-client-go/v2"
   "github.com/apache/rocketmq-client-go/v2/consumer"
   "github.com/apache/rocketmq-client-go/v2/primitive"
   "os"
   "rocketMQ_demo/common"
)

func main() {

   c, _ := rocketmq.NewPushConsumer(
      consumer.WithGroupName("consumer_group_01"),
      consumer.WithNameServer(primitive.NamesrvAddr{common.NameServerAddress}),
      consumer.WithConsumerModel(consumer.Clustering),
   )

   delayLevel := 1
   //订阅topic为test的消息
   err := c.Subscribe("test", consumer.MessageSelector{},
      func(ctx context.Context,
         msgs ...*primitive.MessageExt) (consumer.ConsumeResult, error) {
         fmt.Printf("subscribe callback len: %d \n", len(msgs))

         concurrentCtx, _ := primitive.GetConcurrentlyCtx(ctx)
         // only run when return consumer.ConsumeRetryLater
         concurrentCtx.DelayLevelWhenNextConsume = delayLevel

         for _, msg := range msgs {
            fmt.Printf("subscribe callback: %v \n", msg)
         }

         return consumer.ConsumeSuccess, nil
      })

   if err != nil {
      fmt.Println(err.Error())
   }

   // Note: start after subscribe
   err = c.Start()
   if err != nil {
      fmt.Println(err.Error())
      os.Exit(-1)
   }
   err = c.Shutdown()
   if err != nil {
      fmt.Printf("shundown Consumer error: %s", err.Error())
   }

}

producer

package main

import (
   "context"
   "fmt"
   "github.com/apache/rocketmq-client-go/v2"
   "github.com/apache/rocketmq-client-go/v2/primitive"
   "github.com/apache/rocketmq-client-go/v2/producer"
   "os"
   "rocketMQ_demo/common"
   "sync"
)

func main() {
   p, _ := rocketmq.NewProducer(
      producer.WithNameServer(primitive.NamesrvAddr{common.NameServerAddress}),
      producer.WithRetry(2),
      producer.WithGroupName("producer_group_01"),
      //这里是个坑
      //producer.WithQueueSelector(producer.NewManualQueueSelector()),
      )

   err := p.Start()
   if err != nil {
      fmt.Printf("start producer error: %s", err.Error())
      os.Exit(1)
   }
   var wg sync.WaitGroup
   for i := 0; i < 10; i++ {
      wg.Add(1)
      err := p.SendAsync(context.Background(),
         func(ctx context.Context, result *primitive.SendResult, e error) {
            if e != nil {
               fmt.Printf("receive message error: %s\n", err)
            } else {
               fmt.Printf("send message success: result=%s\n", result.String())
            }
            wg.Done()
         },
         //topic为test
         primitive.NewMessage("test", []byte("Hello 测试 Go Client!")))

      if err != nil {
         fmt.Printf("send message error: %s\n", err)
      }
   }
   wg.Wait()
   err = p.Shutdown()
   if err != nil {
      fmt.Printf("shutdown producer error: %s", err.Error())
   }
   fmt.Println("producer progress exit...")
}

注意

当时运行producer的时候,直接copy了examples/producer/async/main.go的例子,改了nameServer的地址运行了,结果一直报错:send message error: the topic=test route info not found
最后发现要把这行注释掉才行:

producer.WithQueueSelector(producer.NewManualQueueSelector()))