与卡夫卡消费者一起去频道

时间:2018-05-11 22:31:53

标签: go apache-kafka

我是新手,开始学习频道。我正在使用融合的kafka消费者来创建一个功能性消费者。我想要完成的是将消息发送到缓冲通道(2,000)...然后使用管道将通道中的消息写入redis。通过逐个消息println直到它到达抵消结束,我已经得到了消费者的工作,但是当我尝试添加一个频道时,它似乎达到{{1在default:中的情况,然后冻结。

它看起来也不像我正确地填充了频道?此switch始终打印fmt.Println("count is: ", len(redisChnl))

这是我到目前为止所做的:

0

------- ------- EDIT

好的,我想通过移动// Example function-based high-level Apache Kafka consumer package main import ( "fmt" "github.com/confluentinc/confluent-kafka-go/kafka" "os" "os/signal" "syscall" "time" "encoding/json" "regexp" "github.com/go-redis/redis" "encoding/binary" ) var client *redis.Client func init() { client = redis.NewClient(&redis.Options{ Addr: ":6379", DialTimeout: 10 * time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, PoolSize: 10, PoolTimeout: 30 * time.Second, }) client.FlushDB() } type MessageFormat struct { MetricValueNumber float64 `json:"metric_value_number"` Path string `json:"path"` Cluster string `json:"cluster"` Timestamp time.Time `json:"@timestamp"` Version string `json:"@version"` Host string `json:"host"` MetricPath string `json:"metric_path"` Type string `json:"string"` Region string `json:"region"` } //func redis_pipeline(ky string, vl string) { // pipe := client.Pipeline() // // exec := pipe.Set(ky, vl, time.Hour) // // incr := pipe.Incr("pipeline_counter") // pipe.Expire("pipeline_counter", time.Hour) // // // Execute // // // // INCR pipeline_counter // // EXPIRE pipeline_counts 3600 // // // // using one client-server roundtrip. // _, err := pipe.Exec() // fmt.Println(incr.Val(), err) // // Output: 1 <nil> //} func main() { sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) c, err := kafka.NewConsumer(&kafka.ConfigMap{ "bootstrap.servers": "kafka.com:9093", "group.id": "testehb", "security.protocol": "ssl", "ssl.key.location": "/Users/key.key", "ssl.certificate.location": "/Users/cert.cert", "ssl.ca.location": "/Users/ca.pem", }) if err != nil { fmt.Fprintf(os.Stderr, "Failed to create consumer: %s\n", err) os.Exit(1) } fmt.Printf("Created Consumer %v\n", c) err = c.SubscribeTopics([]string{"jmx"}, nil) redisMap := make(map[string]string) redisChnl := make(chan []byte, 2000) run := true for run == true { select { case sig := <-sigchan: fmt.Printf("Caught signal %v: terminating\n", sig) run = false default: ev := c.Poll(100) if ev == nil { continue } switch e := ev.(type) { case *kafka.Message: //fmt.Printf("%% Message on %s:\n%s\n", // e.TopicPartition, string(e.Value)) if e.Headers != nil { fmt.Printf("%% Headers: %v\n", e.Headers) } str := e.Value res := MessageFormat{} json.Unmarshal([]byte(str), &res) fmt.Println("size", binary.Size([]byte(str))) host:= regexp.MustCompile(`^([^.]+)`).FindString(res.MetricPath) redisMap[host] = string(str) fmt.Println("count is: ", len(redisChnl)) //this always prints "count is: 0" redisChnl <- e.Value //I think this is the write way to put the messages in the channel? case kafka.PartitionEOF: fmt.Printf("%% Reached %v\n", e) case kafka.Error: fmt.Fprintf(os.Stderr, "%% Error: %v\n", e) run = false default: fmt.Printf("Ignored %v\n", e) } <- redisChnl // I thought I could just empty the channel like this once the buffer is full? } } fmt.Printf("Closing consumer\n") c.Close() } 内的<- redisChnl来实现它,但现在我看到default内的count before readcount after read总是打印default ...我会想到第一个2,000然后count before read = 2,000因为通道会是空的然后??

count after read = 0

1 个答案:

答案 0 :(得分:0)

我认为简化此代码的更大方法是将管道分成多个goroutine。

渠道的优势在于多人可以同时书写和阅读。在这个例子中,这可能意味着只有一个go例程入列到通道上,另一个例程就是关闭通道并将事物放入redis中。

这样的事情:

c := make(chan Message, bufferLen)
go pollKafka(c)
go pushToRedis(c)

如果要添加批处理,可以添加一个从kafka通道轮询的中间阶段,并附加到切片直到切片已满,然后将该切片排入通道以进行redis。

如果这样的并发不是目标,那么用代码替换代码中的通道可能更容易。如果只有1个goroutine作用于一个物体,那么尝试使用一个频道并不是一个好主意。