go资深之路笔记(九)kafka浅析

一、作用

kafka 是一个消息队列,但不止是一个消息队列,他是一个分布式流式平台;

其实 go可选择的消息队列工具不止一个他们的适用场景各有不同,如果需要高吞吐量的话可以优先考虑,下面是ai给出的讲解:

二、confluent-kafka-go 客户端:

go的客户端库有多个,这里只讲 confluent-kafka-go

首先说下 他的api:

go 复制代码
// 生产者api
func NewProducer(conf *ConfigMap) (*Producer, error) // 创建
func (p *Producer) Produce(msg *Message, deliveryChan chan Event) error // 发送消息
func (p *Producer) Events() chan Event // 获取生产者事件(比如发送完成后回调)
func (p *Producer) Flush(timeoutMs int) int // 确保所有消息发送完成

// 消费者api
func NewConsumer(conf *ConfigMap) (*Consumer, error) 	// 创建
func (c *Consumer) SubscribeTopics(topics []string, rebalanceCb RebalanceCb) (err error)	// 订阅主题
func (c *Consumer) Poll(timeoutMs int) (event Event) 	// 拉取信息
func (c *Consumer) CommitMessage(m *Message) ([]TopicPartition, error)	//提交偏移量(告诉服务端消息已经处理了,这个最好手动,不然默认提交的话失败了就丢失了)

// 结构体
type ConfigMap map[string]ConfigValue			// 配置

type Message struct { // 消息
	TopicPartition TopicPartition
	Value          []byte
	Key            []byte
	Timestamp      time.Time
	TimestampType  TimestampType
	Opaque         interface{}
	Headers        []Header
}

type TopicPartition struct {		// 主题分区信息
	Topic     *string
	Partition int32
	Offset    Offset
	Metadata  *string
	Error     error
}

三、实战:

3.1 docker kafka服务器创建

docker-compose.yml

go 复制代码
	version: '3'
    services:
      zookeeper:
        image: wurstmeister/zookeeper
        ports:
          - "2181:2181"

      kafka:
        image: wurstmeister/kafka
        ports:
          - "9092:9092"
        environment:
          KAFKA_ADVERTISED_HOST_NAME: localhost
          KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
          KAFKA_CREATE_TOPICS: "test_topic:1:1"
        depends_on:
          - zookeeper

3.2 启动

bash 复制代码
 docker-compose up -d

3.3 修改配置:

ps:如果服务器和客户端都在本地运行不用改也行

bash 复制代码
# 进入容器内部
 docker-compose exec kafka bash

# 看 kafka的配置在哪个目录
  ls -l /etc/kafka/
  ls -l /opt/kafka/
 # 我的在 /opt/kafka/  | 打开 server.properties配置
 vim /opt/kafka/config/server.properties
 # 修改配置参数:
 listeners=PLAINTEXT://0.0.0.0:9092
 advertised.listeners=PLAINTEXT://你的公网IP:9092
 #保存退出
 ## 重启生效:
 docker-compose restart kafka 

3.4 生产者代码

confluent-kafka.go

go 复制代码
package main

import (
	"fmt"
	"log"
	"time"

	"github.com/confluentinc/confluent-kafka-go/kafka"
)

func main() {
	// 生产者配置 :cite[4]
	config := &kafka.ConfigMap{
		"bootstrap.servers": "配置填写的ip:9092", // Kafka broker地址  !!! todo 注意改成自己的ip
		// 如需SASL认证(如连接云服务),取消下面注释 :cite[4]:cite[6]
		// "security.protocol": "SASL_PLAINTEXT",
		// "sasl.mechanism":    "PLAIN",
		// "sasl.username":     "your_username",
		// "sasl.password":     "your_password",
		"acks":               -1,   // 等待所有副本确认,保证数据不丢失
		"retries":            3,    // 失败重试次数
		"retry.backoff.ms":   1000, // 重试间隔
		"enable.idempotence": true, // 启用幂等性,避免重复消息
	}

	// 创建生产者
	producer, err := kafka.NewProducer(config)
	if err != nil {
		log.Fatalf("Error creating producer: %v", err)
	}
	defer producer.Close()

	// 监听消息传递结果
	go func() {
		for e := range producer.Events() {
			switch ev := e.(type) {
			case *kafka.Message:
				if ev.TopicPartition.Error != nil {
					fmt.Printf("Delivery failed: %v\n", ev.TopicPartition)
				} else {
					fmt.Printf("Delivered message to %v, key: %s\n",
						ev.TopicPartition, string(ev.Key))
				}
			}
		}
	}()

	// 发送消息
	topic := "test_topic"
	for i := 0; i < 10; i++ {
		key := fmt.Sprintf("key-%d", i)
		value := fmt.Sprintf("Hello Kafka! %s", time.Now().Format("15:04:05"))

		err = producer.Produce(&kafka.Message{
			TopicPartition: kafka.TopicPartition{
				Topic:     &topic,
				Partition: kafka.PartitionAny,
			},
			Key:   []byte(key),
			Value: []byte(value),
		}, nil)

		if err != nil {
			log.Printf("Produce error: %v", err)
		}

		time.Sleep(time.Second)
	}

	// 等待所有消息发送完成
	producer.Flush(15 * 1000)
	fmt.Println("All messages sent")
}

