使用 kafka-go实现生产者和消费者

快速使用 Kafka

Kafka 依赖 Java 运行时环境,因此在启动 Kafka 或 ZooKeeper 之前,确保你的系统上已经安装了 Java。
通过以下步骤安装 OpenJDK:

  1. 更新包信息:sudo apt update
  2. 安装 OpenJDK:sudo apt install default-jdk
    这将安装默认版本的 OpenJDK。如果你需要特定版本的 OpenJDK,可以使用相应的软件包名称。
  3. 安装完成后,验证 Java 安装是否成功:java -version
  4. 重新运行 ZooKeeper 或 Kafka 命令。

步骤1:安装 Kafka

  1. 下载 Kafka: 前往 Apache Kafka 官方网站 下载最新的 Kafka 版本。

  2. 解压文件: 解压下载的 Kafka 压缩包到你选择的目录。

    tar -xzf kafka_2.12-3.6.0.tgz
    
    • -x: 表示解压缩。
    • -z: 表示使用 gzip 解压。
    • -f: 后面跟着压缩包的文件名。
  3. 启动 ZooKeeper: Kafka 依赖于 ZooKeeper,因此在启动 Kafka 之前,需要先启动 ZooKeeper。进入 Kafka 解压目录中的 bin 目录,执行以下命令启动 ZooKeeper:

    ./zookeeper-server-start.sh ../config/zookeeper.properties
    
  4. 启动 Kafka 服务器: 打开一个新的终端,进入 Kafka 解压目录中的 bin 目录,执行以下命令启动 Kafka 服务器:

    ./kafka-server-start.sh ../config/server.properties
    

步骤2:创建一个主题(Topic)

在 Kafka 中,数据被发布到主题(Topic)中,消费者订阅这些主题以接收数据。

  1. 创建一个主题: 打开一个新的终端,进入 Kafka 解压目录中的 bin 目录,执行以下命令创建一个名为 my-topic 的主题:
    ./kafka-topics.sh --create --topic my-topic --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1
    
    • --topic my-topic 指定创建的主题的名称为 “my-topic”。
    • --bootstrap-server localhost:9092 指定用于创建主题的 Kafka 集群的引导服务器地址。
    • --partitions 1 指定创建的主题将包含的分区数量。分区是 Kafka 中消息并行处理的单位。在这里,指定的分区数量是1,表示该主题只有一个分区。分区数量的选择通常取决于并行性需求和消息负载的分布。
    • --replication-factor 1 指定每个分区的副本数量。在这里,指定的副本数量是1,表示每个分区只有一个副本。副本用于提高数据的可靠性和容错性。如果有多个副本,数据会在多个 broker 上进行复制。通常,你会希望设置大于1的副本数量,以确保数据的可靠性。

步骤3:生产者发送消息

在 Kafka 中,生产者负责将消息发布到主题。

  1. 启动生产者: 打开一个新的终端,进入 Kafka 解压目录中的 bin 目录,执行以下命令启动一个生产者:

    ./kafka-console-producer.sh --topic my-topic --bootstrap-server localhost:9092
    
  2. 发送消息: 在生产者终端中,输入一些消息并按回车键发送。

步骤4:消费者接收消息

在 Kafka 中,消费者订阅主题以接收生产者发送的消息。

  1. 启动消费者: 打开一个新的终端,进入 Kafka 解压目录中的 bin 目录,执行以下命令启动一个消费者:

    ./kafka-console-consumer.sh --topic my-topic --bootstrap-server localhost:9092 --from-beginning
    
    • --from-beginning
  2. 接收消息: 在消费者终端中,你将看到生产者发送的消息。

使用 kafka-go 实现生产者和消费者示例代码

github代码

生产者

package main
// ./kafka-console-producer.sh --topic my-topic --bootstrap-server localhost:9092
import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/segmentio/kafka-go"
)

var (
	reader *kafka.Reader
	topic  = "user_click"
)

func Write(ctx context.Context) {
    
    
	writer := &kafka.Writer{
    
    
		Addr:                   kafka.TCP("localhost:9092"),
		Topic:                  topic,
		Balancer:               &kafka.Hash{
    
    },
		WriteTimeout:           1 * time.Second,
		RequiredAcks:           kafka.RequireNone,
		AllowAutoTopicCreation: true,
	}
	defer writer.Close()

	tm := time.Now().Unix()
	for i := 0; i < 3; i++ {
    
    
		if err := writer.WriteMessages(
			ctx,
			kafka.Message{
    
    Key: []byte("1"), Value: []byte("小" + strconv.Itoa(int(tm)))},
			kafka.Message{
    
    Key: []byte("2"), Value: []byte("白" + strconv.Itoa(int(tm)))},
			kafka.Message{
    
    Key: []byte("3"), Value: []byte("小" + strconv.Itoa(int(tm)))},
			kafka.Message{
    
    Key: []byte("1"), Value: []byte("熊" + strconv.Itoa(int(tm)))},
			kafka.Message{
    
    Key: []byte("1"), Value: []byte("猫" + strconv.Itoa(int(tm)))},
		); err != nil {
    
    
			if err == kafka.LeaderNotAvailable {
    
    
				time.Sleep(500 * time.Millisecond)
				continue
			} else {
    
    
				fmt.Println("批量写kafka失败:%v \n", err)
			}
		} else {
    
    
			break
		}
	}
}

func main() {
    
    
	ctx := context.Background()
	Write(ctx)
}

消费者

package main
// ./kafka-console-consumer.sh --topic user_click --bootstrap-server localhost:9092 --from-beginning --group a
import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/segmentio/kafka-go"
)

var (
	reader *kafka.Reader
	topic  = "user_click"
)

func read(ctx context.Context) {
    
    
	reader := kafka.NewReader(kafka.ReaderConfig{
    
    
		Brokers:        []string{
    
    "localhost:9092"},
		Topic:          topic,
		CommitInterval: 1 * time.Second,
		GroupID:        "rec_team",
		StartOffset:    kafka.FirstOffset,
	})

	for {
    
    
		if message, err := reader.ReadMessage(ctx); err != nil {
    
    
			fmt.Println("读kafka失败: ", err)
			break
		} else {
    
    
			fmt.Printf("topic=%s, partition=%d, offset=%d, key=%s, value=%s \n", message.Topic, message.Partition, message.Offset, string(message.Key), string(message.Value))
		}
	}
}

func listenSignal() {
    
    
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	sig := <-c
	fmt.Println("接收到信号: ", sig.String())
	if reader != nil {
    
    
		reader.Close()
	}
	os.Exit(0)
}

func main() {
    
    
	ctx := context.Background()
	go listenSignal()
	read(ctx)
}

猜你喜欢

转载自blog.csdn.net/trinityleo5/article/details/134495659