Golang kafka

文章目录

    • kafka
    • 分区和消费者对应关系
    • offset的提交
    • Golang Kafka 第三方库
    • 实验

kafka

Apache-Kafka 消息队列。传送门

分区和消费者对应关系

1.一个组内的每一个消费者对应一个topic的一个分区。分区数即是最大消费者的数量。每当多余的消费者加入消费,会造成rebalance。比如:如果只有一个分区,并且已经有一个消费者在消费这个分区了,但是又重新加入了一个消费者,那么就会造成rebalance,两个消费者会抢分区,谁抢到谁消费。
2.一个组内的每一个消费者如果订阅了多个topic,同时会收到多个topic的信息。
3.往拥有多分区的topic里面写消息的话,消息会被均分到不同的分区,如果多个分区只有一个消费者的话,这个消费者全吃分区所有消息。

offset的提交

在使用第三方库的时候,一般都是有High-Level的API和Low-Level的API,High-Level API一般都会把一些工作帮你做好,但是如果需要引入错误处理,超时处理等类似的条件的时候,我们就需要手动来管理消息的消费,主要是对于offset的更新,设想如果队列里面的一个消息处理失败,程序崩溃掉了,并且提交了(At Most Once),那么这条消息之后就不会再次被处理了,所以我们在把程序修改重启之后,需要重新处理这条消息。这样就有两种方式:
1.记录这个出错的消息所在的分区+offset+topic,消息的处理可能需要人工的介入。
2.修改程序之后,再通过程序自动去处理这个出错的消息。

对于第一种情况:可能是一次性从消息队列里面取了N条消息,但是第M条消息处理出错了(1 ≤ M ≤ N),我们不可能把offset提交到M-1,这样后面的N-M消息就重复处理了,这种情况下,我能想到的处理方法就只能把三元组记录下来。
对于第二种情况:应该是一条一条地取消息,出错了重新取这条消息来处理,其实这种方法也不太好,还是把错误三元组记录下来人工介入要好得多。

Golang Kafka 第三方库

使用bsm/sarama-cluster这个库。比较好一些,可以手动地提交分区的offset。下面是官方例子:

package main

import (
    "fmt"
    _ "context"
    "github.com/bsm/sarama-cluster"
)

func main() {
    config := cluster.NewConfig()
    config.Consumer.Return.Errors = true
    config.Group.Return.Notifications = true

    brokers := []string{"localhost:9092"}
    topics := []string{"greetlist_test"}
    consumer, err := cluster.NewConsumer(brokers, "greetlist", topics, config)
    if err != nil {
        panic(err)
    }   

    defer consumer.Close()

    go func() {
        for err := range consumer.Errors() {
            fmt.Printf("The err is : %v.\n", err)
        }   
    }() 
    go func() {
        for ntf := range consumer.Notifications() {
            fmt.Printf("The ntf is : %v.\n", ntf)
        }   
    }() 

    for {
        select {
        case msg, ok := <-consumer.Messages():
            if ok {
                fmt.Printf("topic is : %v, offset is : %v, value is : %v.\n", msg.Topic, msg.Offset, string(msg.Value))
                cosumer.MarkOffset(msg, "")
                if err := consumer.CommitOffsets(); err != nil {
                	panic(err)
                }
            }   
        }   
    }   
}

上面从consumer.Message() Channel里面读取offset的消息,本地的offset+1,但是不会提交offset到kafka,需要调用MarkOffset和CommitOffsets手动去提交offset,这样才能把offset更新到kafka。

实验

我新建了greetlist_test 这个topic,一个分区,一个备份:
在这里插入图片描述
可以看到在kafka上面存的offset已经是31了,意味着消费者会从31的offset开始读取数据:
Golang kafka_第1张图片
可以看到,消费者的确是从offset为31 开始消费消息的。
现在我们把手动提交offset的代码改成下面:

if string(msg.value) == "26" {
	consumer.MarkOffset(msg, "")
	if err := consumer.CommitOffsets(); err != nil {
		panic(err)
	} else {
		fmt.Printf("Commit offset.\n")
	}
}

那么会出现offset为36之前的消息,下次都不能被读取了。我们执行一次程序:
Golang kafka_第2张图片
在这里插入图片描述
再次执行程序:
Golang kafka_第3张图片
可以看到kafka上面的offset已经更新到了36,代表下一条消息是从36开始消费。但是之前的31-35offset的消息就不能再次消费了。
如果31-35之间的消息出错了怎么办,那么记下来手动处理。当然上面的例子也是一条一条记录取的,等我先找到能一次性取多条消息的API再更新文章。

你可能感兴趣的:(Golang,工具)