Interceptor personalizado del productor de Kafka (interceptor)

1. Principio de interceptor

  • El interceptor de productor (interceptor) se introdujo en la versión Kafka 0.10, utilizado principalmente para implementar una lógica de control personalizada en el lado del cliente.
  • Para el productor, el interceptor brinda a los usuarios la oportunidad de realizar algunos requisitos personalizados para el mensaje antes de que se envíe el mensaje y antes de la lógica de devolución de llamada del productor, como modificar el mensaje. Al mismo tiempo, el productor permite a los usuarios especificar múltiples interceptores para actuar en el mismo mensaje en secuencia para formar una cadena de interceptores.
  • La interfaz de implementación de Intercetpor es org.apache.kafka.clients.producer.ProducerInterceptor, y sus métodos definidos incluyen:
    (1) configure (configs) : se llama al obtener información de configuración e inicializar datos.
    (2) onSend (ProducerRecord) : este método está encapsulado en el método KafkaProducer.send, es decir, se ejecuta en el hilo principal del usuario. El productor se asegura de que se llame a este método antes de que se serialice el mensaje y se calcule la partición. El usuario puede realizar cualquier operación en el mensaje en este método, pero es mejor asegurarse de que el tema y la partición a la que pertenece el mensaje no se modifiquen, de lo contrario afectará el cálculo de la partición de destino.
    (3) onAcknowledgement (RecordMetadata, Exception) : este método se llamará después de que el mensaje se envíe correctamente desde RecordAccumulator al Kafka Broker o cuando el proceso de envío falle. Y normalmente antes de que se active la lógica de devolución de llamada del productor. onAcknowledgement se ejecuta en el subproceso de E / S del productor, así que no ponga mucha lógica en este método, de lo contrario, ralentizará la eficiencia de envío de mensajes del productor.
    (4) cerrar : cierra el interceptor, utilizado principalmente para realizar algún trabajo de limpieza de recursos. Como se mencionó anteriormente, el interceptor se puede ejecutar en múltiples subprocesos, por lo que los usuarios deben garantizar la seguridad de los subprocesos por sí mismos durante la implementación específica. Además, si se especifican varios interceptores, el productor los llamará en el orden especificado y solo capturará las excepciones que cada interceptor pueda lanzar y las registrará en el registro de errores en lugar de pasarlas hacia arriba. A esto se le debe prestar especial atención durante el uso.

En segundo lugar, el caso del interceptor

1. Preparación

  • Cree un proyecto maven en el IDE, agregue dependencias al archivo pom
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>1.1.1</version>
</dependency>
  • Iniciar grupo de cuidadores del zoológico
bin/zkServer.sh start
  • Inicie el grupo kafka
bin/kafka-server-start.sh -daemon config/server.properties
  • El clúster de Kafka abre un consumidor
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic bigdata 
--from-beginning

2. Análisis de la demanda

Implemente una cadena de interceptores simple compuesta por interceptores duales. El primer interceptor agregará la información de la marca de tiempo en la parte superior del valor del mensaje antes de que se envíe el mensaje; el segundo interceptor actualizará el número de mensajes enviados correctamente y el número de mensajes fallidos después de que se envíe el mensaje.

Inserte la descripción de la imagen aquí

3. Visualización de código

	3.1、 增加时间戳拦截器
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import java.util.Map;

public class MyTimeInterceptor implements ProducerInterceptor<String,String> {
    
    

    @Override
    public void configure(Map<String, ?> configs) {
    
    

    }

    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
    
    
        /* 取出value值 */
        String value = record.value();

        /* 创建一个新的 record,把时间戳写入消息体的最前部 */
        return new ProducerRecord(record.topic(),record.partition(),record.key(),System.currentTimeMillis() + "---" + value);
    }

    @Override
    public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
    
    

    }

    @Override
    public void close() {
    
    

    }
}
	3.2、增加统计次数拦截器,统计发送消息成功和发送失败消息数,并在 producer 关闭时打印这两个计数器
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import java.util.Map;

public class MyCountInterceptor implements ProducerInterceptor<String,String> {
    
    
    private int success;
    private int error;

    @Override
    public void configure(Map<String, ?> configs) {
    
    

    }

    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
    
    
        return record;
    }

    @Override
    public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
    
    
        /* 统计成功和失败的次数 */
        if (metadata != null){
    
    
            success ++;
        }else {
    
    
            error ++ ;
        }
    }

    @Override
    public void close() {
    
    
        /* 保存结果 */
        System.out.println("success: " + success);
        System.out.println("error: " + error);
    }
}
	3.3、producer 主程序
import java.util.ArrayList;
import java.util.Properties;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;

public class MyProducerInterceptor {
    
    
    public static void main(String[] args) {
    
    

        /* 相当于map操作 */
        Properties properties = new Properties();

        /* kafka 集群,broker-list */
        properties.put("bootstrap.servers", "centos7-1:9092");

        /* 等待所有副本节点的应答 */
        properties.put("acks", "all");

        /* 重试次数 */
        properties.put("retries", Integer.valueOf(3));

        /* 批次大小 */
        properties.put("batch.size", Integer.valueOf(16384));

        /* 等待时间 */
        properties.put("linger.ms", Integer.valueOf(1));

        /* RecordAccumulator 缓冲区大小 */
        properties.put("buffer.memory", Integer.valueOf(33554432));

        /* key序列化 */
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        /* value序列化 */
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        /* 构建拦截器链 */
        ArrayList<String> interceptors = new ArrayList<>();
        interceptors.add("com.jh.interceptor.MyTimeInterceptor ");
        interceptors.add("com.jh.interceptor.MyCountInterceptor ");
        /* 添加拦截器链 */
        properties.put("interceptor.classes", interceptors);

        /* 创建生产者对象 */
        KafkaProducer<String, String> kafkaProducer = new KafkaProducer(properties);

        /*  发送消息 */
        for (int i = 0; i < 10000; i++){
    
    
            /* 发送的主题、key、value */
            kafkaProducer.send(new ProducerRecord("bigdata", "jh","jh==" + i));
        }

        /* 一定要关闭 producer,这样才会调用 interceptor的 close 方法 */
        kafkaProducer.close();
    }
}

4. Visualización del efecto de operación
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_46122692/article/details/109293210
Recomendado
Clasificación