golang结合Kafka消息队列实践(二)

上周分享了如何使用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位置

你可能感兴趣的:(消息队列)