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的基本适合用,至于更深层的原理和部署细节以及技巧之后在写,留个位~

相关推荐
代码游侠8 小时前
学习笔记——进程控制函数
linux·运维·笔记·学习·算法
yumgpkpm8 小时前
hadoop集群搭建 (超详细) 接入Impala、Hive,AI 大模型的数据底座
hive·hadoop·mysql·zookeeper·flink·kafka·hbase
nbsaas-boot8 小时前
Java 还是 Go?——从工程规模到长期演进的技术选型思考
java·开发语言·golang
其美杰布-富贵-李8 小时前
循环神经网络(RNN)深度学习笔记
笔记·rnn·深度学习
想搞艺术的程序员8 小时前
Go语言环形队列:原理剖析、编程技巧与核心优势
后端·缓存·golang
资深web全栈开发8 小时前
Golang 最常用的库介绍
开发语言·后端·golang
代码游侠8 小时前
应用--Minishell实现
linux·运维·笔记·学习·算法
音符犹如代码8 小时前
Kafka 技术架构与核心原理深度解析
大数据·微服务·架构·kafka
zore_c9 小时前
【C语言】Win 32 API——一部分内容详解!!!
c语言·开发语言·c++·经验分享·笔记
重生之我在番茄自学网安拯救世界9 小时前
网络安全中级阶段学习笔记(七):Web 安全之文件上传漏洞笔记1(包含upload-labs-master靶场前三关实战)
笔记·学习·web安全·文件上传漏洞·网安基础