运行后:

3.5 消费者代码

go 复制代码
package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/confluentinc/confluent-kafka-go/kafka"
)

func main() {
	// 消费者配置 :cite[6]
	config := &kafka.ConfigMap{
		"bootstrap.servers": "配置填写的ip:9092", // Kafka broker地址  !!! todo 注意改成自己的ip
		// 如需SASL认证(如连接云服务),取消下面注释 :cite[4]:cite[6]
		// "security.protocol": "SASL_SSL",
		// "sasl.mechanism":    "PLAIN",
		// "sasl.username":     "your_username",
		// "sasl.password":     "your_password",
		"group.id":                 "test_consumer_group", // 消费组ID
		"auto.offset.reset":        "earliest",            // 从最早的消息开始消费
		"enable.auto.commit":       false,                 // 手动提交偏移量
		"enable.auto.offset.store": false,                 // 手动存储偏移量
		"max.poll.interval.ms":     300000,                // 最大poll间隔
		"session.timeout.ms":       10000,                 // 会话超时
	}

	// 创建消费者
	consumer, err := kafka.NewConsumer(config)
	if err != nil {
		log.Fatalf("Error creating consumer: %v", err)
	}
	defer consumer.Close()

	// 订阅主题
	err = consumer.SubscribeTopics([]string{"test_topic"}, nil)
	if err != nil {
		log.Fatalf("Subscribe error: %v", err)
	}

	// 处理中断信号
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM)

	// 消费消息
	run := true
	for run {
		select {
		case sig := <-sigchan:
			fmt.Printf("Caught signal %v: terminating\n", sig)
			run = false
		default:
			// 轮询消息,超时时间100ms
			event := consumer.Poll(100)
			if event == nil {
				continue
			}

			switch e := event.(type) {
			case *kafka.Message:
				fmt.Printf("Received message: %s (key: %s) [%s] at offset %v\n",
					string(e.Value), string(e.Key), e.TopicPartition, e.TopicPartition.Offset)

				// 处理业务逻辑...

				// 手动提交偏移量
				_, err := consumer.CommitMessage(e)
				if err != nil {
					fmt.Printf("Commit error: %v\n", err)
				}
			case kafka.Error:
				fmt.Printf("Error: %v\n", e)
				if e.Code() == kafka.ErrAllBrokersDown {
					run = false
				}
			default:
				// 忽略其他事件
			}
		}
	}
}

运行后截图:

最后:这里只讲 kafka的基本适合用,至于更深层的原理和部署细节以及技巧之后在写,留个位~

相关推荐
Yeats_Liao3 小时前
Go Web 编程快速入门 02 - 认识 net/http 与 Handler 接口
前端·http·golang
千码君20163 小时前
Go语言:关于导包的两个重要说明
开发语言·后端·golang·package·导包
云小逸3 小时前
【Win32 多线程程序设计基础第六章笔记】
笔记
埃泽漫笔4 小时前
Kafka、ActiveMQ、RabbitMQ、RocketMQ 对比
kafka·rabbitmq·activemq
摇滚侠4 小时前
Spring Boot 3零基础教程,WEB 开发 默认的自动配置,笔记25
前端·spring boot·笔记
报错小能手4 小时前
linux学习笔记(35)C语言连接mysql
linux·笔记·学习
_dindong5 小时前
笔试强训:Week -2
笔记·学习·算法
雾岛听蓝6 小时前
深入解析内存中的整数与浮点数存储
c语言·经验分享·笔记·visualstudio
jimmyleeee6 小时前
人工智能基础知识笔记十八:Prompt Engineering
笔记·prompt