Kafka の基本 — 2. Kafka プロデューサー API

Kafka ナレッジ ベース - インデックス ディレクトリ

1.KafkaプロデューサーAPI

1. メッセージを送信する

Go 言語で Kafka プロデューサー API を使用するには、まず Kafka の Go クライアント ライブラリが必要です。

一般的に使用されるライブラリには、sarama または confluent-kafka-go などがあります。

sarama は Go 言語の Kafka クライアント ライブラリであり、Kafka と統合し、Kafka プロデューサーとコンシューマーの機能を実装するために使用されます。

ここでは sarama を使用して簡単な例を見てみましょう。手順は次のとおりです。

ステップ 1: Sarama ライブラリをインストールする

go get github.com/Shopify/sarama

ステップ 2: プロデューサー コードを作成する

package main

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

	"github.com/Shopify/sarama"
)

func main() {
    
    
	// 设置 Kafka broker 地址,创建配置
	config := sarama.NewConfig()
	config.Producer.RequiredAcks = sarama.WaitForAll
	config.Producer.Retry.Max = 5
	config.Producer.Return.Successes = true

	// 创建生产者
	producer, err := sarama.NewSyncProducer([]string{
    
    "kafka-broker1:9092", "kafka-broker2:9092"}, config)
	if err != nil {
    
    
		log.Fatalf("Error creating producer: %s", err.Error())
	}
	defer func() {
    
    
		if err := producer.Close(); err != nil {
    
    
			log.Fatalf("Error closing producer: %s", err.Error())
		}
	}()

	// 构造消息
	message := &sarama.ProducerMessage{
    
    
		Topic: "your_topic", // 设置消息发送到的主题
		Value: sarama.StringEncoder("Hello, Kafka!"), // 设置消息内容
	}

	// 发送消息
	partition, offset, err := producer.SendMessage(message)
	if err != nil {
    
    
		log.Fatalf("Failed to send message: %s", err.Error())
	}

	fmt.Printf("Message sent to partition %d at offset %d\n", partition, offset)

	// 处理退出信号
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	<-sigchan
}

コードの説明

  1. saramaライブラリを導入し、Kafkaの接続構成を設定します。
  2. プロデューサー インスタンスを作成します。
  3. Kafka トピックに送信するメッセージを作成します。
  4. プロデューサのメソッドを使用してSendMessageメッセージを送信します。
  5. 送信が成功した後、パーティションとオフセットを処理します。
  6. 信号処理を設定し、プログラムを閉じる割り込み信号を待ちます。

2. メッセージの圧縮

Kafka プロデューサー API でのメッセージ圧縮について話すときは、ネットワーク上で送信されるデータ量を削減し、送信効率を向上させるために、Kafka に送信する前にメッセージを圧縮することを指します。

Kafka は、GZIP、Snappy、LZ4 などの複数のメッセージ圧縮アルゴリズムを提供します。

ステップ 1: Sarama ライブラリをインポートする

まず、Sarama ライブラリがインストールされていることを確認します。これは、次のコマンドを使用してインストールできます。

go get github.com/Shopify/sarama

ステップ 2: メッセージ圧縮コードを作成する

package main

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

	"github.com/Shopify/sarama"
)

func main() {
    
    
	// 设置 Kafka broker 地址,创建配置
	config := sarama.NewConfig()
	config.Producer.RequiredAcks = sarama.WaitForAll
	config.Producer.Retry.Max = 5
	config.Producer.Return.Successes = true
	config.Producer.Compression = sarama.CompressionGZIP // 设置消息压缩算法

	// 创建生产者
	producer, err := sarama.NewSyncProducer([]string{
    
    "kafka-broker1:9092", "kafka-broker2:9092"}, config)
	if err != nil {
    
    
		log.Fatalf("Error creating producer: %s", err.Error())
	}
	defer func() {
    
    
		if err := producer.Close(); err != nil {
    
    
			log.Fatalf("Error closing producer: %s", err.Error())
		}
	}()

	// 构造消息
	message := &sarama.ProducerMessage{
    
    
		Topic: "your_topic",                          // 设置消息发送到的主题
		Value: sarama.StringEncoder("Hello, Kafka!"), // 设置消息内容
	}

	// 发送消息
	partition, offset, err := producer.SendMessage(message)
	if err != nil {
    
    
		log.Fatalf("Failed to send message: %s", err.Error())
	}

	fmt.Printf("Message sent to partition %d at offset %d\n", partition, offset)

	// 处理退出信号
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	<-sigchan
}

