【Kafka】 Registro de esquema confluente

Inserte la descripción de la imagen aquí

Original: https://cloud.tencent.com/developer/article/1336568

1. Registro de esquemas

Ya sea usando las clases de deserialización y serialización personalizadas de la API Avro tradicional o usando la biblioteca Bijection de Twitter para implementar la serialización y deserialización de Avro, ambos métodos tienen una desventaja: en cada registro de Kafka. Incrustado en el esquema, esto duplicará el tamaño del registro. Pero de todos modos, el esquema completo sigue siendo necesario al leer registros, por lo que primero se debe encontrar el esquema. ¿Hay alguna forma de compartir un esquema de datos?

Seguimos el patrón estructural general y utilizamos el "registro de esquema" para lograr el objetivo. El principio de "registro de esquemas" es el siguiente:

Inserte la descripción de la imagen aquí
Guarde todos los esquemas necesarios para escribir datos en el registro y luego haga referencia al ID de esquema en el registro. La aplicación responsable de leer los datos utiliza el ID para extraer el esquema del registro para deserializar el registro. El serializador y el deserializador son responsables de procesar el registro y la extracción del esquema, respectivamente.

El registro de esquemas no pertenece a Kafka, ya existen algunas implementaciones de registros de esquemas de código abierto. Por ejemplo, el Confluent Schema Registry que se analiza en este artículo.

2. Descripción del caso

El archivo de esquema existente user.json tiene el siguiente contenido:

{
    
    
    "type": "record",
    "name": "User",
    "fields": [
        {
    
    "name": "id", "type": "int"},
        {
    
    "name": "name",  "type": "string"},
        {
    
    "name": "age", "type": "int"}
    ]
}

Requisitos: Registre el contenido de este esquema en Confluent Schema Registry, y Kafka Producer y Kafka Consumer serializarán y deserializarán el contenido del esquema en Confluent Schema Registry mediante la identificación.

3. Pasos prácticos

(1) Inicie el servicio Confluent Schema Registry.
Dirección de descarga de Confluent: https://www.confluent.io/download/, aquí uso confluent-oss-4.1.1-2.11.tar.gz para
descargarlo y subirlo al servidor, descomprímalo Disponible
Ingrese al directorio confluent-4.1.1 / etc / schema-registry /, modifique el archivo schema-registry.properties, el contenido y los comentarios son los siguientes:

# Confluent Schema Registry 服务的访问IP和端口
listeners=http://192.168.42.89:8081

# Kafka集群所使用的zookeeper地址,如果不配置,会使用Confluent内置的Zookeeper地址(localhost:2181)
kafkastore.connection.url=192.168.42.89:2181/kafka-1.1.0-cluster

# Kafka集群的地址(上一个参数和这个参数配置一个就可以了)
# kafkastore.bootstrap.servers=192.168.42.89:9092,192.168.42.89:9093,192.168.42.89:9094

# 存储 schema 的 topic
kafkastore.topic=_schemas

# 其余保持默认即可

Inicie el registro de esquema de Confluent

[root@confluent confluent-4.1.1]# bin/schema-registry-start etc/schema-registry/schema-registry.properties
# 省略一些内容......
[2018-06-22 16:10:26,442] INFO Server started, listening for requests... (io.confluent.kafka.schemaregistry.rest.SchemaRegistryMain:45)

Pero mi error

