消息队列
这是我参加「第五届青训营」伴学笔记创作活动的第 10 天
四个问题
- 系统崩溃
- 服务处理能力有限
- 链路耗时长尾
- 日志如何处理
如何解决?
- 解耦(生产消费
- 削峰(每次限制请求数量
- 异步(先反馈给用户,再处理后台
- 消息队列记录
消息队列:保存消息的容器,本质是一个队列,但是要满足高吞吐、高并发、高可用
Kafka消息队列
Kafka是一种分布式消息队列,可以支持高吞吐量和低延迟。它主要用于在大型分布式系统中进行数据流处理和事件驱动微服务。
Kafka消息队列拥有以下特点:
- 高吞吐量:可以处理每秒数千万条消息。
- 分布式:支持在多台机器上运行,以提高可用性和可扩展性。
- 持久性:消息可以永久保存,以保证不会丢失任何数据。
- 可靠性:支持消息的可靠传递,以保证消息不会丢失。
- 简单:支持简单的生产者/消费者API,使用起来非常方便。
在Go语言中,可以使用第三方包github.com/segmentio/kafka-go"来使用Kafka消息队列。以下是生产者的示例代码:
package main
import (
"fmt"
"github.com/segmentio/kafka-go"
)
func main() {
// 创建一个生产者
producer := kafka.NewWriter(kafka.WriterConfig{
Brokers: []string{"localhost:9092"},
Topic: "test-topic",
Balancer: &kafka.LeastBytes{},
})
// 发送消息
message := "hello, kafka"
producer.WriteMessages(
kafka.Message{
Key: []byte("key"),
Value: []byte(message),
},
)
// 关闭生产者
producer.Close()
fmt.Println("Message sent:", message)
}
以下是消费者的示例代码:
package main
import (
"fmt"
"github.com/segmentio/kafka-go"
)
func main() {
// 创建一个消费者
consumer := kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{"localhost:9092"},
Topic: "test-topic",
Partition: 0,
MinBytes: 10e3, // 10KB
MaxBytes: 10e6, // 10MB
})
// 读取消息
for {
message, err := consumer.ReadMessage(context.Background())
if err != nil {
break
}
fmt.Println("Message received:", string(message.Value))
}
// 关闭消费者
consumer.Close()
}
高吞吐发挥出色
如何使用?
- 创建Kafka集群(有些地方可以不做,例如字节)
- 新增Topic
- 生产者逻辑
- 消费者逻辑
基本概念?
- offset,消息在分区内的位置,可以理解为唯一id,在分区内部严格递增(说明了可以二分
如何高吞吐?
- 批量发送(减少发送次数
- 数据压缩(减少消息大小
BMQ
存算分离,云原生消息队列,逐步替换Kafka BMQ (Binary Message Queue) 是一种消息队列系统,具有高吞吐量、高并发能力、可靠性等特点。它主要通过二进制格式存储消息,使用简单、效率高,适用于各种分布式系统。
在 Go 语言中,可以使用第三方库 github.com/bm-metrics/bmq 来实现 BMQ 的生产和消费。
以下是一个生产者示例代码:
package main
import (
"github.com/bm-metrics/bmq"
)
func main() {
// 创建一个生产者
producer := bmq.NewProducer("localhost:11300")
defer producer.Close()
// 发送消息
producer.Put("test-tube", []byte("Hello, BMQ!"), 0, 0)
}
以下是一个消费者示例代码:
package main
import (
"github.com/bm-metrics/bmq"
)
func main() {
// 创建一个消费者
consumer := bmq.NewConsumer("localhost:11300")
defer consumer.Close()
// 订阅消息
consumer.Watch("test-tube")
// 消费消息
for {
job, err := consumer.Reserve(0)
if err != nil {
break
}
fmt.Println("Message received:", string(job.Body))
// 标记任务已完成
consumer.Delete(job.ID)
}
}
RocketMQ
低延迟,实施场景使用
RocketMQ 是阿里巴巴开源的分布式消息中间件,具有高性能、高可用、高可靠的特点。RocketMQ 提供了生产者、消费者、存储和管理等功能,可以很好的满足分布式系统的消息需求。
在 Go 语言中,可以使用第三方库 "github.com/apache/rocketmq-client-go" 来实现 RocketMQ 的生产和消费。
以下是一个生产者示例代码:
package main
import (
"github.com/apache/rocketmq-client-go/v2"
"github.com/apache/rocketmq-client-go/v2/producer"
)
func main() {
// 创建生产者
p, err := rocketmq.NewProducer(
producer.WithNameServer([]string{"localhost:9876"}),
producer.WithRetry(2),
)
if err != nil {
fmt.Printf("create producer error: %s", err)
return
}
defer p.Shutdown()
// 发送消息
res, err := p.SendSync(
context.Background(),
&producer.Message{
Topic: "test-topic",
Body: []byte("Hello, RocketMQ!"),
},
)
if err != nil {
fmt.Printf("send message error: %s", err)
return
}
fmt.Printf("send message success: result=%s", res)
}
以下是一个消费者示例代码:
package main
import (
"context"
"fmt"
"github.com/apache/rocketmq-client-go/v2"
"github.com/apache/rocketmq-client-go/v2/consumer"
)
func main() {
// 创建消费者
c, err := rocketmq.NewPushConsumer(
consumer.WithNameServer([]string{"localhost:9876"}),
consumer.WithConsumerGroup("test-group"),
consumer.WithRetry(2),
)
if err != nil {
fmt.Printf("create consumer error: %s", err)
return
}
defer c.Shutdown()
// 订阅消息
err = c.Subscribe("test-topic", consumer.MessageSelector{}, func(ctx context.Context, msg *consumer.Message) (consumer.ConsumeResult, error) {
fmt.Printf("receive message: %s\n", string(msg.Body))
return consumer.ConsumeSuccess, nil
})
if err != nil {
fmt.Printf("subscribe error: %s", err)
return
}
// 启动消费者
err = c.Start()
if err != nil {
fmt.Printf("start consumer error: %s", err)
return
}
}