ステップ 3: コードを説明する

この例では、Kafka プロデューサの作成時にメッセージ圧縮アルゴリズムを設定します。

config.Producer.Compression = sarama.CompressionGZIP // 设置消息压缩算法

ここでは GZIP 圧縮アルゴリズムを選択しましたが、Snappy や LZ4 などの他のアルゴリズムを選択することもできます。

圧縮アルゴリズムが設定されると、プロデューサーによって送信されるメッセージは、ネットワーク上で送信されるデータ量を削減するために、送信前に圧縮されます。

Kafka コンシューマはメッセージを受信した後に自動的に解凍するため、圧縮はコンシューマにとって透過的です。

3. プロデューサーの設定

ステップ 1: Sarama ライブラリをインポートする

まず、Sarama ライブラリがインストールされていることを確認します。これは、次のコマンドを使用してインストールできます。

go get github.com/Shopify/sarama

ステップ 2: プロデューサー構成コードを作成する

package main

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

	"github.com/Shopify/sarama"
)

func main() {
    
    
	// 创建配置
	config := sarama.NewConfig()

	// 设置生产者参数
	config.Producer.RequiredAcks = sarama.WaitForAll      // 设置等待所有副本确认消息
	config.Producer.Retry.Max = 5                          // 设置最大的重试次数
	config.Producer.Return.Successes = true                // 设置是否返回成功的消息
	config.Producer.Compression = sarama.CompressionGZIP   // 设置消息压缩算法
	config.Producer.Partitioner = sarama.NewRandomPartitioner // 设置分区策略为随机分区

	// 创建生产者
	producer, err := sarama.NewSyncProducer([]string{
    
    "kafka-broker1:9092", "kafka-broker2:9092"}, config)
	if err != nil {
    
    
		log.Fatalf("Error creating producer: %s", err.Error())
	}
	defer func() {
    
    
		if err := producer.Close(); err != nil {
    
    
			log.Fatalf("Error closing producer: %s", err.Error())
		}
	}()

	// 构造消息
	message := &sarama.ProducerMessage{
    
    
		Topic: "your_topic",                          // 设置消息发送到的主题
		Value: sarama.StringEncoder("Hello, Kafka!"), // 设置消息内容
	}

	// 发送消息
	partition, offset, err := producer.SendMessage(message)
	if err != nil {
    
    
		log.Fatalf("Failed to send message: %s", err.Error())
	}

	fmt.Printf("Message sent to partition %d at offset %d\n", partition, offset)

	// 处理退出信号
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	<-sigchan
}

ステップ 3: コードを説明する

この例では、sarama.Configオブジェクトを作成し、いくつかの一般的なプロデューサー構成パラメーターを設定します。

  1. config.Producer.RequiredAcks: すべてのレプリカがメッセージを確認するまで待機するように設定します。つまり、プロデューサーは、メッセージが正常に送信されたと判断する前に、すべてのレプリカがメッセージを正常に書き込むのを待機します。

  2. config.Producer.Retry.Max: 最大再試行回数を設定します。メッセージの送信に失敗した場合、プロデューサーは最大回数だけメッセージの再送信を試みます。

  3. config.Producer.Return.Successes: 成功メッセージを返すかどうかを設定します。 に設定するとtrue、プロデューサはメッセージの送信が成功したときにメッセージを返しますsuccess

  4. config.Producer.Compression: メッセージ圧縮アルゴリズムを設定します。ここでは GZIP が選択されています。必要に応じて他のアルゴリズムを選択できます。

  5. config.Producer.Partitioner: パーティショニング戦略を設定します。ここではランダム パーティショニング戦略が選択されます。つまり、メッセージはランダム パーティションに送信されます。

