gin和gorm进阶功能(8)之消息队列 | 青训营笔记

568 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天

概念

消息队列是一种设计模式,用于在两个不同的应用程序之间传递消息。它是一种非常有用的工具,因为它可以帮助解决应用程序之间的耦合问题。通过消息队列,可以确保消息可以在应用程序之间被安全地传递,而不用担心应用程序之间的联系。

消息队列可以是任何类型的消息,例如字符串,数字,对象等。消息队列通常用于在不同的系统中进行通信,例如分布式系统,微服务等。它也可以用于在同一系统内进行通信,例如不同的应用程序模块之间的通信。

消息队列具有以下几个重要的特征:

  • 异步:消息队列是异步的,因此消息可以在不同的时间传递。
  • 顺序:消息在队列中以特定顺序传递。
  • 可靠:消息队列具有可靠性,因此消息不会丢失。
  • 无状态:消息队列是无状态的,因此不需要考虑消息是否已经被处理。

消息队列通常由以下几个组件组成:

  • 生产者:生产者负责将消息放入队列。
  • 消息队列:消息队列负责存储消息并维护消息的顺序。
  • 消费者:消费者负责从队列中取出消息并对其进行处理。

有许多不同的消息队列实现可供选择,例如 RabbitMQ,Kafka,ActiveMQ 等。这些实现可以在本地环境或云环境中使用,并提供了丰富的特性,如高可用性,负载均衡等。

在使用消息队列时,有几个关键的概念需要考虑,如:

  • 消息确认:消息确认是指消费者确认已经处理完消息。这是一个重要的特性,因为它可以确保消息不会丢失。
  • 消息重试:消息重试是指在消息处理失败时,消息会重新放回队列以便再次尝试处理。

各种消息队列优缺点

  1. RabbitMQ:RabbitMQ 是一个开源的消息队列,支持 AMQP 协议。它提供了丰富的特性,如高可用性,负载均衡等。其优点是功能强大,支持多种协议,稳定性高。缺点是配置相对复杂,学习曲线较陡峭。
  2. Kafka:Kafka 是一个高性能的分布式消息队列,支持分区和复制。它具有高吞吐量,低延迟,高可用性的特点。其优点是性能高,适用于大规模数据处理场景。缺点是配置相对复杂,需要有一定的技术储备才能使用。
  3. ActiveMQ:ActiveMQ 是一个开源的消息队列,支持多种协议,如 JMS,STOMP 等。它提供了许多特性,如消息确认,消息重试等。其优点是易于使用,功能强大,社区活跃。缺点是性能不如 RabbitMQ 和 Kafka。
  4. Redis:Redis 是一个开源的内存数据库,也可以用作消息队列。它具有高速读写,低延迟的特点。其优点是性能高,易于使用。缺点是不支持分布式,不支持消息持久化。

Kafka在go的使用

docker部署Kafka

下面这个镜像集成了zookeeper和kafka aijishu.com/a/106000000… blog.csdn.net/weixin_4225… 连接不上解决方法: www.cnpython.com/java/668022

其中:

  • -d:表示容器在后台运行;
  • --name kafka:为容器命名为kafka;
  • -p 2181:2181:将容器中的2181端口映射到主机的2181端口;
  • -p 9092:9092:将容器中的9092端口映射到主机的9092端口;
  • --env ADVERTISED_HOST=<host_name>:指定Kafka集群的主机名,请替换为你的实际主机名;
  • --env ADVERTISED_PORT=9092:指定Kafka集群的端口,默认为9092。

注意下面必须写主机IP,否则连接不上

# 1.  下载Kafka镜像:
docker pull spotify/kafka

# 2. 启动容器
docker run -p 2181:2181 -p 9092:9092 --env ADVERTISED_HOST=[主机IP] --env ADVERTISED_PORT=9092 spotify/kafka

配置

go get -u github.com/confluentinc/confluent-kafka-go/kafka

代码

工具类

package kafka_client

import (
   "context"
   "github.com/segmentio/kafka-go"
)

// KafkaClient 封装了kafka-go库中的生产者和消费者
type KafkaClient struct {
   // producer 用于生产消息
   producer *kafka.Writer
   // consumer 用于消费消息
   consumer *kafka.Reader
}

// NewKafkaClient 创建一个Kafka工具类
func NewKafkaClient(brokers []string, topic string) *KafkaClient {
   kafkaClient := &KafkaClient{}
   // 创建生产者
   kafkaClient.producer = kafka.NewWriter(kafka.WriterConfig{
      Brokers:  brokers,
      Topic:    topic,
      Balancer: &kafka.LeastBytes{},
   })
   // 创建消费者
   kafkaClient.consumer = kafka.NewReader(kafka.ReaderConfig{
      Brokers:  brokers,
      Topic:    topic,
      MinBytes: 10e3, // 10KB
      MaxBytes: 10e6, // 10MB
   })
   return kafkaClient
}

// ProduceMessage 生产消息
func (k *KafkaClient) ProduceMessage(message string) error {
   // 封装消息
   kafkaMessage := kafka.Message{
      Value: []byte(message),
   }
   // 发送消息
   return k.producer.WriteMessages(context.Background(), kafkaMessage)
}

// ConsumeMessage 消费消息
func (k *KafkaClient) ConsumeMessage() (string, error) {
   // 获取消息
   m, err := k.consumer.FetchMessage(context.Background())
   if err != nil {
      return "", err
   }
   return string(m.Value), nil
}

// Close 关闭Kafka工具类,释放资源
func (k *KafkaClient) Close() {
   k.producer.Close()
   k.consumer.Close()
}