配置文件
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:
查看日志:
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()))