消息中间件 - 5.消息中间件Kafka生产者端

生产者客户端必要参数配置

  • bootstrap.servers:指定生产者客户端连接Kafka集群所需的broker地址清单。配置单个broker地址也可以获取到集群中所有的broker地址清单,但是配置多个broker地址,可以防止单个broker故障而无法获取其他broker地址的问题处理,提升高可用性。
  • key.serializer和value.serializer:broker端接受的消息必须是以字节数组的形式。该参数分别用来指定key和value序列化操作的序列化器。客户端通常提供了几个默认的序列化器,也可以自定义。
  • client.id:设置生产者客户端的ID。默认为空字符串,则会以producer-{NO}生成。

  1. acks:指定分区中必须要有多少个副本收到这条消息,生产者才会认为消息是写入成功的。
    ack=1(默认值)。表示只要Leader收到消息,生产者就完成消息的发送了;
    ack=0。生产者发送消息之后不需要等待任何服务端的响应;
    acks=all(-1)。生产者必须等待ISR中的所有副本都成功写入消息之后才认为消息是写入成功的。
  2. max.request.size:限制生产者客户端能发送的消息的最大值,默认值1MB。这个配置与message.max.bytes配置的亲密性很高,往往需要相互考虑。
  3. retries和retry.backoff.ms:分别用于配置生产者重试的次数以及每次重试的间隔时间。默认值分别为0和100。
  4. connections.max.idle.ms:空闲连接的在经过多久之后进行关闭。默认值9分钟。
  5. linger.ms:生产者客户端会在 ProducerBatch 被填满或等待时间超过linger.ms值时发送出去。增大该参数可以一定程度上提升吞吐量,但会增加消息的延迟。
  6. request.timeout.ms:请求超时时长。与replica.lag.time.max.ms配置关系密切。
  7. receive.buffer.bytes和send.buffer.bytes:分别用于配置Socket接收消息缓冲区(SO_RECBUF)和 发送消息缓冲区(SO_SNDBUF)的大小。默认值分别为32KB、128KB。
    更多配置名称在org.apache.kafka.clients.producer.ProducerConfig配置类中。

生产者发送消息必要的参数

  • topic:消息主题
  • partition:主题分区。分区存在多种策略,通常是以key作为分区的因子参数。
  • header:消息头部
  • key:消息键
  • value:消息体
  • timestamp:消息的时间戳

生产者消息发送

  • 发后即忘(fire-and-forget):只向kafka发送消息,而不关心是否发送成功。(数据可能会因生产者自身原因丢失,可靠性查,但性能高)。
  • 同步(sync):以阻塞的方式必须等待向kafka发送消息的结果,开发人员可根据响应结果做出不同的处理策略,如:重试、忽略。(能保证数据不会因生产者自身原因丢失,可靠性高,但性能较差,通常必须设置一个合理的超时时长,否则会严重影响业务)
  • 异步(async):以异步非阻塞的方式向等待向kafka发送消息的结果,业务线程可以继续执行,开发人员可根据异步发送的响应结果做出不同的处理策略,如:重试、忽略。(效果类似同步方式,但其性能稍好,强在对业务线程的执行干扰较小,但异常处理会更复杂)

消息在发送之后,可以获取到当前消息所在的分区的一些元数据信息。如:消息的主题、分区号、分区中的偏移量(offset)、时间戳等。 消息发送是常见的异常有:

  1. NetworkException:可能是由于网络瞬时故障而导致的异常。(重试可能会解决)
  2. LeaderNotAvailableException:分区的leader副本不可用。可能leader副本下线而新的 leader 副本选举完成之前。(重试可能会解决)
  3. UnknownTopicOrPartitionException:主题或分区不存在。常发生在主题未创建,分区策略存在问题。(重试可能会解决)
  4. NotEnoughReplicasException:min.insync.replicas配置的数值小于当前集群可用的副本数。当前集群所配置的副本数与创建主题时指定的副本数和是否开启unclean.leader.election.enable配置有关。(重试可能会解决)
  5. NotCoordinatorException:收到的事务ID与协调器不一致。通常发生在broker重新选举之后,生产者尚未感知到。(重试可能会解决)
  6. RecordTooLargeException:发送的消息太大,broker无法处理,不会重试。

消息拦截器

