Kafka-GO 在实际业务下的使用

2,520 阅读3分钟

Kafka-GO 在实际业务下的使用

简介

Kafka-GO是一款基于Go语言的轻量级Kafka SDK,目前已有stars个Star数。
对比saramaconfluent-kafka-go无论是在文档还是使用简单程度上都有着不小的优势。
易用性特别重要,如今现成的轮子实在太多了!最好是几行代码就能轻松使用,而不是必须要读完老长的一份文档,再写个几十行代码才能生效。就和产品说明书一样,太复杂会直接把人劝退。这也是我这次选用 Kafka-GO的原因之一。

什么是Kafka

用简单通俗的话来说就是一个高可靠性的消息列队。
主要通过“生产者”(Producer)来生产数据发送到不同的“Topic”下,再由“消费者”(Consumer)对其进行消费。
Kafka运行在一个由一台或多台服务器组成的集群上,并且分区可以跨集群结点分布,这也说明Kafka有着极高的可扩展性。

背景

在实际业务中,我们团队需要通过Kafka来获取和CP公司约定好格式的数据,在经过几个基于Go语言的Kafka SDK考察后,最后我们决定使用Kafka-GO来接入Kafka,主要看重的就是它的轻量化与简介的代码实现。
由于我们这次的业务流程只涉及到读取数据,所以不会基于写入做过多展开。

数据的读取

默认情况下使用ReadMessage来读取数据,Kafka会更具GroupID来自动标记offset位置,保证消耗的消息不会重复发送。

// make a new reader that consumes from topic-A
r := kafka.NewReader(kafka.ReaderConfig{
    Brokers:   []string{"localhost:9092"},
    GroupID:   "consumer-group-id",
    Topic:     "topic-A",
    MinBytes:  10e3, // 10KB
    MaxBytes:  10e6, // 10MB
})

for {
    m, err := r.ReadMessage(context.Background())
    if err != nil {
        break
    }
    fmt.Printf("message at topic/partition/offset %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)
}

当然你也可以手动指定Partition区域和设定SetOffset来获取特定的数据

// make a new reader that consumes from topic-A, partition 0, at offset 42
r := kafka.NewReader(kafka.ReaderConfig{
    Brokers:   []string{"localhost:9092"},
    Topic:     "topic-A",
    Partition: 0,
    MinBytes:  10e3, // 10KB
    MaxBytes:  10e6, // 10MB
})
r.SetOffset(42)

for {
    m, err := r.ReadMessage(context.Background())
    if err != nil {
        break
    }
    fmt.Printf("message at offset %d: %s = %s\n", m.Offset, string(m.Key), string(m.Value))
}

if err := r.Close(); err != nil {
    log.Fatal("failed to close reader:", err)
}

实际业务场景

但是在我们的数据业务场景下,很多时候需要我们对数据进行写入至数据库中,在写入数据的时候有可能因为各种原因导致error的出现,那么有没有什么办法可以保证我们的数据被正确储存之后再提交消耗吗?

答案是肯定的。

ctx := context.Background()
for {
    m, err := r.FetchMessage(ctx)
    if err != nil {
        break
    }
    fmt.Printf("message at topic/partition/offset %v/%v/%v: %s = %s\n", m.Topic, m.Partition, m.Offset, string(m.Key), string(m.Value))
    if err := r.CommitMessages(ctx, m); err != nil {
        log.Fatal("failed to commit messages:", err)
    }
}

通过先查询数据,在提交Commit的方式就可以实现自由的控制

身份验证

Kafka-GO也支持Plain以及SCRAM的验证方式,感兴趣的同学可以去看一下

踩坑

  1. 正如Kafka-GO展示代码一样,它是一个单线程的读取,如果需要实现并行读取,则需要自己实现一个Jobs列队来控制并行读取。
  2. 在使用ReadMessageCommitMessages的时候,会有一个性能的消耗,以至于读取下一条信息的速度不会特别快,如果追求极致性能的时候可以只FetchMessageCommitMessages,但是这样做的坏处就是如果停机再读取的时候会从头开始读取数据。

结尾

第一次使用并总结Kafka-GO的相关内容,如有错误还请多多指出,多多包含,感谢大家看到这里,谢谢。