一、环境介绍
RabbitMQ版本:3.8.4
Golang版本:1.13.1
开发工具:IntelliJ IDEA 2019.2.3 x64
部署环境:centos7
代码已上传github:https://github.com/reachyu/realtimelog
二、业务场景
Web界面提交启动AI算法训练任务,AI算法训练结束后,发消息RabbitMQ,UI service从RabbitMQ获取到消息,存储AI算法训练结果
实体和算法操作只需要操作一次即可,一条消息只被一个消费端消费,因此使用RabbitMQ的工作队列模式。队列que01和que02持久化
生产者和消费者代码如下
package msgmq
import (
"github.com/golang/glog"
"github.com/streadway/amqp"
"log"
)
// rabbitmq 工作队列模式
// 发送消息(生产者)
func PublishMsgWork(queueName string,msg string) {
//申请队列,如果不存在会自动创建,存在跳过创建,保证队列存在,消息能发送到队列中
channel, err1 := MQInstance().GetMQCon().Channel()
if err1 != nil{
glog.Fatal(err1)
}
_,err := channel.QueueDeclare(
queueName,
//控制队列是否为持久的,当mq重启的时候不会丢失队列
true,
//是否为自动删除
false,
//是否具有排他性
false,
//是否阻塞
false,
//额外属性
nil,
)
if err != nil{
glog.Fatal(err)
}
//发送消息到队列中
_ = channel.Publish(
"",
queueName,
//如果为true,根据exchange类型和routekey类型,如果无法找到符合条件的队列,name会把发送的信息返回给发送者
false,
//如果为true,当exchange发送到消息队列后发现队列上没有绑定的消费者,则会将消息返还给发送者
false,
//发送信息
amqp.Publishing{
// 设置消息为持久的
DeliveryMode: amqp.Persistent,
ContentType: "text/plain",
Body: []byte(msg),
},
)
//defer channel.Close()
}
// 消费消息(消费者)
func ConsumeMsgWork(queueName string,user string){
//申请队列,如果不存在会自动创建,存在跳过创建,保证队列存在,消息能发送到队列中
channel, _ := MQInstance().GetMQCon().Channel()
_,err := channel.QueueDeclare(
queueName,
//控制消息是否持久化,true开启
true,
//是否为自动删除
false,
//是否具有排他性
false,
//是否阻塞
false,
//额外属性
nil,
)
if err != nil{
glog.Fatal(err)
}
//接收消息
msgs,err := channel.Consume(
queueName,
//用来区分多个消费者
"",
//是否自动应答(自动应答确认消息,这里设置为否,在下面手动应答确认)
false,
//是否具有排他性
false,
//如果设置为true,表示不能将同一个connection中发送的消息
//传递给同一个connection的消费者
false,
//是否为阻塞
false,
nil,
)
if err != nil {
glog.Fatal(err)
}
forever := make(chan bool)
//启用协程处理消息
go func() {
for d := range msgs {
// 手动确认收到本条消息, true表示回复当前信道所有未回复的ack,用于批量确认。false表示回复当前条目
d.Ack(false)
ParseMsg(d.Body)
log.Printf("接收端-----"+user + "==== [x] %s", d.Body)
}
}()
<-forever
}
三、使用
初始化连接
package msgmq
import (
_const "aisvc/common/const"
"fmt"
"github.com/golang/glog"
"github.com/streadway/amqp"
"sync"
)
type RabbitMQ struct {
conn *amqp.Connection
channel *amqp.Channel
}
var instance *RabbitMQ
var once sync.Once
func MQInstance() *RabbitMQ {
once.Do(func() {
instance = &RabbitMQ{}
})
return instance
}
func (r *RabbitMQ)InitConnect() bool {
fmt.Println("=====================初始化RabbitMQ连接=====================")
var err error
r.conn, err = amqp.Dial(_const.RABBITMQ_BROKER_URL)
if err != nil{
glog.Infof("failed to connect rabbitmq: %v",err)
return false
}
/*
channel, err = conn.Channel()
if err != nil {
glog.Infof("failed to open a channel: %v", err)
return false
}
*/
return true
}
func (r *RabbitMQ)CloseMq() {
_ = r.channel.Close()
_ = r.conn.Close()
}
func (r *RabbitMQ)GetMQCon() *amqp.Connection {
return r.conn
}
func (r *RabbitMQ)GetMQChannel() *amqp.Channel {
var err error
r.channel, err = r.conn.Channel()
if err != nil{
glog.Infof("failed to open a rabbitmq channel: %v",err)
return nil
}
return r.channel
}
测试
package main
import (
"encoding/json"
"flag"
_const "reallog/common/const"
"reallog/common/initenv"
"reallog/httpserver"
mq "reallog/msgmq"
"time"
)
func main() {
// 不调用的话,glog会报错----ERROR: logging before flag.Parse:
flag.Parse()
initenv.InitEnv()
go httpserver.InitHttpServer()
// 测试实时日志,rabbitmq路由模式
//testlogs()
// 测试工作队列模式
testwork()
}
func testlogs() {
msg := map[string]interface{}{
"trainId": 123456,
"trainLog": "测试测试测试测试",
}
msgJson, _ := json.Marshal(msg)
forever := make(chan bool)
go func() {
for {
// 测试,所以id写死
mq.PublishMsgRout(_const.RABBITMQ_ROUT_EXCHANGE_NAME,_const.RABBITMQ_ROUT_ROUTING_KEY+"123456",string(msgJson))
time.Sleep(1 * time.Second)
}
}()
<-forever
}
func testwork() {
msg := map[string]interface{}{
"msgId": "",
"objName": "trial",
"opt": "start",
"data": map[string]interface{}{
"trialId": 123,
"modelId": 666,
"dataPath": "image/test/001509.jpg",
"trialPara": map[string]interface{}{"score_threshold": "0.4"},
"ossBucket": "file",
"ossPath": "result/detection/test",
"model": map[string]interface{}{
"modelPath": "model/yolov3.YYMnist.h5",
"configPath": "result/detection/train-06-12/config.zip",
},
},
}
msgJson, _ := json.Marshal(msg)
go func() {
for {
mq.PublishMsgWork(_const.RABBITMQ_WORK_PUBLISH_QUEUE,time.Now().String() +"======="+string(msgJson))
time.Sleep(1 * time.Second)
}
}()
mq.ConsumeMsgWork(_const.RABBITMQ_WORK_CONSUME_QUEUE)
}
测试效果如下