自由的羽毛 发表于 2024-11-29 04:20:58

kafka之protobuf

Protobuf 的 .proto 文件是一种形貌消息结构的定义文件,使用这种文件可以定义数据结构(消息),然后生成对应语言的类或代码用于序列化和反序列化数据。生成 .proto 文件涉及到编写 .proto 文件定义,然后通过 protoc 编译器生成目标语言的代码(如 Java、Python、Go 等)。
生成 .proto 文件的步调

1. 编写 .proto 文件

首先,手动编写 .proto 文件来定义消息的结构。每个 .proto 文件定义了消息类型、字段以及字段的类型和编号。
例如,下面的 .proto 文件定义了一个图片消息的结构,包罗文件名、格式和二进制数据:
// image.proto
syntax = "proto3";


message ImageRecord {
// 文件名
string filename = 1;

// 文件格式
string format = 2;

// 二进制数据
bytes imageData = 3;
}
2. 使用 protoc 编译 .proto 文件

protoc 是 Google 的 Protocol Buffers 编译器,负责将 .proto 文件编译成对应编程语言的类文件。这些类文件用于序列化和反序列化数据。
2.1. 安装 protoc



[*]下载并安装 protoc:

[*] Linux/macOS:使用包管理器安装

# macOS
brew install protobuf

# Ubuntu
sudo apt-get install -y protobuf-compiler
Windows:从 官方下载页面 获取并安装。
https://i-blog.csdnimg.cn/direct/5cb24dc72b564456a44456baf56db082.png
win 解压上述zip包:
https://i-blog.csdnimg.cn/direct/d3b619cdaf9c49a585819a1a7ae6f993.png
执行的文件就在这里:
https://i-blog.csdnimg.cn/direct/e4b1812a88bf46cb9bbe6265f5c99649.png
为了方便使用可以把这个bin目录设置在系统情况变量里,也可以直接进入到这个文件夹里
如果设置情况变量的话,安装完毕之后验证:
验证安装:
protoc --version
2.2. 编译 .proto 文件

通过 protoc 命令来编译 .proto 文件为目标语言代码。下面是几种常见语言的生成方式。
2.2.1. 生成 Java 代码

# 将 image.proto 编译为 Java 类,生成到指定目录
protoc --java_out=./output image.proto
上述的指令直接在win的cmd命令行里即可完成,记得提前建好 output目录
https://i-blog.csdnimg.cn/direct/0ab404110150470683b640c126016a20.png
https://i-blog.csdnimg.cn/direct/cc2cb23fa7db45c5928245333545354e.png
执行完毕之后就会生成一个 .java文件
https://i-blog.csdnimg.cn/direct/0a17211055ad4440a60ab7b55cffb935.png
编译后,会在 ./output 目录下生成相应的 Java 类(如 ImageRecord.java),你可以直接使用这些类举行 Protobuf 的序列化和反序列化。
3. 使用生成的类

编译生成的类会包罗以下功能:


[*]序列化:将定义的消息对象转换为二进制格式,得当传输或存储。
[*]反序列化:将二进制格式的数据解析回消息对象。
例如,使用生成的 Java 类序列化和反序列化 ImageRecord:
import com.example.proto.ImageRecord;// 假设包名为 com.example.proto
import java.nio.file.Files;
import java.io.File;

public class ProtobufExample {
    public static void main(String[] args) throws Exception {
      // 构建 ImageRecord 消息对象
      ImageRecord image = ImageRecord.newBuilder()
            .setFilename("example.jpg")
            .setFormat("jpg")
            .setImageData(ByteString.copyFrom(Files.readAllBytes(new File("example.jpg").toPath())))
            .build();

      // 序列化为二进制数据
      byte[] serializedData = image.toByteArray();

      // 反序列化为 ImageRecord 对象
      ImageRecord deserializedImage = ImageRecord.parseFrom(serializedData);

      System.out.println("Filename: " + deserializedImage.getFilename());
    }
}
4. 定义 .proto 文件的规则

以下是 .proto 文件的常见语法:


[*] syntax:定义 Protobuf 版本,保举使用 proto3,较为简洁并且是最新的标准。
syntax = "proto3";



[*]消息(Message)定义:使用 message 关键字定义数据结构。
message ImageRecord {
    string filename = 1;// string 类型字段,字段编号为 1
    string format = 2;    // string 类型字段,字段编号为 2
    bytes imageData = 3;// 二进制数据,字段编号为 3
}
字段类型:常见的 Protobuf 字段类型包罗:


