why is kafka
Apache Kafka 是一种实时数据流技术,每天能够处理数万亿个事件。Kafka 最初被设想为消息队列,基于分布式提交日志的抽象。自 2011 年创建并开源以来,Kafka 已成为处理动态数据的行业标准
sarama
这里我们使用在go当中常用的第三方插件 Go语言中连接kafka使用第三方库
1、下载及安装`
go get github.com/Shopify/sarama
注意
sarama v1.20之后的版本加入了zstd压缩算法,需要用到cgo,在Windows平台编译时会提示类似如下错误:
# github.com/DataDog/zstd
exec: "gcc":executable file not found in %PATH%
所以在Windows平台请使用v1.19版本的sarama。
2、连接kafka发送消息
package main
import (
"fmt"
"github.com/Shopify/sarama"
)
// 基于sarama第三方库开发的kafka client
func main() {
config := sarama.NewConfig()
config.Producer.RequiredAcks = sarama.WaitForAll // 发送完数据需要leader和follow都确认
config.Producer.Partitioner = sarama.NewRandomPartitioner // 新选出一个partition
config.Producer.Return.Successes = true // 成功交付的消息将在success channel返回
// 构造一个消息
msg := &sarama.ProducerMessage{}
msg.Topic = "web_log"
msg.Value = sarama.StringEncoder("this is a test log")
// 连接kafka
client, err := sarama.NewSyncProducer([]string{"127.0.0.1:9092"}, config)
if err != nil {
fmt.Println("producer closed, err:", err)
return
}
defer client.Close()
// 发送消息
pid, offset, err := client.SendMessage(msg)
if err != nil {
fmt.Println("send msg failed, err:", err)
return
}
fmt.Printf("pid:%v offset:%v\n", pid, offset)
}
3、连接kafka消费消息
package main
import (
"fmt"
"github.com/Shopify/sarama"
)
// kafka consumer
func main() {
consumer, err := sarama.NewConsumer([]string{"127.0.0.1:9092"}, nil)
if err != nil {
fmt.Printf("fail to start consumer, err:%v\n", err)
return
}
partitionList, err := consumer.Partitions("web_log") // 根据topic取到所有的分区
if err != nil {
fmt.Printf("fail to get list of partition:err%v\n", err)
return
}
fmt.Println(partitionList)
for partition := range partitionList { // 遍历所有的分区
// 针对每个分区创建一个对应的分区消费者
pc, err := consumer.ConsumePartition("web_log", int32(partition), sarama.OffsetNewest)
if err != nil {
fmt.Printf("failed to start consumer for partition %d,err:%v\n", partition, err)
return
}
defer pc.AsyncClose()
// 异步从每个分区消费信息
go func(sarama.PartitionConsumer) {
wg.Add(1)//等待数量+1
for msg := range pc.Messages() {
fmt.Printf("Partition:%d Offset:%d Key:%v Value:%v", msg.Partition, msg.Offset, msg.Key, msg.Value)
}
wg.Done()//等待数量-1
}(pc)
}
time.Sleep(time.Hour)
}
4、至此一个简单的kafka生产者和消费者就完成了,具体的业务可再次基础之上封装抽象
随着go语音开发大军的增长sarama也出现了一些不一样声音
为什么不推荐使用Sarama Go客户端收发消息?
问题现象
所有Sarama Go版本客户端存在以下已知问题:
- 当Topic新增分区时,Sarama Go客户端无法感知并消费新增分区,需要客户端重启后,才能消费到新增分区。
- 当Sarama Go客户端同时订阅两个以上的Topic时,有可能会导致部分分区无法正常消费消息。
- 当Sarama Go客户端的消费位点重置策略设置为
Oldest(earliest)时,如果客户端宕机或服务端版本升级,由于Sarama Go客户端自行实现OutOfRange机制,有可能会导致客户端从最小位点开始重新消费所有消息。
解决方案
Confluent Go请访问github.com/confluentin…。
注意 如果无法在短期内替换客户端,请注意以下事项:
- 针对生产环境,请将位点重置策略设置为
Newest(latest);针对测试环境,或者其他明确可以接收大量重复消息的场景,设置为Oldest(earliest)。 - 如果发生了位点重置,产生大量堆积,您可以使用消息队列Kafka版控制台提供的重置消费位点功能,手动重置消费位点到某一时间点,无需改代码或换Consumer Group。具体操作,