Kafka01--Kafka生产者使用方式
Kafka之--生产者入门
前言:
Kafka诞生至今,产生两个版本的生产者客户端:1是早期基于scala语言编写的客户端;2是随着Java用户的广泛涌入,kafka0.9版本开始退出Java版本的客户端;
一个基本生产者producer逻辑需要具备以下基本条件:
- 配置Producer,创建生产者实例;
- 构建待发送消息;
- 发送消息;
- 关闭生产者实例;
KafkaProducer必要参数和常用参数配置:
必要参数:
bootstrap.servers:待连接的broker地址;
- key.serializer和value.serializer:kafka中的消息都需要转化为字节数组byte[]进行传递,一般会使用到改参数指定key和value的序列化方式。对应的服务端的参数配置中需要有反序列化参数配置,他们是对应的。
KafkaProducer是线程安全的,可以在多个线程中共享单个KafkaProducer实例,或者进行池化,这样方便了使用。在实际使用中,可以通过Java配置方式,在项目启动时进行生产端的初始化,生成对应的实例即可。
可选参数,部分参数没有列出:
- acks :消息发送到某个partition,该参数指定需有多少个副本同步确认后,服务端才会向客户端确认消息发送成功。有三个String的值可配置:
- “1”:默认值。leader副本写入即可确认;
- “0”:生产者只管发送,不需要服务端确认;
- "-1"或者"all":ISR集合中的所有副本确认之后,才会确认;(若ISR中只有leader副本,那仍然无法百分百可靠)
- max.request.size :客户端一条消息容量的最大值,默认为1M。
- retries ,retry.backoff.ms :生产者发送异常时的重试次数和两次重试间的时间间隔。
- max.in.flight.request.per.connection :默认值为5,限制客户端与Node之间最多缓存的请求数量。
- Kafka只能保证一个partition中的消息是有序的。当缓存数>1,且配置重试机制后,有可能出现先发送的消息异常,后发送消息成功,然后先发送的消息重试,这样两条消息的顺序就出现了错乱。若要保证顺序,建议将connection置为1.
- linger.ms :指定生产者发送ProducerBatch之前等待更多消息的写入,默认为0。当batch满了或者linger时间到了,才会 发送。
- request.time.out :生产者发送消息后等待响应的最长时间。
KafkaProducer发送消息:
kafka消息的发送需要通过构建ProducerRecoder对象来实现,该类的属性有:
private final String topic;
private final Integer partition;
private final Headers headers;
private final K key;
private final V value;
private final Long timestamp;
其中,最简的一种使用只需要指定topic和消息体即可。`ProducerRecord<String, String> record = new ProducerRecord<>(topic, "hello, Kafka!");
Kafka有三种发送消息的模式:
- 发送即忘:KafkaProducer只管发送,不管有没有发送成功。
- 同步模式:KafkaProducer发送后阻塞,一致等到Server端返回消息或者抛出异常;(Server端一般有多个副本,多副本的消息确认机制等到服务端介绍时再说);
- 同步模式下,可以根据返回的数据进行进一步的业务处理,比如返回的partition,offset等;
异步模式:通过CallBack回调函数,对服务端响应后的事件进一步处理,;
示例代码如下:
1 public static void main(String[] args) {
2 Properties properties = new Properties();
3 properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerList);
4 properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
5 properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
6 KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
7 ProducerRecord<String, String> record = new ProducerRecord<>(topic, "hello, Kafka!");
8 try {
9 /**①:发送不管*/
10 producer.send(record);
11 /**②:同步发送:通过调用get方法,进行阻塞,可以通过Future获取发送结果,进行业务逻辑处理*/
12 producer.send(record).get();//同步发送
13 Future<RecordMetadata> future = producer.send(record);
14 RecordMetadata metadata = future.get();
15 //分区为:0偏移量为:240048
16 System.out.println("分区为:" + metadata.partition() + "偏移量为:" + metadata.offset());
17 /**③:异步发送:KafkaProducer将发送请求暂存,当服务端response响应后,从中取出对应的发送请求,然后调用回调函数*/
18 producer.send(record, new Callback() {
19 @Override
20 public void onCompletion(RecordMetadata metadata, Exception exception) {
21 if (exception != null){
22 exception.printStackTrace();
23 }else {
24 //分区为:0偏移量为:240048
25 System.out.println("分区为:" + metadata.partition() + "偏移量为:" + metadata.offset());
26 }
27 }
28 });
29 } catch (Exception e) {
30 e.printStackTrace();
31 }
32 producer.close();
33 }
三种发送模式-示例代码
KafkaProducer消息序列化:
生产端和消费端的序列化方式要一一对应,一般而言,会将消息进行json话之后发送,因此一般指定为kafka自带的StringSerializer类即可;
KafkaProducer分区器:
1、生产端将消息发送到broker时,可能要经过拦截器,序列化器,分区器等一系列节点进行处理。默认情况下,Kafka中的消息在发送前,会经过 DefaultPartation 默认分区器进行处理,其从父类实现了两个方法, close(...) 主要进行分区器关闭之后的资源回收。 partition(...) 主要就进行分区的分配,返回int值。configure(...)方法继承自Configurable接口,可以用来获取配置信息和初始化数据,这里只是空实现。
* @param key The key to partition on (or null if no key) key的值
* @param keyBytes serialized key to partition on (or null if no key) key序列化后的值
* @param value The value to partition on or null value值,待发送内容值
* @param valueBytes serialized value to partition on or null value值序列化后的值
* @param cluster The current cluster metadata 集群的元数据信息,包含一些分区数量等信息;
*/
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster
由上面的ProducerRecoder的属性可知,可以在发送消息时,指定消息发送到哪个分区。若采用默认的分区器 DefaultPartation则会包含以下两种情况:
- key为null,消息以轮询的方式发送消息到 topic 中的所有可用分区;
- key不为null,对key进行hash,通过hash值计算分区号,相同key的消息会被发送到同一个分区。
采用默认分区器时,不改变分区的数量,那么key与分区号的映射关系时对应的。若增加一个分区,那么相同的key在增加分区后,就可能不在同一个分区中了。
2、若采用自定义分区器,完全可以根据业务需要,进行自定义分配规则,只需继承父类 Partitioner ,并在生产端配置中加入分区器配置即可,代码示例如下:
//配置中指定分区器
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, DemoPartitioner.class);
...
//因为用了字符串序列化方式,消息体中指定key值为字符串“1”。(这里是根据key值进行分区分配的)
ProducerRecord<String, String> record = new ProducerRecord(topic,"1", "hello, Kafka!");
自定义分区器的示例代码如下:
public class DemoPartitioner implements Partitioner {
//原子类,线程安全
private final AtomicInteger counter = new AtomicInteger(0); @Override
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
//获取可用分区
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
int numPartitions = partitions.size();
// if (null == keyBytes) {
// return counter.getAndIncrement() % numPartitions;
// } else
// return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;
if (key.toString() == "0"){
return 0;
}else
return 1;
} @Override
public void close() {
} @Override
public void configure(Map<String, ?> configs) {
}
}
自定义分区器
通过send之后的Future,可以观察到消息确实发送到了不同的分区中。
KafkaProducer拦截器:
拦截器分生产者拦截器和消费者拦截器(后续介绍);
生产者拦截器的作用时间点:
- 消息序列化和计算分区之前,调用生产者拦截器的 onSend() 方法进行个性化操作;
- 消息被服务端应答,或者发送失败时,调用 onAcknowledgement() 方法进行处理,该操作优先于回调函数。
Kafka中提供了父接口 ProducerInterceptor 方便用户进行自定义的拦截器实现,比如可以在自定义的拦截器中对kafka消息的发送数量进行统计:
注:通过onAcknowledgement()统计发送成功与失败数量,而不是 onSend()方法;
public class HawkKafkaProducerInterceptor implements ProducerInterceptor<String, String> { @Override
public ProducerRecord<String, String> onSend(ProducerRecord<String, String> producerRecord) {
return producerRecord;
} @Override
public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {
if (e == null) {
/// success
Cat.logEvent(HawkConstants.KAFKA_PRODUCER_EVENT_TYPE, recordMetadata.topic());
} else {
/// failed
Cat.logEvent(HawkConstants.KAFKA_PRODUCER_EVENT_TYPE, recordMetadata.topic(), HawkConstants.EVENT_FAILED_STATUS, null);
}
} @Override
public void close() { } @Override
public void configure(Map<String, ?> map) { }
}
自定义拦截器统计消息发送数量
然后需要在配置文件中加入该拦截器:
// 只配置一个拦截器
props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, HawkKafkaProducerInterceptor.class.getName()); // 若想配置多个拦截器,形成拦截链,则配置顺序即为拦截顺序,以“,”隔开(注意,若拦截器2完全依赖拦截器1的结果,则不利于稳定性)
props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, "Intercepter01"+","+"Intercepter02);
Kafka01--Kafka生产者使用方式的更多相关文章
- Kafka集群安装部署、Kafka生产者、Kafka消费者
Storm上游数据源之Kakfa 目标: 理解Storm消费的数据来源.理解JMS规范.理解Kafka核心组件.掌握Kakfa生产者API.掌握Kafka消费者API.对流式计算的生态环境有深入的了解 ...
- 【转】 详解Kafka生产者Producer配置
粘贴一下这个配置,与我自己的程序做对比,看看能不能完善我的异步带代码: ----------------------------------------- 详解Kafka生产者Produce ...
- Python 使用python-kafka类库开发kafka生产者&消费者&客户端
使用python-kafka类库开发kafka生产者&消费者&客户端 By: 授客 QQ:1033553122 1.测试环境 python 3.4 zookeeper- ...
- Kafka权威指南 读书笔记之(三)Kafka 生产者一一向 Kafka 写入数据
不管是把 Kafka 作为消息队列.消息总线还是数据存储平台来使用 ,总是需要有一个可以往 Kafka 写入数据的生产者和一个从 Kafka 读取数据的消费者,或者一个兼具两种角色的应用程序. 开发者 ...
- java实现Kafka生产者示例
使用java实现Kafka的生产者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...
- kafka生产者和消费者流程
前言 根据源码分析kafka java客户端的生产者和消费者的流程. 基于zookeeper的旧消费者 kafka消费者从消费数据到关闭经历的流程. 由于3个核心线程 基于zookeeper的连接器监 ...
- JAVA封装消息中间件调用一(kafka生产者篇)
这段时间因为工作关系一直在忙于消息中间件的发开,现在趁着项目收尾阶段分享下对kafka的一些使用心得. kafka的原理我这里就不做介绍了,可参考http://orchome.com/kafka/in ...
- Kafka生产者----向kafka写入数据
开发者可以使用kafka内置的客户端API开发kafka应用程序.除了内置的客户端之外,kafka还提供了二进制连接协议,也就是说,我们直接向kafka网络端口发送适当的字节序列,就可以实现从Kafk ...
- 了解Kafka生产者
了解Kafka生产者 之前对kafka的整体架构有浅显的了解,这次正好有时间,准备深入了解一下kafka,首先先从数据的生产者开始吧. 生产者的整体架构 可以看到整个生产者进程主要由两个线程进 ...
- kafka生产者和消费者api的简单使用
kafka生产者和消费者api的简单使用 一.背景 二.需要实现的功能 1.生产者实现功能 1.KafkaProducer线程安全的,可以在多线程中使用. 2.消息发送的key和value的序列化 3 ...
随机推荐
- Java基于ClassLoder/ InputStream 配合读取配置文件
阅读java开源框架源码或者自己开发系统时配置文件是一个不能忽略的,在阅读开源代码的过程中尝尝困惑配置文件是如何被读取到内存中的.配置文件本身只是为系统运行提供参数的支持,个人阅读源码时重点不大可能放 ...
- Spring Cloud之微服务注册到Eureka Server集群后访问改造
上篇Spring Cloud之服务注册中心搭建Eureka Server服务注册中⼼ - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)已经已经成功将两个微服务注册到集群中,那么能正常能与注 ...
- io流复习+代码演示
前置知识: 序列化和反序列化 1.序列化就是在保存数据时, 保存数据的值和数据类型 2.反序列化就是在恢复数据时, 恢复数据的值和数据类型 3.需要让某个对象支持序列化机制,则必须让其类是可序列化的, ...
- CLR 详解
公共语言运行时就是按照CLI标准制作的执行托管代码的环境.CLR 能运行非托管代码. 公共语言运行的功能:代码JIT/AOT编译. 内存管理 .垃圾回收.异常处理.反射服务.安全服务.程序集加载.本 ...
- Hive数子IP与字符串IP之间的转换
字符串IP:247.164.62.58 对应的 数字IP:4154736186 数子IP=>字符串IP select concat_ws('.',conv(substr(hex(41547 ...
- Spring5框架学习笔记(详细)
目录 01 Spring框架概述 02 IOC容器 IOC概念和原理 IOC BeanFactory接口 IOC操作 Bean管理(概念) IOC操作 Bean管理(基于xml方式) IOC操作 Be ...
- Hadoop权威指南 - 学习笔记
初识Hadoop.关于MapReduce Hadoop宏观介绍 相对于其他系统的优势 关系型数据库管理系统 为什么不能用配有大量硬盘的数据库进行大规模分析?为什么需要Hadoop? 因为计算机硬盘的发 ...
- kibana实现条件查询和修改
GET jyb_report_index_preprod/_search { "query": { "match": { "report_id&quo ...
- python初略复习(2)及python相关数据分析模块的介绍
常用模块 Python中的模块在使用的时候统一都是采用的句点符(.) # 就是模块名点方法的形式 import time time.time() import datetime datetime.da ...
- 昇思MindSpore全场景AI框架 1.6版本,更高的开发效率,更好地服务开发者
摘要:本文带大家快速浏览昇思MindSpore全场景AI框架1.6版本的关键特性. 全新的昇思MindSpore全场景AI框架1.6版本已发布,此版本中昇思MindSpore全场景AI框架易用性不断改 ...