[*]int32, int64: 整数
[*]float, double: 浮点数
[*]bool: 布尔值
[*]string: 字符串
[*]bytes: 二进制数据(如文件、图片、视频)
字段编号:每个字段必须有唯一的编号,编号用于序列化和反序列化。编号必须是正整数,1 到 15 的编号用于最常用的字段,因为它们序列化时占用更少的空间
嵌套消息:可以在消息中定义嵌套的消息类型
message User {
string username = 1;
Profile profile = 2; // 嵌套消息类型

message Profile {
      string email = 1;
      int32 age = 2;
}
}
总结


[*]编写 .proto 文件:定义消息结构,包罗字段类型、名称和编号。
[*]使用 protoc 编译:将 .proto 文件编译为目标语言代码,如 Java、Python、Go 等。
[*]使用生成的类:使用生成的类举行消息的序列化(转换为二进制格式)和反序列化(解析二进制数据)。
kafka和protobuf集成例子:

要将 Protobuf 与 Kafka 集成,我们可以使用 Protobuf 定义的数据结构作为 Kafka 消息体,并通过 Kafka Producer 将序列化的 Protobuf 消息发送到 Kafka。在消耗者端,通过 Kafka Consumer 接收消息并反序列化为原始的 Protobuf 对象。
步调:


[*]编写 .proto 文件:定义消息的结构。
[*]使用 protoc 编译生成类:使用 Protobuf 编译器将 .proto 文件编译为 Java/Python 等语言的类。
[*]Kafka Producer 发送 Protobuf 消息:使用生成的类,构造 Protobuf 消息并通过 Kafka Producer 发送。
[*]Kafka Consumer 接收并反序列化 Protobuf 消息:在 Kafka Consumer 中接收消息,并反序列化为 Protobuf 对象。
1. 编写 Protobuf .proto 文件

例如,定义一个包罗图片信息的 ImageRecord.proto 文件:
syntax = "proto3";
message ImageRecord {string filename = 1;string format = 2;bytes imageData = 3;} 2. 使用 protoc 编译生成 Java 类

假设使用 Java,将 .proto 文件编译为 Java 类:
protoc --java_out=./output ImageRecord.proto
3. Kafka Producer 发送 Protobuf 消息

通过 Kafka Producer 发送 Protobuf 格式的消息:
import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}
import java.util.Properties
import java.nio.file.Files
import java.io.File
import com.example.proto.ImageRecord

object ProtobufKafkaProducer {
    def main(args: Array): Unit = {
      // Kafka Producer 配置
      val props = new Properties()
      props.put("bootstrap.servers", "localhost:9092")
      props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer")
      props.put("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer")

      val producer = new KafkaProducer](props)

      // 构建 Protobuf 消息
      val imageBytes = Files.readAllBytes(new File("/path/to/image.jpg").toPath)
      val imageRecord = ImageRecord.newBuilder()
            .setFilename("image.jpg")
            .setFormat("jpg")
            .setImageData(com.google.protobuf.ByteString.copyFrom(imageBytes))
            .build()

      // 序列化并发送 Protobuf 消息到 Kafka
      val record = new ProducerRecord]("image_topic", "image_key", imageRecord.toByteArray)
      producer.send(record)

      producer.close()
    }
}
4. Kafka Consumer 接收并反序列化 Protobuf 消息

通过 Kafka Consumer 接收 Protobuf 消息并反序列化:
import org.apache.kafka.clients.consumer.{KafkaConsumer, ConsumerRecords}
import java.util.Properties
import com.example.proto.ImageRecord

object ProtobufKafkaConsumer {
    def main(args: Array): Unit = {
      // Kafka Consumer 配置
      val props = new Properties()
      props.put("bootstrap.servers", "localhost:9092")
      props.put("group.id", "test")
      props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
      props.put("value.deserializer", "org.apache.kafka.common.serialization.ByteArrayDeserializer")
      props.put("auto.offset.reset", "earliest")

      val consumer = new KafkaConsumer](props)
      consumer.subscribe(java.util.Arrays.asList("image_topic"))

      // 消费并反序列化消息
      while (true) {
            val records: ConsumerRecords] = consumer.poll(100)
            records.forEach { record =>
                // 反序列化 Protobuf 消息
                val imageRecord = ImageRecord.parseFrom(record.value())
                println(s"Filename: ${imageRecord.getFilename}, Format: ${imageRecord.getFormat}")
            }
      }
    }
}
Kafka 与 Protobuf 集成的优势:


[*]高效序列化:Protobuf 生成的二进制格式非常紧凑,得当大数据量和高吞吐场景。
[*]跨语言支持:Protobuf 支持多种语言,因此 Kafka 与 Protobuf 的集成能轻松跨多语言系统工作。
[*]Schema 支持:通过 Protobuf,数据结构的厘革可以通过 .proto 文件的模式演进举行管理。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: kafka之protobuf