Loading

Kafka Consumer和Producer开发

Producer

Producer做的工作

  1. 确认消息发送到的partition,相同key映射到相同分区,无key轮询
  2. 寻找分区的leader所在的Kafka broker,Producer可以选择不同的策略来发送消息
    1. 直接发送成功
    2. leader响应写入操作后成功
    3. ...

Producer异常

Producer发布消息后,不论同步异步,发生异常时都会通知到你。

异常可以分为可恢复异常不可恢复异常两种,前者一般是一些瞬时异常,稍后会自己恢复,所以只需要简单的重试即可:

  1. LeaderNotAvailableException:分区的leader副本不可用,通常出现在leader换届选举期间
  2. NotControllerException:当前controller不可用,可能是controller在经历新一轮选举
  3. NetworkException:网络异常

可恢复异常的父类是RetriableException,发生这些异常时,Producer会在配置的重试次数内进行重试,直到超出该次数才抛给你

不可重试异常比如:

  1. RecordTooLongException
  2. SerializationException
  3. KafkaException

Producer主要参数

acks

acks 指定了在给 producer 发送响应前, leader broker 必须要确保己成功写入该消息的副本数。

  1. acks=0,不等待任何消息确认,甚至无法保证消息被broker接收到,客户端不知道是否故障,每条消息返回的offset都是-1
  2. acks=1,leader写入消息到本地日志后立即响应,不等待follower应答,如果follower同步完成前leader故障,还可能丢消息
  3. acks=all/acks=-1,leader等待所有副本同步后应答给Producer,只要还有一个副本消息就不会丢失

该参数是在吞吐量和消息持久性之间做权衡

compression.type

Producer消息压缩类型,默认是none,即不压缩。

压缩可以降低网络I/O,但会带来额外的CPU压力。需要注意的是,如果压缩类型和broker设置不同,那么broker也需要对该消息进行解压-重压缩的操作。

那样不就让这些数据必须拷贝到Kafka服务器的用户空间,并且对它进行内存操作了吗??

batch.size

Producer的batch大小,即批量发送消息的批大小,默认是16384

linger.ms

消息发送延时,即消息进入batch后,即使batch未满,也要在linger.ms毫秒后发送

batch.sizelinger.ms是吞吐量和消息延时的权衡

其它参数

  • buffer.memory:Producer发送缓冲区大小
  • retries:瞬时故障的重试次数
    • 重试可能造成消息的重复发送,Consumer手动去重
    • 重试可能造成消息的乱序
  • max.request.size:消息请求的最大大小
  • request.timeout.ms:Producer认为多少毫秒内没有得到broker的确认,就认为消息请求超时,抛出TimeoutException

多线程操作Producer

  1. 多线程操作同一个KafkaProducer实例
    1. 实现简单,性能好
    2. 一旦KafkaProducer被破坏,所有线程都无法工作
  2. 多线程操作多个KafkaProducer实例
    1. 线程之间使用不同的Producer实例,不互相影响
    2. 可以独立做更细粒度的配置
    3. 需要较大内存分配开销

Consumer

消费者组

消费者使用一个消费者组名(即 group.id)来标记自己, topic 的每条消息都只会被发送到每个订阅它的消费者组的一个消费者实例上。Kafka使用消费者组的概念实现基于队列和基于发布订阅的模型,即生产者和消费者的映射关系(基于队列是一对一映射,基于发布订阅是一对多映射)。

  1. 队列模式:所有consumer都放到一个group中
  2. 发布订阅:consumer放到不同的group中

Consumer组重平衡:组内多个consumer可以同时读取Kafka消息,一旦其中一个挂了,consumer group会立即将已崩溃的consumer负责的分区转交给其它consumer负责。

image

位移(Offset)

和大多数消息系统不一样,Kafka broker不会记录消费者消费了多少条消息,而是由消费者自己记录Offset,这带来了一些好处

  1. broker无状态,副本间同步成本低
  2. consumer消费成功后不再需要向broker发出ack,如消费失败,它不更新offset即可
  3. broker无需维护复杂的数据结构

需要注意:

  1. consumer会使用检查点机制将offset持久化
  2. consumer需要保存它所订阅的全部topic的分区的offset,可以用一个类似map的结构来存储

位移提交

consumer定期向Kafka集群汇报自己的位移,目前还不知道汇报是为了啥,因为都说了broker不保存这个状态。

旧版本的consumer将唯一信息提交到Zookeeper的固定节点上,而新版本的则提交到Kafka的内部topic——__consumer_offsets上。__consumer_offset有50个,不然的话,所有consumer都向同一个topic写入自己的进度,负载全部堆到了一个topic上。

重平衡(rebalance)

Topic有很多partitions,消费者组中的consumer和这些partitions的对应关系是什么呢?

Kafka是本着平均分配的原则将分区分配给组中所有consumer进行消费的,这意味着如果当前分区数和消费者组中的消费者数量一致,那么每个消费者将消费一个分区。

当消费者组中的消费者数量变动,客户端就会启用重平衡算法,将分区尽量平均的分配到组内每个消费者上

Consumer主要参数

必要参数group.id

除了bootstrap.serverskey.deserializervalue.deserializer,还有一个group.id是必须指定的。

session.timeout.ms

消费者会周期性的发送心跳到它的group coordinator,若到达这个时间还没有收到心跳,broker就将该消费者从它所在分组移除,并启动重平衡。

每一个Consumer Group都会选择一个broker作为自己的group coordinator

该参数在老版本的Kafka中好像还有其它的含义,但现在就是这样

max.poll.interval.ms

消费者两次poll之间的最大间隔,也就是你poll到一条消息之后执行业务所能够花费的最大时间。超过这个时间,消费者会被踢出它的group,并且group重平衡。

heartbeat.interval.ms

发送心跳间隔时间,在当前的网络配置情况下越快越好。

broker决定要让group重平衡时,它是通过heartbeat的response中的字段来下发这个通知的,所以说它越快就能让group更快的响应这次rebalance。

发送心跳的间隔时间(heartbeat.interval.ms)必须小于心跳的超时时间session.timeout.ms,否则consumer还没来得及发送心跳,broker就认为它已经死了。

auto.offset.reset

消费者消费时,若它没指定位移信息或者该位移信息不在当前消息日志的合理区间范围内,该选项决定了要执行的策略。

  1. earliest:自动将位移重置为最早的位移
  2. latest:自动将位移重置为最新的位移
  3. none:抛出异常

connections.max.idle.ms

Kafka会定期的关闭空闲的Socket,该参数是Socket被判定为空闲状态的依据,默认是9分钟。

其它参数

  • enable.auto.commit:consumer是否自动提交位移
  • fetch.max.bytes:consumer单次获取的最大字节数
  • max.poll.records:consumer单次获取的最大消息条数(因为broker有批量返回的行为)
posted @ 2022-10-26 07:17  yudoge  阅读(71)  评论(0编辑  收藏  举报