Kafka 之producer拦截器(interceptor)
Kafka 之producer拦截器(interceptor)
一、拦截器原理
Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑。
对于producer而言,interceptor使得用户在消息发送前以及producer回调逻辑前有机会对消息做一些定制化需求,比如修改消息等。同时,producer允许用户指定多个interceptor按序作用于同一条消息从而形成一个拦截链(interceptor chain)。Intercetpor的实现接口是org.apache.kafka.clients.producer.ProducerInterceptor,其定义的方法包括:
(1)configure(configs)
获取配置信息和初始化数据时调用。
(2)onSend(ProducerRecord):
该方法封装进KafkaProducer.send方法中,即它运行在用户主线程中。Producer确保在消息被序列化以及计算分区前调用该方法。用户可以在该方法中对消息做任何操作,但最好保证不要修改消息所属的topic和分区,否则会影响目标分区的计算
(3)onAcknowledgement(RecordMetadata, Exception):
该方法会在消息被应答或消息发送失败时调用,并且通常都是在producer回调逻辑触发之前。onAcknowledgement运行在producer的IO线程中,因此不要在该方法中放入很重的逻辑,否则会拖慢producer的消息发送效率
(4)close:
关闭interceptor,主要用于执行一些资源清理工作
如前所述,interceptor可能被运行在多个线程中,因此在具体实现时用户需要自行确保线程安全。另外倘若指定了多个interceptor,则producer将按照指定顺序调用它们,并仅仅是捕获每个interceptor可能抛出的异常记录到错误日志中而非在向上传递。这在使用过程中要特别留意。
二、拦截器案例
1)需求:
实现一个简单的双interceptor组成的拦截链。第一个interceptor会在消息发送前将时间戳信息加到消息value的最前部;第二个interceptor会在消息发送后更新成功发送消息数或失败发送消息数。

