Kafka的Producer和Consumer源码学习

来源:互联网 发布:怎么把照片导入mac 编辑:程序博客网 时间:2024/05/16 09:11

本文记录自己的一些理解,盼路过高手指正。

先解释下两个概念:

high watermark (HW)

        它表示已经被commited的最后一个message offset(所谓commited, 应该是ISR中所有replica都已写入),HW以下的消息都已被ISR中各个replica同步,从而保持一致。HW以上的消息可能是脏数据:部分replica写成功,但最终失败了。

Kafka Partition:
1> 均衡各个Broker之间的数据和请求压力;
2> 分摊处理不同的消费者进程;
3> 在partition内可以保证局部有序和状态记录;

Producer发送数据时,Broker的内部处理流程:
        a. Broker Server接到一个Producer request

        b. 会先从ZK中获取该topic的metadata

        c. 进而找到partition的metadata

        d. 从而确定对应的partition leader

        e. 接下来通过该leader partition来append log

         f. 最后计算是否调整leader的High Watermark (它是ISR中所有replica的logEndOffset的最小值与leader的logEndOffset比较得出的最大值)
        当然,Broker Server还要根据Producer request的需要决定是否回复ack给client;

Kafka Producer配置:

Kafka的Producer采用了 linkedBlockingQueue, 所以用户设置的batchNumMessages不能大于queueBufferingMaxMessages.
Producer线程可以设定为定期更新Topic Metadata (topic.metadata.refresh.interval.ms, 若该值为负值,则取消定期更新);但是一旦Producer遇到失败情况(partition missing or leader not available), 她会自动更新Metadata;
message.send.max.retries: Kafka有可能会出现某个partition leader暂时不可访问的情况,这个配置参数描述了Producer在此种情况下最多retry的次数。
compression.codec:           在Producer配置中,该参数指定压缩模式,默认是NoCompressionCodec(对所有Topic都不使用压缩)
compressed.topics:            在compression.codec不是NoCompressionCodec的前提下,则为指定的若干Topic执行写压缩,当compressed.topics为空时则是为所有topic执行压缩。
producer.type:                       sync or async
metadata.broker.list:           Producer通过这个参数指定的Broker来获取Topic Metadata
partitioner.class:                     关于生产者向指定的分区发送数据,通过设置partitioner.class的属性来指定向那个分区发送数据;如果自己指定必须编写相应的程序,默认是kafka.producer.DefaultPartitioner,分区程序是基于散列的键( Utils.abs(key.hashCode) % numPartitions )。
retry.backoff.ms:                  设置Producer在refresh metadata之前要等待的时间 (Producer在每次retry之前都要refresh metadata, 但是可能partition的leader selection等需要一定的执行时间),默认100毫秒;

Kafka Consumer配置:

group.id:                                           指定consumer所属的consumer group
consumer.id:                                    如果不指定会自动生成
socket.timeout.ms:                      网络请求的超时设定
socket.receive.buffer.bytes:        Socket的接收缓存大小
fetch.message.max.bytes:          试图获取的消息大小之和(bytes)
num.consumer.fetchers:             该消费去获取data的总线程数
auto.commit.enable:                       如果是true, 定期向zk中更新Consumer已经获取的last message offset(所获取的最后一个batch的first message offset)
auto.commit.interval.ms:             Consumer向ZK中更新offset的时间间隔
queued.max.message.chunks:  默认为2
rebalance.max.retries:                     在rebalance时retry的最大次数,默认为4
fetch.min.bytes:                              对于一个fetch request, Broker Server应该返回的最小数据大小,达不到该值request会被block, 默认是1字节。
fetch.wait.max.ms:                           Server在回答一个fetch request之前能block的最大时间(可能的block原因是返回数据大小还没达到fetch.min.bytes规定);
rebalance.backoff.ms:                  当rebalance发生时,两个相邻retry操作之间需要间隔的时间。
refresh.leader.backoff.ms:           如果一个Consumer发现一个partition暂时没有leader, 那么Consumer会继续等待的最大时间窗口(这段时间内会refresh partition leader);
auto.offset.reset:                            当发现offset超出合理范围(out of range)时,应该设成的大小(默认是设成offsetRequest中指定的值):
                                                                    smallest: 自动把该consumer的offset设为最小的offset;
                                                                    largest: 自动把该consumer的offset设为最大的offset;
                                                                    anything else: throw exception to the consumer;
consumer.timeout.ms:                 如果在该规定时间内没有消息可供消费,则向Consumer抛出timeout exception;
                                                             该参数默认为-1, 即不指定Consumer timeout;
client.id:                                           区分不同consumer的ID,默认是group.id

Kafka Consumer如何与ZK交互:

/brokers/ids/[0]...[N-1]: N是Broker个数,每个[i]是一个Broker,里面存储着每个Broker相关的信息(ip,port,epoch等);
/brokers/topics/[topic_name]/partitions/[0]...[N-1]/state: N是这个topic的partition数目,state里存放了每个partition的leader及ISR等信息;
                                                                                                     备注: [topic_name]这个znode本身也存储了所有partition对应的leader broker;

/consumers/[group_id]/ids/[consumer_id]/[topic0]-[topicN]: [consumer_id]是一个临时znode, 其子node是该consumer监听的topic
/consumers/[group_id]/offsets/[topic_name]/[partition_id]: [partition_id]结点中的值即为offset
/consumers/[group_id]/owners/[topic_name]: ?(会陆续补充)

ConsumerFetcherThread的内部命名:
                                  "ConsumerFetcherThread-%s-%d-%d".format(consumerIdString, fetcherId, sourceBroker.id)


Kafka消费端如何知道从哪个partition消费,以及如何在多个消费者之间平衡对于多个partition的消费?

目前Broker Server端不会做类似处理,client端可以利用zookeeper来动态分配。(此处还有些不解)

Kafka Consumer在ZK中注册后会监听Broker变化及同组内(Consumer Group)consumer的加入或推出,从而自动实现partitions与consumers的平衡。

关于平衡算法,简单的说就是在实现平衡过程中,尽量保证一个consumer只和尽可能少的Broker维持连接。


IT人的微信自媒体--- 杰天空, 走在寻找创意的路上

发掘创意,点缀生活,品味人生。
请搜索微信订阅号:
jksy_studio ,或者微信扫描头像二维码添加关注


0 0
原创粉丝点击