【Golang】mq消息队列学习

在软件开发中,消息队列(MQ)常用于实现异步通信、解耦合、以及提高系统的伸缩性和可靠性。以下是一个简单的 Go 语言示例,展示了 使用 MQ不使用 MQ 的区别。

场景:

假设我们有一个需要处理的任务,比如发送通知。我们有两种方式:

  1. 不使用 MQ:直接在同一进程中同步处理任务。
  2. 使用 MQ:通过消息队列异步地发送任务,消息队列可以让任务在后台处理。

不使用 MQ(同步处理任务)

在不使用消息队列的情况下,程序会同步处理任务,即在发送通知时,任务需要在主程序中等待完成。

代码示例(不使用 MQ)
package main

import (
	"fmt"
	"time"
)

// 发送通知的函数(同步)
func sendNotification(message string) {
	// 模拟任务处理时间
	time.Sleep(2 * time.Second)
	fmt.Println("通知已发送:", message)
}

func main() {
	fmt.Println("开始发送通知")

	// 直接同步处理任务
	sendNotification("任务1")
	sendNotification("任务2")
	sendNotification("任务3")

	fmt.Println("所有通知已发送")
}

使用 MQ(异步处理任务)

在使用消息队列的情况下,任务被发送到消息队列,然后由消费者(独立的处理程序)异步处理。这种方式提高了系统的伸缩性,因为生产者和消费者可以独立工作,不需要同步等待。

假设我们使用 RabbitMQ 作为消息队列。你需要安装 Go 的 amqp 包来与 RabbitMQ 进行交互。

go get github.com/streadway/amqp
代码示例(使用 RabbitMQ 作为 MQ)
生产者(将任务发送到 MQ)
package main

import (
	"fmt"
	"log"
	"github.com/streadway/amqp"
)

// 发送消息到队列
func sendMessageToQueue(message string) {
	// 连接到 RabbitMQ
	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
	if err != nil {
		log.Fatalf("连接 RabbitMQ 失败: %s", err)
	}
	defer conn.Close()

	// 创建通道
	ch, err := conn.Channel()
	if err != nil {
		log.Fatalf("创建通道失败: %s", err)
	}
	defer ch.Close()

	// 声明一个队列
	q, err := ch.QueueDeclare(
		"notificationQueue", // 队列名称
		false,               // 是否持久化
		false,               // 是否自动删除
		false,               // 是否排他
		false,               // 是否阻塞
		nil,                 // 额外参数
	)
	if err != nil {
		log.Fatalf("声明队列失败: %s", err)
	}

	// 发送消息到队列
	err = ch.Publish(
		"",                // 交换机
		q.Name,            // 队列名称
		false,             // 是否等待确认
		false,             // 是否永久存储
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		})
	if err != nil {
		log.Fatalf("发送消息失败: %s", err)
	}

	fmt.Println("已将消息发送到队列:", message)
}

func main() {
	// 模拟任务发送
	sendMessageToQueue("任务1")
	sendMessageToQueue("任务2")
	sendMessageToQueue("任务3")
}

消费者(从 MQ 获取任务并处理)

package main

import (
	"fmt"
	"log"
	"github.com/streadway/amqp"
	"time"
)

// 从队列获取并处理任务
func consumeMessageFromQueue() {
	// 连接到 RabbitMQ
	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
	if err != nil {
		log.Fatalf("连接 RabbitMQ 失败: %s", err)
	}
	defer conn.Close()

	// 创建通道
	ch, err := conn.Channel()
	if err != nil {
		log.Fatalf("创建通道失败: %s", err)
	}
	defer ch.Close()

	// 声明一个队列
	q, err := ch.QueueDeclare(
		"notificationQueue", // 队列名称
		false,               // 是否持久化
		false,               // 是否自动删除
		false,               // 是否排他
		false,               // 是否阻塞
		nil,                 // 额外参数
	)
	if err != nil {
		log.Fatalf("声明队列失败: %s", err)
	}

	// 获取队列中的消息
	msgs, err := ch.Consume(
		q.Name, // 队列名称
		"",     // 消费者标签
		true,   // 自动确认
		false,  // 排他
		false,  // 非持久
		false,  // 阻塞
		nil,    // 额外参数
	)
	if err != nil {
		log.Fatalf("消费队列失败: %s", err)
	}

	// 处理接收到的消息
	for msg := range msgs {
		fmt.Println("正在处理通知:", string(msg.Body))
		// 模拟处理时间
		time.Sleep(2 * time.Second)
		fmt.Println("通知已处理:", string(msg.Body))
	}
}

func main() {
	// 启动消费者
	consumeMessageFromQueue()
}

总结

  1. 不使用 MQ(同步)

    • 所有的任务(如发送通知)都在主程序内同步处理,导致程序必须等待每个任务完成后才能继续执行其他任务。适用于任务量少或不需要异步处理的场景。
  2. 使用 MQ(异步)

    • 使用 RabbitMQ 或其他消息队列,生产者将任务发送到消息队列,消费者从队列中取任务并异步处理。这样生产者和消费者解耦,任务处理更加灵活且可扩展,适用于高并发或需要任务异步处理的场景。

性能和可靠性:

  • 使用 MQ 可以提高系统的可靠性和伸缩性,特别是在处理大量任务时。通过消息队列的异步处理,系统的吞吐量能够大幅提升。
  • 在没有 MQ 的情况下,任务的处理会被同步阻塞,可能导致性能瓶颈。

运行环境

在使用 RabbitMQ 的代码示例中,你需要确保本地有 RabbitMQ 服务在运行。你可以通过 Docker 启动 RabbitMQ 服务:

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management

docker ps 显示镜像

http://x.x.x.x:

以下是简单的rabbitmq客户端的操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值