安装
go get github.com/segmentio/kafka-go
生产者
常用配置
writer = &kafka.Writer{
Addr: kafka.TCP(kafkaAddress), // 设置Kafka的TCP连接地址(配置)
Topic: topicName, // 设置要写入的主题名称(配置)
Balancer: &kafka.LeastBytes{}, // 选择分区策略,这里使用最小字节策略(保持)
BatchSize: 100, // 设置批次大小,以消息数量为单位(选填)
BatchBytes: 1024 * 1024, // 设置批次字节大小上限(选填)
BatchTimeout: 1 * time.Second, // 批次超时时间,触发批量发送的超时机制(选填)
Async: true, // 使用异步模式发送消息,提高吞吐量(保持)
RequiredAcks: kafka.RequireOne, // 设置应答级别,仅需一个副本确认,平衡可靠性和性能(保持,默认kafka.RequireNone)
Compression: kafka.Snappy, // 使用Snappy压缩以减少网络传输量(选填)
}
(选填)仅调优时适当调整,一般不需要管。(保持)保持默认即可,通常的配置。(配置)后面有完整示例。
测试连接是否成功
conn, err := kafka.Dial("tcp", kafkaAddress)
if err != nil {
fmt.Printf("连接Kafka broker失败: %v", err)
return
}
defer conn.Close()
检查是否有对应topic
_, err = conn.ReadPartitions(topicName)
if err != nil {
fmt.Printf("找不到topic %s: %v", topicName, err)
writer.Close()
return
}
写入消息
err := writer.WriteMessages(context.Background(),
kafka.Message{
Value: []byte("Hello Kafka"),
},
)
if err != nil {
log.Printf("写入消息失败: %v", err)
c.JSON(500, gin.H{"error": "写入消息失败"})
return
}
生产者完整代码
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/gin-gonic/gin"
"github.com/segmentio/kafka-go"
)
// Kafka 配置
const (
kafkaAddress = "127.0.0.1:9092"
topicName = "test"
)
// 全局 Kafka Writer 实例
var writer *kafka.Writer
func initKafkaWriter() {
writer = &kafka.Writer{
Addr: kafka.TCP(kafkaAddress), // 设置Kafka的TCP连接地址(配置)
Topic: topicName, // 设置要写入的主题名称(配置)
Balancer: &kafka.LeastBytes{}, // 选择分区策略,这里使用最小字节策略(保持)
BatchSize: 100, // 设置批次大小,以消息数量为单位(选填)
BatchBytes: 1024 * 1024, // 设置批次字节大小上限(选填)
BatchTimeout: 1 * time.Second, // 批次超时时间,触发批量发送的超时机制(选填)
Async: true, // 使用异步模式发送消息,提高吞吐量(保持)
RequiredAcks: kafka.RequireOne, // 设置应答级别,仅需一个副本确认,平衡可靠性和性能(保持,默认kafka.RequireNone)
Compression: kafka.Snappy, // 使用Snappy压缩以减少网络传输量(选填)
}
// 测试连接 Kafka
conn, err := kafka.Dial("tcp", kafkaAddress)
if err != nil {
fmt.Printf("连接Kafka broker失败: %v", err)
return
}
defer conn.Close()
// 确保 topic 存在
_, err = conn.ReadPartitions(topicName)
if err != nil {
fmt.Printf("找不到topic %s: %v", topicName, err)
writer.Close()
return
}
fmt.Println("连接Kafka broker成功")
}
func main() {
initKafkaWriter()
r := gin.Default()
r.GET("/write", func(c *gin.Context) {
// 写入消息
err := writer.WriteMessages(context.Background(),
kafka.Message{
Value: []byte("Hello Kafka"),
},
)
if err != nil {
log.Printf("写入消息失败: %v", err)
c.JSON(500, gin.H{"error": "写入消息失败"})
return
}
log.Println("写入消息成功")
c.JSON(200, gin.H{"message": "写入消息成功"})
})
// 启动服务器
r.Run()
}
消费者
常用配置
r = kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{kafkaAddress}, // 设置Kafka代理地址列表(配置)
Topic: topicName, // 指定要读取的主题(配置)
GroupID: consumergroup, // 设置消费者组ID,支持消费组管理(配置)
MinBytes: 1, // 设置单次读取的最小字节数(选填)
MaxBytes: 10e6, // 设置单次读取的最大字节数为10MB(保持)
MaxWait: 10 * time.Second, // 获取批处理时等待新数据的最大时间(选填)
StartOffset: kafka.LastOffset, // 指定读取的起始偏移量,从最新的消息开始(保持,默认kafka.FirstOffset)
CommitInterval: 0, // 自动提交偏移量的时间间隔,为0时为同步提交(保持,每秒time.Second)
})
读取消息
for {
m, err := r.ReadMessage(context.Background())
if err != nil {
log.Printf("读取消息时出错: %v", err)
break
}
fmt.Printf("主题/分区/偏移量 %v/%v/%v: %s = %s\n", m.Topic, m.Partition, m.Offset, string(m.Key), string(m.Value))
}
if err := r.Close(); err != nil {
log.Fatal("failed to close reader:", err)
}
消费者完整代码
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/segmentio/kafka-go"
)
// Kafka 配置
const (
kafkaAddress = "127.0.0.1:9092"
topicName = "test"
consumergroup = "consumer-group-id"
)
var r *kafka.Reader
func initKafkaReader() {
r = kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{kafkaAddress}, // 设置Kafka代理地址列表(配置)
Topic: topicName, // 指定要读取的主题(配置)
GroupID: consumergroup, // 设置消费者组ID,支持消费组管理(配置)
MinBytes: 1, // 设置单次读取的最小字节数(选填)
MaxBytes: 10e6, // 设置单次读取的最大字节数为10MB(保持)
MaxWait: 10 * time.Second, // 获取批处理时等待新数据的最大时间(选填)
StartOffset: kafka.LastOffset, // 指定读取的起始偏移量,从最新的消息开始(保持,默认kafka.FirstOffset)
CommitInterval: 0, // 自动提交偏移量的时间间隔,为0时为同步提交(保持,每秒time.Second)
})
// 测试连接 Kafka
conn, err := kafka.Dial("tcp", kafkaAddress)
if err != nil {
fmt.Printf("连接Kafka broker失败: %v", err)
return
}
defer conn.Close()
// 确保 topic 存在
_, err = conn.ReadPartitions(topicName)
if err != nil {
fmt.Printf("找不到topic %s: %v", topicName, err)
r.Close()
return
}
fmt.Println("连接Kafka broker成功")
}
func main() {
initKafkaReader()
fmt.Println("开始消费消息...")
for {
m, err := r.ReadMessage(context.Background())
if err != nil {
log.Printf("读取消息时出错: %v", err)
break
}
fmt.Printf("主题/分区/偏移量 %v/%v/%v: %s = %s\n", m.Topic, m.Partition, m.Offset, string(m.Key), string(m.Value))
}
if err := r.Close(); err != nil {
log.Fatal("failed to close reader:", err)
}
}