1.数据生成流程解析
步骤如下:
- 1.Producer创建时,会创建一个Sender线程并设置为守护线程
- 2.生产消息时,内部其实是异步流程;生产的消息先经过拦截器->序列化器->分区器,然后将消息缓存在缓冲区(该缓冲区也是在Producer创建时创建)
- 3.批次发送的条件为:缓冲区数据大小达到batch.size或者linger.ms达到上限,哪个先达到就算哪个
- 4.批次发送后,发往指定分区,然后落盘到broker;如果生产者配置了retrires参数大于0并且失败原因允许重试,那么客户端内部会对该消息进行重试
- 5.落盘到broker成功,返回生产元数据给生产者。
- 6.元数据返回有两种方式:一种是通过阻塞直接返回,另一种是通过回调返回
2. 必要参数配置
2.1. Broker配置
特别说明
- 生产者发送消息到 Kafka 集群,是以推送的方式发送的
- 生产者只需要连接任意一台 Kafka 节点即可
- 生产者发送的消息会被封装成为一个 record 对象,其中包含了发送的主题,分区,key,value
3.序列化器
Kafka中的数据都是字节数组,在将消息发送到Kafka之前需要先将数据序列化为字节数组。序列化器的作用就是用于序列化要发送的消息
Kafka使用 org.apache.kafka.common.serialization.Serializer
接口用于定义序列化器,将泛型指定类型的数据转换为字节数组。
系统提供了该接口的子接口以及实现类:实现类如下
org.apache.kafka.common.serialization.ByteArraySerializer
-org.apache.kafka.common.serialization.ByteBufferSerializer
org.apache.kafka.common.serialization.BytesSerializer
org.apache.kafka.common.serialization.IntegerSerializer
org.apache.kafka.common.serialization.StringSerializer
3.1.自定义序列化器
自定义序列化器需要实现org.apache.kafka.common.serialization.Serializer<T>
接口,并实现其中的 serialize 方法
生产者定义自定义序列化器
4.分区器
默认(DefaultPartitioner)分区计算:思考:发送出去的消息是如何进行分区的呢?
- 1.如果是指定了分区,那么就会按照指定的分区将所有的 value 都发送到一个分区中(优先级最高)
- 如果是指定了 key 但是没有指定分区,那么就会按照 DefaultPartitioner 这个类进行分区,底层使用 hash 取模的方式进行分区
1.会首先在可用的分区中分配分区号
2.如果没有可用的分区,则在该主题所有分区中分配分区号
如果是没有指定分区和 key,那么就会按照轮循的方式进行循环分区。
4.可以自定义分区类(根据 DefaultPartitioner 来进行模仿即可)
在这个过程中的 key 只是逻辑上的一个业务标记(key 是可以重复的),而 value 才是消息中的真正内容
4.1. 自定义分区器
自定义分区器步骤;
- 首先开发Partitioner接口的实现类
在KafkaProducer中进行设置:configs.put("partitioner.class", "xxx.xx.Xxx.class")
位于 org.apache.kafka.clients.producer
中的分区器接口:
仿照org.apache.kafka.clients.producer.internals
中分区器的默认实现进行实现自定义分区器
-生产者
5. 拦截器
image
Producer拦截器(interceptor)和Consumer端Interceptor是在Kafka 0.10版本被引入的,主要用于实现Client端的定制化控制逻辑。
对于Producer而言,Interceptor使得用户在消息发送前以及Producer回调逻辑前有机会对消息做一些定制化需求,比如修改消息等。同时,Producer允许用户指定多个Interceptor按序作用于同一条消息从而形成一个拦截链(interceptor chain)。Intercetpor的实现接口是org.apache.kafka.clients.producer.ProducerInterceptor,其定义的方法包括:
- onSend(ProducerRecord):该方法封装进KafkaProducer.send方法中,即运行在用户主线程中。Producer确保在消息被序列化以计算分区前调用该方法。用户可以在该方法中对消息做任何操作,但最好保证不要修改消息所属的topic和分区,否则会影响目标分区的计算。
- onAcknowledgement(RecordMetadata, Exception):该方法会在消息被应答之前或消息发送失败时调用,并且通常都是在Producer回调逻辑触发之前。onAcknowledgement运行在Producer的IO线程中,因此不要在该方法中放入很重的逻辑,否则会拖慢Producer的消息发送效率。
- close:关闭Interceptor,主要用于执行一些资源清理工作。
如前所述,Interceptor可能被运行在多个线程中,因此在具体实现时用户需要自行确保线程安全。另外倘若指定了多个Interceptor,则Producer将按照指定顺序调用它们,并仅仅是捕获每个Interceptor可能抛出的异常记录到错误日志中而非在向上传递。这在使用过程中要特别留意。
5.1 自定义拦截器
自定义拦截器步骤:
- 实现ProducerInterceptor接口
在KafkaProducer的设置中设置自定义的拦截器
自定义拦截器1
自定义拦截器2
生产者
运行结果: 说明拦截器生效