[2020-09-10 17:01:23,523] ERROR Server died unexpectedly:  (io.confluent.kafka.schemaregistry.rest.SchemaRegistryMain:51)
io.confluent.common.config.ConfigException: No supported Kafka endpoints are configured. Either kafkastore.bootstrap.servers must have at least one endpoint matching kafkastore.security.protocol or broker endpoints loaded from ZooKeeper must have at least one endpoint matching kafkastore.security.protocol.
 at io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig.endpointsToBootstrapServers(SchemaRegistryConfig.java:614)
 at io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig.bootstrapBrokers(SchemaRegistryConfig.java:554)
 at io.confluent.kafka.schemaregistry.storage.KafkaStore.<init>(KafkaStore.java:101)
 at io.confluent.kafka.schemaregistry.storage.KafkaSchemaRegistry.<init>(KafkaSchemaRegistry.java:139)
 at io.confluent.kafka.schemaregistry.rest.SchemaRegistryRestApplication.setupResources(SchemaRegistryRestApplication.java:60)
 at io.confluent.kafka.schemaregistry.rest.SchemaRegistryRestApplication.setupResources(SchemaRegistryRestApplication.java:42)
 at io.confluent.rest.Application.createServer(Application.java:157)
 at io.confluent.kafka.schemaregistry.rest.SchemaRegistryMain.main(SchemaRegistryMain.java:43)

Hay una referencia de error aquí: https://github.com/confluentinc/schema-registry/issues/765

(2) Registre el esquema del usuario en el tema correspondiente.

Primero, marque el archivo de esquema original con "esquema"

{
    
    
    "schema": "{
    
    
        "type": "record",
        "name": "User",
        "fields": [
            {
    
    "name": "id", "type": "int"},
            {
    
    "name": "name",  "type": "string"},
            {
    
    "name": "age", "type": "int"}
        ]
    }"
}

Algunos "necesitan escapar:

{
    
    
    "schema": "{
    
    
        \"type\": \"record\",
        \"name\": \"User\",
        \"fields\": [
            {
    
    \"name\": \"id\", \"type\": \"int\"},
            {
    
    \"name\": \"name\",  \"type\": \"string\"},
            {
    
    \"name\": \"age\", \"type\": \"int\"}
        ]
    }"
}

El comando para registrar el esquema es el siguiente

curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
--data '' \ 
http://192.168.42.89:8081/subjects/dev3-yangyunhe-topic001-value/versions

Descripción:

  1. ''Necesita completar la cadena de esquema entre
  2. El tema que solía probar es dev3-yangyunhe-topic001, y solo serializo el valor de Kafka con avro, por lo que la dirección registrada eshttp://192.168.42.89:8081/subjects/dev3-yangyunhe-topic001-value/versions
  3. http://192.168.42.89:8081 debe modificarse de acuerdo con su propia configuración

Complete el esquema de escape en las dos comillas simples de --data ''

curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
--data '{"schema": "{\"type\": \"record\", \"name\": \"User\", \"fields\": [{\"name\": \"id\", \"type\": \"int\"}, {\"name\": \"name\",  \"type\": \"string\"}, {\"name\": \"age\", \"type\": \"int\"}]}"}' \
http://192.168.42.89:8081/subjects/dev3-yangyunhe-topic001-value/versions

El registro exitoso devolverá el ID de este esquema

{
    
    "id":102}

(3) Introduzca los paquetes jar relacionados con Confluent Schema Registry en el proyecto maven.
Estos paquetes jar no se pueden descargar desde el almacén de maven. Debe agregarlos manualmente al clúster. Después de descomprimir confluent-4.1.1, los paquetes jar están disponibles en el directorio share / java / Los paquetes jar de componentes confluentes:
Inserte la descripción de la imagen aquí

Necesitamos common-config-4.1.1.jar, common-utils-4.1.1.jar y todos los paquetes jar que comiencen con jackson en el directorio confluent-common y kafka-schema-registry- en el directorio kafka-serde-tools client-4.1.1.jar y kafka-avro-serializer-4.1.1.jar, cómo agregar el paquete jar local al proyecto java, este artículo no los repetirá.

(4) Kafka Producer envía datos

package com.bonc.rdpe.kafka110.producer;

import java.util.Properties;
import java.util.Random;

import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;

/**
 * @Title ConfluentProducer.java 
 * @Description 使用Confluent实现的Schema Registry服务来发送Avro序列化后的对象
 * @Author YangYunhe
 * @Date 2018-06-25 10:49:19
 */
public class ConfluentProducer {
    
    
    
    public static final String USER_SCHEMA = "{\"type\": \"record\", \"name\": \"User\", " + 
            "\"fields\": [{\"name\": \"id\", \"type\": \"int\"}, " + 
            "{\"name\": \"name\",  \"type\": \"string\"}, {\"name\": \"age\", \"type\": \"int\"}]}";
    
    public static void main(String[] args) throws Exception {
    
    
        
        Properties props = new Properties();
        props.put("bootstrap.servers", "192.168.42.89:9092,192.168.42.89:9093,192.168.42.89:9094");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        // 使用Confluent实现的KafkaAvroSerializer
        props.put("value.serializer", "io.confluent.kafka.serializers.KafkaAvroSerializer");
        // 添加schema服务的地址,用于获取schema
        props.put("schema.registry.url", "http://192.168.42.89:8081");

        Producer<String, GenericRecord> producer = new KafkaProducer<>(props);
        
        Schema.Parser parser = new Schema.Parser();
        Schema schema = parser.parse(USER_SCHEMA);
        
        Random rand = new Random();
        int id = 0;

        while(id < 100) {
    
    
            id++;
            String name = "name" + id;
            int age = rand.nextInt(40) + 1;
            GenericRecord user = new GenericData.Record(schema);
            user.put("id", id);
            user.put("name", name);
            user.put("age", age);
            
            ProducerRecord<String, GenericRecord> record = new ProducerRecord<>("dev3-yangyunhe-topic001", user);
            
            producer.send(record);
            Thread.sleep(1000);
        }

        producer.close();

    }

}

(5) Datos de consumo de Kafka Consumer

package com.bonc.rdpe.kafka110.consumer;

import java.util.Collections;
import java.util.Properties;

import org.apache.avro.generic.GenericRecord;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

/**
 * @Title ConfluentConsumer.java
 * @Description 使用Confluent实现的Schema Registry服务来消费Avro序列化后的对象
 * @Author YangYunhe
 * @Date 2018-06-25 11:42:21
 */
public class ConfluentConsumer {
    
    

    public static void main(String[] args) throws Exception {
    
    

        Properties props = new Properties();
        props.put("bootstrap.servers", "192.168.42.89:9092,192.168.42.89:9093,192.168.42.89:9094");
        props.put("group.id", "dev3-yangyunhe-group001");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        // 使用Confluent实现的KafkaAvroDeserializer
        props.put("value.deserializer", "io.confluent.kafka.serializers.KafkaAvroDeserializer");
        // 添加schema服务的地址,用于获取schema
        props.put("schema.registry.url", "http://192.168.42.89:8081");
        KafkaConsumer<String, GenericRecord> consumer = new KafkaConsumer<>(props);

        consumer.subscribe(Collections.singletonList("dev3-yangyunhe-topic001"));

        try {
    
    
            while (true) {
    
    
                ConsumerRecords<String, GenericRecord> records = consumer.poll(1000);
                for (ConsumerRecord<String, GenericRecord> record : records) {
    
    
                    GenericRecord user = record.value();
                    System.out.println("value = [user.id = " + user.get("id") + ", " + "user.name = "
                            + user.get("name") + ", " + "user.age = " + user.get("age") + "], "
                            + "partition = " + record.partition() + ", " + "offset = " + record.offset());
                }
            }
        } finally {
    
    
            consumer.close();
        }
    }
}

(6) Resultados de la prueba

La salida de la consola de Kafka Consumer es la siguiente:

value = [user.id = 1, user.name = name1, user.age = 20], partition = 1, offset = 696
value = [user.id = 2, user.name = name2, user.age = 27], partition = 0, offset = 696
value = [user.id = 3, user.name = name3, user.age = 35], partition = 2, offset = 695
value = [user.id = 4, user.name = name4, user.age = 7], partition = 1, offset = 697
value = [user.id = 5, user.name = name5, user.age = 34], partition = 0, offset = 697

......

Supongo que te gusta

Origin blog.csdn.net/qq_21383435/article/details/108522841
Recomendado
Clasificación