生产者拦截器既可以用来在消息发送前做一些准备工作,比如按照某个规则过滤不符合要求的消息、修改消息的内容等,也可以用来在发送回调逻辑前做一些定制化的需求,比如统计类工作。主要是通过实现org.apache.kafka.clients.producer.ProducerInterceptor接口完成自定义拦截器。拦截器的工作模式是链路模式,即前一个拦截器的拦截之后将会计入到下一个拦截器,拦截器之间以固定书序执行。

消息分区器

生产者在将消息发往broker时,如果未指定分区,则会经过分区器(Partitioner)来确认将当前消息发送到哪一个分区。kafka内置了一个默认的分区器org.apache.kafka.clients.producer.internals.DefaultPartitioner。该分区器在消息的key为null时按照轮训的方式往各个分区均衡的发送消息;当key不为null时则会以key做一个哈希运算并对分区数取模获得要发送的分区号。用户可以通过实现org.apache.kafka.clients.producer.internals.Partitioner接口来自定义分区策略。

消息的序列化器与反序列化器

生产者需要用序列化器(Serializer)把对象转换成字节数组才能通过网络发送给Kafka。同时,消费者需要用反序列化器(Deserializer)把从 Kafka 中收到的字节数组转换成相应的对象。通常消息的序列化器与反序列化器是成对出现的。
kakfa内置了众多序列化器与反序列化器,如:String、ByteArray、ByteBuffer、Bytes、Double、Integer、Long。开发人员还可以通过实现org.apache.kafka.common.serialization.Serializer接口来自定义序列化器,同理亦可以实现反序列化器。

RecordAccumulator(消息累加器) 简介

RecordAccumulator 主要用来缓存消息以便 Sender 线程可以批量发送,进而减少网络传输的资源消耗以提升性能。RecordAccumulator 缓存的大小可以通过生产者客户端参数buffer.memory 配置,默认值为 32MB。如果消息缓冲区满了,使用KafkaProducer发送消息的时候就会被阻塞或者抛出异常,阻塞时间取决于max.block.ms配置的值,默认是60秒。

在这里插入图片描述

在 RecordAccumulator 的内部为每个分区都维护了一个双端队列,队列中的内容就是ProducerBatch,即 Deque<ProducerBatch>。业务线程发过来的所有消息都会按照TopicPartition作为key塞入到对应的一个双端队列的尾部中。队列中的元素ProducerBatch可以包含一条或者多条消息,实际上ProducerBatch使用的是一个ByteBuffer可以被循环利用。当一条消息很大是超过了批量缓存batch.size的大小,就会单独申请一块内存存储,而这块内存时无法回收利用的,当消息发送完之后就会被释放,缓存大小默认16KB。而这些ByteBuffer是由 BufferPool 进行管理复用。


KafkaProducer 实例创建时会启动一个 Sender 线程,从而创建与 bootstrap.servers 中所有 Broker 的 TCP 连接。而这个Sender线程负责从RecordAccumulator中获取批量的消息(一个ProducerBatch中的所有消息)并将其发送到Kafka中。Sender线程在将消息发送往Kafka之前首先会保存在InFlightRequests中,表示该消息已发送但未收到Kafka的响应,从而可以让Sender继续获取消息累加器中的其他消息继续发送,这里实际上与HTTP2.0的并行发送的理念是一致的。但是已发送但未响应的请求的数量是有限的,可以通过max.in.flight.requests.per.connection配置设置(默认值5),当超过该InFlightRequests的个数超过该配置后就会进入阻塞状态,不会继续从累加器中获取消息发送到Kafka。这说明kafka服务端可能存在比较大的负载或是网络连接存在问题。
Sender线程同时也会挑选一个leastLoadedNode(InFlightRequests数最小的节点)向其获取Kafka的元数据信息,如:broker其他地址、分区数量、AR、ISR、控制器节点等。Kafka的元数据信息由于需要被业务线程访问,所以这些信息也是通过synchronized和final关键字来保障线程安全的。

Producer发送消息流程

  1. KafkaProducer会使用业务线程在经过拦截器、序列化器、分区器之后发送到消息累加器(RecordAccumulator)中;
  2. 消息累加器负责将每条消息追加到一个双端队列中,并且队列中的元素是一条多多条的消息;
  3. Sender线程从消息累加器中批量获取消息,并发送到对应的Broker中。

在这里插入图片描述

幂等生产者和事务生产者

消息中间件 - 4.消息中间件Kafka服务端运行机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值