この例では、同期プロデューサー ( NewSyncProducer) を使用していますが、NewAsyncProducer必要に応じて非同期プロデューサー ( ) を選択することもできます。

4. パーティショナー

Kafka プロデューサー API のパーティショナーについて話すときは、メッセージがどのパーティションに送信されるかを決定するメカニズムを指します。

パーティショナーは、プロデューサーが Kafka トピックのどのパーティションにメッセージを書き込むかを決定するのに役立ちます。これは、メッセージの順序付け、ロード バランシング、および並列処理に影響を与えるため、設計上の重要な決定事項となります。

4.1 パーティショナーの役割

Kafka トピックは通常、複数のパーティションに分割されており、各パーティションは順序付けられたログです。メッセージは特定のパーティションに送信されるため、メッセージの順序が維持されます。パーティショナーのタスクは、特定のルールに基づいてメッセージがどのパーティションに属するかを決定することです。

4.2 例と詳細な説明

package main

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

	"github.com/Shopify/sarama"
)

// CustomPartitioner 自定义分区器
type CustomPartitioner struct{
    
    }

// Partition 实现sarama.Partitioner接口
func (p *CustomPartitioner) Partition(message *sarama.ProducerMessage, numPartitions int32) (int32, error) {
    
    
	// 在这里,设置自定义的分区逻辑
	// 这里简单地使用消息的 key 的哈希值对分区数取余
	key := message.Key
	if key == nil {
    
    
		// 如果消息没有 key,使用默认分区(随机分区)
		return int32(sarama.NewRandomPartitioner.RandomPartition(message, numPartitions)), nil
	}
	return int32(sarama.NewHashPartitioner.Hash(key, numPartitions)), nil
}

func main() {
    
    
	// 创建配置
	config := sarama.NewConfig()

	// 设置自定义分区器
	config.Producer.Partitioner = &CustomPartitioner{
    
    }

	// 创建生产者
	producer, err := sarama.NewSyncProducer([]string{
    
    "kafka-broker1:9092", "kafka-broker2:9092"}, config)
	if err != nil {
    
    
		log.Fatalf("Error creating producer: %s", err.Error())
	}
	defer func() {
    
    
		if err := producer.Close(); err != nil {
    
    
			log.Fatalf("Error closing producer: %s", err.Error())
		}
	}()

	// 构造消息
	message := &sarama.ProducerMessage{
    
    
		Topic: "your_topic",                          // 设置消息发送到的主题
		Value: sarama.StringEncoder("Hello, Kafka!"), // 设置消息内容
		Key:   sarama.StringEncoder("some_key"),      // 设置消息的 key
	}

	// 发送消息
	partition, offset, err := producer.SendMessage(message)
	if err != nil {
    
    
		log.Fatalf("Failed to send message: %s", err.Error())
	}

	fmt.Printf("Message sent to partition %d at offset %d\n", partition, offset)

	// 处理退出信号
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	<-sigchan
}

4.3 コードの説明

この例では、最初にカスタム パーティショナーを作成しCustomPartitionersarama.PartitionerインターフェイスのPartitionメソッドを実装します。このメソッドではPartition、独自のパーティショニング ロジックを定義できます。ここでは、メッセージのキーのハッシュ値を使用してパーティションの数を調整します。メッセージにキーがない場合は、デフォルトのランダム パーティションが使用されます。

func (p *CustomPartitioner) Partition(message *sarama.ProducerMessage, numPartitions int32) (int32, error) {
    
    
	key := message.Key
	if key == nil {
    
    
		return int32(sarama.NewRandomPartitioner.RandomPartition(message, numPartitions)), nil
	}
	return int32(sarama.NewHashPartitioner.Hash(key, numPartitions)), nil
}

次に、このカスタム パーティショナーをプロデューサーの構成に設定します。

config.Producer.Partitioner = &CustomPartitioner{
    
    }

このようにして、メッセージを送信するときに、プロデューサーはカスタム パーティショニング ロジックを使用して、メッセージをどのパーティションに送信するかを決定します。

