在 Golang 中,Kafka 是一个常用的分布式消息队列,可以通过社区支持的库(如 sarama
和 confluent-kafka-go
)进行操作。以下是 Kafka 在 Golang 中的使用详细介绍,包括生产者、消费者、和高级功能。
Kafka 客户端选择
- Sarama
- 纯 Go 实现,无需额外的 Kafka C 库。
- 功能强大,广泛使用。
- 配置和实现较复杂。
- Confluent Kafka Go
- 基于 C 库的绑定实现(依赖
librdkafka
)。 - 性能高,且配置简单。
- 需要安装 C 库。
- 基于 C 库的绑定实现(依赖
以下内容以 Sarama 为例。
Kafka 基础操作
1. 安装 Sarama 库
在项目目录中运行:
go get github.com/Shopify/sarama
2. 配置 Kafka 生产者
package main
import (
"log"
"github.com/Shopify/sarama"
)
func main() {
// Kafka 配置
config := sarama.NewConfig()
config.Producer.RequiredAcks = sarama.WaitForAll // 等待所有副本应答
config.Producer.Partitioner = sarama.NewRandomPartitioner // 随机选择分区
config.Producer.Return.Successes = true // 确认成功发送
// 创建生产者
producer, err := sarama.NewSyncProducer([]string{"localhost:9092"}, config)
if err != nil {
log.Fatalf("Failed to create producer: %v", err)
}
defer producer.Close()
// 发送消息
msg := &sarama.ProducerMessage{
Topic: "test_topic", // Kafka 主题
Value: sarama.StringEncoder("Hello, Kafka!"),
}
partition, offset, err := producer.SendMessage(msg)
if err != nil {
log.Fatalf("Failed to send message: %v", err)
}
log.Printf("Message sent to partition %d, offset %d\n", partition, offset)
}
3. 配置 Kafka 消费者
package main
import (
"log"
"os"
"os/signal"
"github.com/Shopify/sarama"
)
func main() {
// 创建消费者
consumer, err := sarama.NewConsumer([]string{"localhost:9092"}, nil)
if err != nil {
log.Fatalf("Failed to create consumer: %v", err)
}
defer consumer.Close()
// 订阅主题
partitionConsumer, err := consumer.ConsumePartition("test_topic", 0, sarama.OffsetNewest)
if err != nil {
log.Fatalf("Failed to start consumer for partition: %v", err)
}
defer partitionConsumer.Close()
// 捕获中断信号
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
// 消费消息
log.Println("Consuming messages...")
for {
select {
case msg := <-partitionConsumer.Messages():
log.Printf("Consumed message: %s\n", string(msg.Value))
case <-signals:
log.Println("Interrupt is detected, shutting down...")
return
}
}
}
4. 配置 Kafka 的异步生产者
异步生产者允许同时发送多条消息,提高吞吐量。
producer, err := sarama.NewAsyncProducer([]string{"localhost:9092"}, config)
if err != nil {
log.Fatalf("Failed to create async producer: %v", err)
}
defer producer.Close()
// 异步发送消息
go func() {
for {
select {
case success := <-producer.Successes():
log.Printf("Message sent successfully: %v", success)
case err := <-producer.Errors():
log.Printf("Failed to send message: %v", err)
}
}
}()
producer.Input() <- &sarama.ProducerMessage{
Topic: "test_topic",
Value: sarama.StringEncoder("Async Hello, Kafka!"),
}
高级功能
1. 设置 SSL 和 SASL
如果 Kafka 需要身份验证,可以通过 Sarama 配置:
config.Net.SASL.Enable = true
config.Net.SASL.User = "your_username"
config.Net.SASL.Password = "your_password"
config.Net.TLS.Enable = true
2. 消费者组
消费者组可以实现多个消费者共享一个组,每个消费者消费不同的分区:
package main
import (
"context"
"log"
"github.com/Shopify/sarama"
)
type consumerGroupHandler struct{}
func (consumerGroupHandler) Setup(_ sarama.ConsumerGroupSession) error {
return nil
}
func (consumerGroupHandler) Cleanup(_ sarama.ConsumerGroupSession) error {
return nil
}
func (consumerGroupHandler) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {
for message := range claim.Messages() {
log.Printf("Message claimed: topic=%s, value=%s, timestamp=%v\n", message.Topic, string(message.Value), message.Timestamp)
session.MarkMessage(message, "")
}
return nil
}
func main() {
config := sarama.NewConfig()
config.Version = sarama.V2_1_0_0
config.Consumer.Group.Rebalance.Strategy = sarama.BalanceStrategyRange
config.Consumer.Offsets.Initial = sarama.OffsetNewest
group, err := sarama.NewConsumerGroup([]string{"localhost:9092"}, "test_group", config)
if err != nil {
log.Fatalf("Error creating consumer group: %v", err)
}
defer group.Close()
ctx := context.Background()
for {
handler := consumerGroupHandler{}
if err := group.Consume(ctx, []string{"test_topic"}, handler); err != nil {
log.Fatalf("Error from consumer: %v", err)
}
}
}
调试和监控
- Kafka 自带工具:使用
kafka-console-producer.sh
和kafka-console-consumer.sh
测试。 - 日志级别:通过
config
配置sarama.Logger
,调试连接问题。
常见问题
- 分区分配问题:确保生产者配置了分区策略,消费者组使用了正确的再平衡策略。
- 消息丢失:配置
acks=all
和分区副本。 - 性能调优:增加消费者并发,或调整批量发送设置。
通过上述步骤,你可以在 Golang 项目中高效地使用 Kafka,并根据需求扩展其高级功能。