go rabbitmq配置使用及调优

生产者

gin结合rabbitmq(生产者完整代码)

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/gin-gonic/gin"
	amqp "github.com/rabbitmq/amqp091-go"
)

// 处理错误,如果有错误则输出错误信息并终止程序
func failOnError(err error, msg string) {
	if err != nil {
		log.Panicf("%s: %s", msg, err)
	}
}

var ch *amqp.Channel // 声明一个全局变量用于存储 RabbitMQ 频道

// 初始化 RabbitMQ 连接和队列
func initmq() {
	// 连接到 RabbitMQ 服务器
	conn, err := amqp.DialConfig("amqp://testmq:testmq@127.0.0.1:5672/", amqp.Config{
		Heartbeat: 60 * time.Second, // 设置心跳间隔为 60 秒,防止连接超时
	})
	failOnError(err, "Failed to connect to RabbitMQ")

	// 创建一个通道
	ch, err = conn.Channel()
	failOnError(err, "Failed to open a channel")

	// 声明一个队列
	_, err = ch.QueueDeclare(
		"hello", // 队列名称
		true,    // 是否持久化
		false,   // 是否自动删除(当没有消费者时删除)
		false,   // 是否排他(仅当前连接可用)
		false,   // 等待服务器确认队列创建
		nil,     // 额外参数
	)
	failOnError(err, "Failed to declare a queue")

	// 监听 RabbitMQ 连接是否被关闭
	notifyClose := conn.NotifyClose(make(chan *amqp.Error))
	go func() {
		err := <-notifyClose
		if err != nil {
			fmt.Printf("连接关闭,心跳超时或其他原因: %v\n", err)
		} else {
			fmt.Println("连接正常关闭")
		}
	}()
}

func main() {
	initmq() // 初始化 RabbitMQ 连接
	//------------------------------------------------------------------------
	r := gin.New()                      // 创建 Gin 路由引擎
	r.GET("/mq", func(c *gin.Context) { // 定义一个 GET 请求的接口
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // 设置 5 秒的上下文超时
		defer cancel()

		body := "bodyFrom" // 消息内容
		err := ch.PublishWithContext(ctx,
			"",      // 交换机(此处为空,表示使用默认交换机)
			"hello", // 路由键(即队列名称)
			false,   // 是否强制投递(mandatory)
			false,   // 是否立即投递(immediate)
			amqp.Publishing{
				DeliveryMode: amqp.Persistent, // 设置消息持久化
				ContentType:  "text/plain",    // 消息内容类型
				Body:         []byte(body),    // 消息内容
			})
		failOnError(err, "Failed to publish a message") // 发送消息失败时打印错误信息
	})

	r.Run() // 启动 Gin 服务器
}

连接rabbittmq并配置心跳 

conn, err := amqp.DialConfig("amqp://testmq:testmq@122.51.231.250:5672/", amqp.Config{
		Heartbeat: 60 * time.Second, // 设置心跳间隔为 60 秒,防止连接超时
	})

心跳一般配置为60秒最佳

声明队列

_, err = ch.QueueDeclare(
		"hello", // 队列名称
		true,    // 是否持久化
		false,   // 是否自动删除(当没有消费者时删除)
		false,   // 是否排他(仅当前连接可用)
		false,   // 等待服务器确认队列创建
		nil,     // 额外参数
	)

这里有只需要管前两个参数,后面保持默认即可。或者只需要管第一个参数,声明一下队列名称。第二个参数是否持久化,保持默认开启即可。它会把消息持久化到内存中,重启rabbitmq消息还在。

使用队列(向队列发送消息)

err := ch.PublishWithContext(ctx,
			"",      // 交换机(此处为空,表示使用默认交换机)
			"hello", // 路由键(即队列名称)
			false,   // 是否强制投递(mandatory)
			false,   // 是否立即投递(immediate)
			amqp.Publishing{
				DeliveryMode: amqp.Persistent, // 设置消息持久化
				ContentType:  "text/plain",    // 消息内容类型
				Body:         []byte(body),    // 消息内容
			})

