用RabbitMQ和golang实现一个异步任务系统,你会不会?

在使用 RabbitMQ 和 Go 语言实现一个异步任务系统时,你可以将任务分配给生产者,将任务的处理交给消费者,这样消费者可以异步处理这些任务。

RabbitMQ 是一个强大的消息队列系统,它允许多个生产者和多个消费者进行异步通信,这使得它成为构建异步任务系统的理想选择。

系统架构概述

  • 生产者 (Producer):生产者是任务的发送方。它会将任务发送到 RabbitMQ 中的一个队列。

  • 消费者 (Consumer):消费者从 RabbitMQ 队列中获取任务,并处理这些任务。

  • RabbitMQ:它充当消息中间件,负责存储和分发消息(任务)。

步骤概述:

  1. 安装 RabbitMQ。

  2. 使用 Go 的 amqp 库与 RabbitMQ 交互。

  3. 实现生产者,将任务发送到队列中。

  4. 实现消费者,从队列中获取任务并处理。

 

》》》GoLand永久账号 免费领取《《《

 

图片

 

1. 安装 RabbitMQ

RabbitMQ 可以通过 Docker 快速安装:

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

RabbitMQ 将运行在 localhost:5672 上,管理控制台运行在 localhost:15672。默认登录用户名和密码为 guest/guest

2. 安装 Go 的 amqp 库

首先,安装用于与 RabbitMQ 进行交互的 Go 包 github.com/streadway/amqp

go get github.com/streadway/amqp

3. 生产者实现(Producer)

生产者将任务发送到 RabbitMQ 的队列中。

package main

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

// 连接 RabbitMQ
func connectRabbitMQ() (*amqp.Connection, error) {
	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
	if err != nil {
		return nil, fmt.Errorf("failed to connect to RabbitMQ: %w", err)
	}
	return conn, nil
}

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func main() {
	conn, err := connectRabbitMQ()
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

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

	// 声明队列
	q, err := ch.QueueDeclare(
		"task_queue", // 队列名称
		true,         // 持久化
		false,        // 是否自动删除
		false,        // 是否排他
		false,        // 是否阻塞
		nil,          // 额外参数
	)
	failOnError(err, "Failed to declare a queue")

	// 要发送的消息
	body := "This is a task"
	err = ch.Publish(
		"",         // 交换机
		q.Name,     // 队列名称
		false,      // 如果没有路由到队列,是否返回消息
		false,      // 如果消费者没有接收,是否返回消息
		amqp.Publishing{
			DeliveryMode: amqp.Persistent, // 持久化消息
			ContentType:  "text/plain",
			Body:         []byte(body),
		})
	failOnError(err, "Failed to publish a message")
	log.Printf(" [x] Sent %s", body)
}

这个生产者会将消息 This is a task 发送到名为 task_queue 的 RabbitMQ 队列中。

 

4. 消费者实现(Consumer)

消费者将从队列中异步获取消息,并处理这些消息。

package main

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

// 错误处理函数
func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

// 模拟耗时任务
func worker(body string) {
	log.Printf("Processing task: %s", body)
	// 模拟耗时任务
	time.Sleep(2 * time.Second)
	log.Printf("Task finished: %s", body)
}

func main() {
	// 连接 RabbitMQ
	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	// 打开信道
	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()

	// 声明队列
	q, err := ch.QueueDeclare(
		"task_queue", // 队列名称
		true,         // 持久化
		false,        // 是否自动删除
		false,        // 是否排他
		false,        // 是否阻塞
		nil,          // 额外参数
	)
	failOnError(err, "Failed to declare a queue")

	// 消费者从队列中获取消息
	msgs, err := ch.Consume(
		q.Name, // 队列名称
		"",     // 消费者标识
		false,  // 自动应答
		false,  // 是否排他
		false,  // 非本地
		false,  // 阻塞
		nil,    // 额外参数
	)
	failOnError(err, "Failed to register a consumer")

	// 启动协程处理消息
	forever := make(chan bool)
	go func() {
		for d := range msgs {
			// 模拟任务处理
			log.Printf("Received a message: %s", d.Body)
			worker(string(d.Body))

			// 手动应答消息已处理
			d.Ack(false)
		}
	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	<-forever
}

5. 运行步骤

  1. 启动 RabbitMQ Docker 容器(如果还没有启动)。

  2. 运行消费者(Consumer)程序:

    go run consumer.go
    
  3. 运行生产者(Producer)程序:

    go run producer.go
    

消费者会自动获取生产者发布的任务,并处理这些任务。在这个例子中,消费者每次处理一条消息后会等待 2 秒钟,模拟任务处理的过程。

6. 扩展

这个基础结构可以进一步扩展来支持更多功能:

  • 任务重试机制:在消费者无法处理消息时,可以重新放回队列或者进行错误处理。

  • 多个消费者:可以启动多个消费者,处理并行任务。

  • 任务优先级:可以基于消息属性设置不同的优先级。

  • 延迟任务:可以使用 RabbitMQ 插件实现延迟队列,调度未来的任务。

通过 RabbitMQ 和 Go 的结合,你可以轻松构建一个高效的异步任务系统,并根据需求进行扩展。

posted @   技术颜良  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
历史上的今天:
2023-10-22 go中介模式
2023-10-22 golang validator 检验工具的使用指北
2021-10-22 redis linux内核优化方案
2021-10-22 REDIS缓存穿透,缓存击穿,缓存雪崩原因+解决方案
2021-10-22 容器编排系统K8s之节点污点和pod容忍度
点击右上角即可分享
微信分享提示