5.シリアライザ

Kafka プロデューサー API のシリアライザーについて話すときは、メッセージをネットワーク経由で送信できるようにメッセージをバイト ストリームに変換するプロセスを指します。

Kafka では、プロデューサーによってメッセージが Kafka クラスターに送信される前に、メッセージをバイト ストリームにシリアル化する必要があります。シリアライザーは、メッセージ オブジェクトをバイト ストリームに変換し、そのバイト ストリームをコンシューマ側で元のメッセージ オブジェクトに逆シリアル化する役割を果たします。

このプロセスは、メッセージを効率的に送信し、ネットワークに保存できるようにするためのものです。

5.1 なぜシリアル化が必要なのでしょうか?

Kafka は分散メッセージング システムであり、メッセージは異なるノード間で配信される必要があります。このネットワーク間送信を実現するには、メッセージをバイト ストリームの形式で表現する必要があります。シリアル化は、メッセージ オブジェクトをバイト ストリームに変換するプロセスです。

5.2 例と詳細な説明

簡単な例でシリアル化プロセスを説明してみましょう。

次のようなメッセージ構造があるとします。

type MyMessage struct {
    
    
	ID   int
	Body string
}

まず、この構造体をバイト ストリームに変換するシリアライザーを定義する必要があります。

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
)

// MyMessage 结构体
type MyMessage struct {
    
    
	ID   int
	Body string
}

// Serializer 序列化器
type Serializer struct{
    
    }

// Serialize 将消息对象序列化为字节流
func (s *Serializer) Serialize(message *MyMessage) ([]byte, error) {
    
    
	var buffer bytes.Buffer
	encoder := gob.NewEncoder(&buffer)
	err := encoder.Encode(message)
	if err != nil {
    
    
		return nil, err
	}
	return buffer.Bytes(), nil
}

// Deserialize 将字节流反序列化为消息对象
func (s *Serializer) Deserialize(data []byte) (*MyMessage, error) {
    
    
	var message MyMessage
	decoder := gob.NewDecoder(bytes.NewReader(data))
	err := decoder.Decode(&message)
	if err != nil {
    
    
		return nil, err
	}
	return &message, nil
}

func main() {
    
    
	// 创建消息对象
	message := &MyMessage{
    
    
		ID:   1,
		Body: "Hello, Kafka!",
	}

	// 创建序列化器
	serializer := &Serializer{
    
    }

	// 序列化消息
	serializedData, err := serializer.Serialize(message)
	if err != nil {
    
    
		log.Fatalf("Error serializing message: %s", err.Error())
	}

	// 打印序列化后的字节流
	fmt.Printf("Serialized data: %v\n", serializedData)

	// 反序列化消息
	deserializedMessage, err := serializer.Deserialize(serializedData)
	if err != nil {
    
    
		log.Fatalf("Error deserializing message: %s", err.Error())
	}

	// 打印反序列化后的消息对象
	fmt.Printf("Deserialized message: %+v\n", deserializedMessage)
}

5.3 コードの解釈

この例では、最初に単純なメッセージ構造を定義し、次にメソッドとメソッドを実装するMyMessageシリアライザーを作成しますメソッドはメッセージ オブジェクトをバイト ストリームに変換し、メソッドはバイト ストリームをメッセージ オブジェクトに逆シリアル化します。SerializerSerializeDeserializeSerializeDeserialize

encoding/gobシリアル化と逆シリアル化にはパッケージを使用します。実際のアプリケーションでは、ニーズやシステムの互換性に応じて、JSON や Avro などの他のシリアル化方法を選択できます。

最後に、メッセージ オブジェクトを作成し、シリアライザーを使用してそれをバイト ストリームにシリアル化し、結果を出力します。次に、バイト ストリームをメッセージ オブジェクトに逆シリアル化し、結果を出力します。これは、実際のアプリケーションにおけるシリアル化の基本的な使用法を示しています。

おすすめ

転載: blog.csdn.net/weixin_49015143/article/details/135061197
おすすめ