Golang+RabbitMQ工作模式

3 篇文章 0 订阅

一、环境介绍

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)

}

测试效果如下
在这里插入图片描述

在Go语言中集成RabbitMQ通常涉及到使用第三方库,如`gRPC-amqp`或`amqpcclient`,它们提供了Go语言绑定到AMQP协议(RabbitMQ使用的通信标准)的功能。以下是集成的基本步骤: 1. 安装依赖:首先需要安装RabbitMQ客户端库,可以使用`go get`命令获取官方推荐的`github.com/rabbitmq/amqp091-go`。 ```sh go get github.com/rabbitmq/amqp091-go ``` 2. 连接RabbitMQ:创建连接并设置相应的认证信息,例如用户名、密码和服务器地址。 ```go import ( "github.com/rabbitmq/amqp091-go" ) conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") if err != nil { // 处理错误 } defer conn.Close() ``` 3. 创建通道和交换机:在连接上打开一个新的通道,并可能创建或声明一个交换机。 ```go channel, err := conn.Channel() if err != nil { // 处理错误 } exchangeName := "myExchange" err = channel.ExchangeDeclare(exchangeName, "direct", true, false, false, nil, nil) if err != nil { // 处理错误 } ``` 4. 发布消息:将消息发送到指定的队列。 ```go routingKey := "myQueue" message := []byte("Hello, RabbitMQ!") err = channel.Publish(exchangeName, routingKey, false, false, amqp.Publishing{ DeliveryMode: amqp.Persistent, // 设置为持久化消息 Body: message, }) if err != nil { // 处理错误 } ``` 5. 消费消息:在另一个地方,你可以创建一个消费者来接收并处理从RabbitMQ发出的消息。 ```go queueName := "myQueue" consumerTag, err := channel.QueueConsume(queueName, "", true, false, false, nil, nil) if err != nil { // 处理错误 } for msg := range consumerTag Deliveries { body, _ := ioutil.ReadAll(msg.Body) fmt.Printf("Received: %s\n", string(body)) } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值