消费者

消费者完整代码

package main

import (
	"fmt"
	"log"
	"time"

	amqp "github.com/rabbitmq/amqp091-go"
)

// 处理错误并打印日志,如果发生错误则终止程序
func failOnError(err error, msg string) {
	if err != nil {
		log.Panicf("%s: %s", msg, err)
	}
}

func main() {

	// 连接到 RabbitMQ 服务器,并设置心跳间隔为 60 秒,防止连接超时
	conn, err := amqp.DialConfig("amqp://testmq:testmq@127.0.0.1:5672/", amqp.Config{
		Heartbeat: 60 * time.Second,
	})
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close() // 在函数结束时关闭连接

	// 创建一个通道(Channel),通过该通道与 RabbitMQ 进行通信
	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close() // 在函数结束时关闭通道

	// 声明一个队列
	q, err := ch.QueueDeclare(
		"hello", // 队列名称
		true,    // 是否持久化
		false,   // 是否自动删除(当没有消费者连接时是否删除队列)
		false,   // 是否排他(仅限当前连接使用)
		false,   // 等待服务器确认队列创建
		nil,     // 其他参数
	)
	failOnError(err, "Failed to declare a queue")

	// 设置消费端的 QoS(质量保证服务)
	err = ch.Qos(
		30,    // 预取消息数,限制每次最多分配 30 条消息,防止消费者积压过多未处理的消息
		0,     // 预取大小(0 表示不限制单条消息大小)
		false, // 是否应用到整个连接(false 表示只对当前通道生效)
	)
	failOnError(err, "Failed to set QoS")

	// 注册消费者,监听队列中的消息
	msgs, err := ch.Consume(
		q.Name, // 队列名称
		"",     // 消费者名称(留空表示让 RabbitMQ 自动分配)
		false,  // 是否自动确认(auto-ack: false 需要手动确认消息)
		false,  // 是否排他(exclusive: false 允许多个消费者监听同一队列)
		false,  // 是否本地消费(no-local: false 允许连接自己消费自己发布的消息)
		false,  // 是否阻塞(no-wait: false 表示等待服务器返回确认)
		nil,    // 额外参数
	)
	failOnError(err, "Failed to register a consumer")

	// 创建一个阻塞通道,防止主协程退出
	var forever chan struct{}

	// 启动一个 goroutine 监听 RabbitMQ 消息
	go func() {
		for d := range msgs {
			// 业务逻辑处理部分
			fmt.Println(d.Body) // 打印收到的消息

			// 手动确认消息已被正确处理,false 表示仅确认该条消息
			d.Ack(false)
		}
	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	<-forever // 阻塞主线程,使程序保持运行
}

预取值

	err = ch.Qos(
		30,    // 预取消息数,限制每次最多分配 30 条消息,防止消费者积压过多未处理的消息
		0,     // 预取大小(0 表示不限制单条消息大小)
		false, // 是否应用到整个连接(false 表示只对当前通道生效)
	)

这里示例为30,实际运用时,要考消费者数量与消息堆积。经验值1-300,通常100以内都够用。如果不知道如何填可以3,填1的话均等分发最保守,性能太差。

手动确认消息

	msgs, err := ch.Consume(
		q.Name, // 队列名称
		"",     // 消费者名称(留空表示让 RabbitMQ 自动分配)
		false,  // 是否自动确认(auto-ack: false 需要手动确认消息)
		false,  // 是否排他(exclusive: false 允许多个消费者监听同一队列)
		false,  // 是否本地消费(no-local: false 允许连接自己消费自己发布的消息)
		false,  // 是否阻塞(no-wait: false 表示等待服务器返回确认)
		nil,    // 额外参数
	)

第二个参数为false

d.Ack(false)

消息被成功消费后执行d.Ack(false)确认

gitee代码示例

https://gitee.com/alsark/go-rabbbitmq-producer-consumer.githttps://gitee.com/alsark/go-rabbbitmq-producer-consumer.githttps://gitee.com/alsark/go-rabbbitmq-producer-consumer.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值