2)案例实操
(1)增加时间戳拦截器
package com.libt.kafka.interceptor;
import java.util.Map;
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata; public class TimeInterceptor implements ProducerInterceptor<String, String> { @Override
public void configure(Map<String, ?> configs) { } @Override
public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
// 创建一个新的record,把时间戳写入消息体的最前部
return new ProducerRecord(record.topic(), record.partition(), record.timestamp(), record.key(),
System.currentTimeMillis() + "," + record.value().toString());
} @Override
public void onAcknowledgement(RecordMetadata metadata, Exception exception) { } @Override
public void close() { }
}
(2)统计发送消息成功和发送失败消息数,并在producer关闭时打印这两个计数器
package com.libt.kafka.interceptor;
import java.util.Map;
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata; public class CounterInterceptor implements ProducerInterceptor<String, String>{
private int errorCounter = 0;
private int successCounter = 0; @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 (exception == null) {
successCounter++;
} else {
errorCounter++;
}
} @Override
public void close() {
// 保存结果
System.out.println("Successful sent: " + successCounter);
System.out.println("Failed sent: " + errorCounter);
}
}
(3)producer主程序
package com.libt.kafka.interceptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord; public class InterceptorProducer { public static void main(String[] args) throws Exception {
// 1 设置配置信息
Properties props = new Properties();
props.put("bootstrap.servers", "hadoop1:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); // 2 构建拦截链
List<String> interceptors = new ArrayList<>();
interceptors.add("com.atguigu.kafka.interceptor.TimeInterceptor"); interceptors.add("com.atguigu.kafka.interceptor.CounterInterceptor");
props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, interceptors); String topic = "first";
Producer<String, String> producer = new KafkaProducer<>(props); // 3 发送消息
for (int i = 0; i < 10; i++) { ProducerRecord<String, String> record = new ProducerRecord<>(topic, "message" + i);
producer.send(record);
} // 4 一定要关闭producer,这样才会调用interceptor的close方法
producer.close();
}
}
3)测试
(1)在kafka上启动消费者,然后运行客户端java程序。
[hadoop1 kafka]$ bin/kafka-console-consumer.sh \
--zookeeper hadoop1:2181 --from-beginning --topic first 1501904047034,message0
1501904047225,message1
1501904047230,message2
1501904047234,message3
1501904047236,message4
1501904047240,message5
1501904047243,message6
1501904047246,message7
1501904047249,message8
1501904047252,message9
(2)观察java平台控制台输出数据如下:
Successful sent: 10
Failed sent: 0
Kafka 之producer拦截器(interceptor)的更多相关文章
- Kafka producer拦截器(interceptor)
Producer拦截器(interceptor)是个相当新的功能,它和consumer端interceptor是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于 ...
- Kafka详解与总结(七)-Kafka producer拦截器(interceptor)
1. 拦截器原理 Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于producer而言,interceptor ...
- Kafka producer拦截器(interceptor)
Kafka producer拦截器(interceptor) 拦截器原理 Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制 ...
- struts2学习笔记--拦截器(Interceptor)和登录权限验证Demo
理解 Interceptor拦截器类似于我们学过的过滤器,是可以在action执行前后执行的代码.是我们做web开发是经常使用的技术,比如权限控制,日志.我们也可以把多个interceptor连在一起 ...
- struts2拦截器interceptor的三种配置方法
1.struts2拦截器interceptor的三种配置方法 方法1. 普通配置法 <struts> <package name="struts2" extend ...
- SSM-SpringMVC-33:SpringMVC中拦截器Interceptor讲解
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 拦截器Interceptor: 对处理方法进行双向的拦截,可以对其做日志记录等 我选择的是实现Handler ...
- 过滤器(Filter)和拦截器(Interceptor)
过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...
- 二十五、过滤器Filter,监听器Listener,拦截器Interceptor的区别
1.Servlet:运行在服务器上可以动态生成web页面.servlet的声明周期从被装入到web服务器内存,到服务器关闭结束.一般启动web服务器时会加载servelt的实例进行装入,然后初始化工作 ...
- Flume 拦截器(interceptor)详解
flume 拦截器(interceptor)1.flume拦截器介绍拦截器是简单的插件式组件,设置在source和channel之间.source接收到的事件event,在写入channel之前,拦截 ...
随机推荐
- YII学习总结2(命名空间和操作响应)
YII基础准备1.命名空间<?php /****假设有三个同名的类,输出的值为A,B,C****/ use a\b\c\apple; use d\e\f\apple as bApple; use ...
- Win10系统下基于Docker构建Appium容器连接Android模拟器Genymotion完成移动端Python自动化测试
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_196 Python自动化,大概也许或者是今年最具热度的话题之一了.七月流火,招聘市场上对于Python自动化的追捧热度仍未消减,那 ...
- springboot的@ConditionalOnClass注解
大家好,我是"良工说技术". 今天给大家带来的是springboot中的@ConditionalOnClass注解的用法.上次的@ConditionalOnBean注解还记得吗? ...
- 小白之Python基础(一)
一.数字类型: 1.整形 十进制:默认为十进制:(如:99,100.......) 十六进制: 0x,0X开头的表示16进制数 二进制:0b,0B开头的表示2进制数 八进制: 0o,0O开头的表示8进 ...
- 编译器工程师眼中的好代码:Loop Interchange
摘要:本文将以Loop Interchange的场景为例,讲述在编写代码时可以拿到更优性能的书写方式. 本文分享自华为云社区<编译器工程师眼中的好代码(1):Loop Interchange&g ...
- 万答#9,MySQL 中有哪些常用的日志
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 前 ...
- 学习javascript知识
开始学习了 努力----努力----努力 从今天开始 绝不 三天打鱼两天晒网 先把基础再巩固一下
- beego下让swagger按照更新了controllers的接口信息自动更新commentsRouter_controllers.go
beego下让swagger按照更新了controllers的接口信息自动更新commentsRouter_controllers.go (1)在beego环境中,当更新了controllers目录下 ...
- Luogu3090 [USACO13NOV]空荡荡的摊位Empty Stalls (动态规划)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> ...
- 第三十九篇:Vue3 watch(ref和reactive的监视)
好家伙, 1.vue2中的watch是调用配置项,(只能写一个) vue3中的watch是一个函数(可以写很多个) 2.watch一些用法: 这里是定义的数据 set up(){ let sum =r ...