上周分享了如何使用go来对kafka进行生产和消费,这周接着对kafka消息队列的一些特性来进行使用。
上次讲到kafka有个consumer group的概念,而我们使用的sarama并没有支持,所以这次引入sarama-cluster项目 : go get “github.com/bsm/sarama-cluster”
producer的代码不变,参考上一篇文章,consumer的代码改为如下:
import KafkaCluster "github.com/bsm/sarama-cluster"
func KafkaConsumerCluster(consumerId string) {
brokers := []string{"182.61.9.153:6667","182.61.9.154:6667","182.61.9.155:6667"}
topics := []string{"0612_test"}
config := KafkaCluster.NewConfig()
config.Consumer.Return.Errors = true
config.Consumer.Offsets.CommitInterval=1*time.Second
config.Consumer.Offsets.Initial=sarama.OffsetNewest
config.Group.Return.Notifications = true
//第二个参数是groupId
consumer, err := KafkaCluster.NewConsumer(brokers, "consumer-group1", topics, config)
if err != nil {
panic(err)
}
defer consumer.Close()
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
// 接收错误
go func() {
for err := range consumer.Errors() {
log.Printf("Error: %s\n", err.Error())
}
}()
// 打印一些rebalance的信息
go func() {
for ntf := range consumer.Notifications() {
log.Printf("Rebalanced: %+v\n", ntf)
}
}()
// 消费消息
for {
select {
case msg, ok := <-consumer.Messages():
if ok {
fmt.Fprintf(os.Stdout, "%s : %s/%d/%d\t%s\t%s\n", consumerId,msg.Topic, msg.Partition, msg.Offset, msg.Key, msg.Value)
consumer.MarkOffset(msg, "") // 提交offset
}
case <-signals:
return
}
}
}
如果需要多个consumer去消费同一个topic,可以多次调用KafkaCluster.NewConsumer(brokers, "consumer-group1", topics, config)
来新建consumer,注意第二个参数是groupId,同一个group的consumer,它们的groupId必须相同。如果新建了另一个group,则可以重复消费topic的数据,是不是有点发布订阅的味道。
同一个group的consumer,kafka会均衡的为每个consumer分配partition,并遵循策略从partition中弹出消息给之前分配好的consumer,每个partition每次只能有一个consumer进行消费,所以consumer的数量应该小于partition数量。
func GetKafkaPartitionOffset() {
config2 := sarama.NewConfig()
config2.Consumer.Offsets.CommitInterval = 1 * time.Second
config2.Version = sarama.V0_10_0_1
brokers := []string{"182.61.9.153:6667","182.61.9.154:6667","182.61.9.155:6667"}
//topics := []string{"0612_test"}
client, err := sarama.NewClient(brokers, config2)
if err != nil {
panic("client create error")
}
defer client.Close()
//有个要注意的地方,如果想获取某个partition的offset位置,需要这个offsetManager的groupId和consumer的一致,否则拿到的offset是不正确的。
offsetManager,err:=sarama.NewOffsetManagerFromClient("consumer-group1",client)
if err != nil {
panic("offsetManager create error")
}
defer offsetManager.Close()
partitionOffsetManager,err:=offsetManager.ManagePartition("0612_test",14)
if err != nil {
panic("partitionOffsetManager create error")
}
defer partitionOffsetManager.Close()
nextOffset,_:=partitionOffsetManager.NextOffset()
fmt.Println("nextOffset:",nextOffset)
}
这个是获取某个consumer group对应的某个分区的offset位置