Kafka 0.8 Consumer处理逻辑
0.前言
客户端用法:
kafka.javaapi.consumer.ConsumerConnector consumer = kafka.consumer.Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));
// 决定一个topic启动几个线程去拉取数据,即生成几个KafkaStream;
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, new Integer(threads));
Map<String, List<KafkaStream<byte[], byte[]>>> topicMessageStreams = consumer.createMessageStreams(topicCountMap);
List<KafkaStream<byte[], byte[]>> streams = topicMessageStreams.get(topic);
// 本质是调用了 ZookeeperConsumerConnector
val consumerConnect = new kafka.javaapi.consumer.ZookeeperConsumerConnector(config)
- 一个Topic启动几个消费者线程,会生成几个KafkaStream。
- 一个KafkaStream对应的是一个Queue(有界的LinkedBlockingQueue),有界的参数控制:
queued.max.message.chunks。消费者线程数量决定阻塞队列的个数。 - Fetcher线程是对应topic所在的broker的个数。
因此,分析Consumer,主要是分析ZookeeperConsumerConnector。代码里面,有两个类,它们是什么关系呢?
- kafka.consumer.ZookeeperConsumerConnector:核心类
- kafka.javaapi.consumer.ZookeeperConsumerConnector:对上面那个类的scala数据结构封装,方便Java程序员使用。
0.8.0 和 0.8.2.1
ZookeeperConsumerConnector的源码不一样,下面以0.8.2.1源码为主来分析,也就是从这个版本开始,可以将Offset存在Kafka的Broker中。(关注实现思想,忽略细节。)
1.ZookeeperConsumerConnector 架构
一个Consumer会创建一个ZookeeperConsumerConnector,代表一个消费者进程.
- fetcher: 消费者获取数据, 使用ConsumerFetcherManager fetcher线程抓取数据
- zkClient: 消费者要和ZK通信, 除了注册自己,还有其他信息也会写到ZK中
- topicThreadIdAndQueues: 消费者会指定自己消费哪些topic,并指定线程数, 所以topicThreadId都对应一个队列
- messageStreamCreated: 消费者会创建消息流, 每个队列都对应一个消息流
- offsetsChannel: offset可以存储在ZK或者kafka中,如果存在kafka里,像其他请求一样,需要和Broker通信。可以理解成OffsetManager的一部分。
- scheduler: 后台调度autoCommit
- 还有其他几个Listener监听器,分别用于topicPartition的更新,负载均衡,消费者重新负载等
简述获取数据的流程
- 初始化上面的几个组件,包括与ZK的连接,创建ConsumerFetcherManager,确保连接上OffsetManager(为该ConsumerGroup建立一个OffsetChannel)。
createMessageStreams创建消息流,反序列化message- 通过Fetcher线程拉取数据,放入BlockingQueue来给客户端。
- 客户端启动ZKRebalancerListener,ZKRebalancerListener实例会在内部创建一个线程,这个线程定时检查监听的事件有没有执行(消费者发生变化),如果没有变化则wait 1秒钟,当发生了变化就调用
syncedRebalance方法,去rebalance消费者。
1.1 消费者线程(consumer thread),队列(LinkedBlockingQueue),拉取线程(fetch thread)三者之间关系
以一段代码来说明,消费的topic 12 partition,分配在3台broker机器上。
ConsumerConnector consumer = kafka.consumer.Consumer.createJavaConsumerConnector(createConsumerConfig());
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put("test-string-topic", new Integer(2)); //value表示consumer thread线程数量
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
- consumer thread数量与BlockingQueue一一对应。所以上述的代码只有2个BlockQueue。(它们连接的桥梁是KafkaStream)
- fetcher线程数和topic所在多少台broker有关。因此,共有3个fetcher线程与broker建立一个连接。(3个fetch thread线程去拉取消息数据,最终放到2个BlockingQueue中,等待consumer thread来消费。)
下面是分配的情况:
- 消费者线程,缓冲队列,partitions分布列表如下
| consumer线程 | Blocking Queue | partitions |
|---|---|---|
| consumer thread1 | blockingQueue1 | 0,1,2,3,4,5 |
| consumer thread2 | blockingQueue2 | 6,7,8,9,10,11 |
- fetch thread与partitions分布列表如下
| fetch线程 | partitions |
|---|---|
| fetch thread1 | 0,3,6,9 |
| fetch thread2 | 1,4,7,10 |
| fetch thread3 | 2,5,8,11 |
用户的consumer thread就使用2个BlockingQueue的数据进行处理;所以一般会使用2个consumer thread去消费这2个BlockingQueue数据。
1.2 rebalance的流程
代码上调用:syncedRebalance方法在内部会调用def rebalance(cluster: Cluster): Boolean方法,去执行操作。
- // 关闭所有的数据获取者 closeFetchers
- // 解除分区的所有者 releasePartitionOwnership
- // 按规则得到当前消费者拥有的分区信息并保存到topicRegistry中
topicRegistry=getCurrentConsumerPartitionInfo - // 修改并重启Fetchers updateFetchers
最后,对每个broker创建一个FetcherRunnable线程,并启动它。这个fetcher线程负责从Broker上不断获取数据,对每个partition分别创建FetchRequest,最后把数据插入BlockingQueue的操作。
KafkaStream对ConsumerIterator做了进一步的封装,我们调用stream的next方法就可以取到数据了(内部通过调用ConsumerIterator的next方法实现)
1.3 注意
ConsumerIterator的实现可能会造成数据的重复发送(这要看生产者如何生产数据),FetchedDataChunk是一个数据集合,它内部会包含很多数据块,一个数据块可能包含多条消息,但同一个数据块中的消息只有一个offset,所以当一个消息块有多条数据,处理完部分数据发生异常时,消费者重新去取数据,就会再次取得这个数据块,然后消费过的数据就会被重新消费。
- 没想到里面,里面是这个样子的,给一个数据块,导致了数据消费的重复。
3.美团遇到的一个问题
问题: Kafka中由Consumer维护消费状态,当Consumer消费消息时,支持2种模式commit消费状态,分别为立即commit和周期commit。前者会导致性能低下,做到消息投递恰好一次,但很少使用,后者性能高,通常用于实际应用,但极端条件下无法保证消息不丢失。
解决方案(这个问题太极端情况,不推荐,长个知识)
- 将本来的结果改成下面的处理流程:等待“执行业务逻辑”成功完成后更新缓存消费状态,就可以保证消息不会丢失。
变成下面的:
Kafka 0.8 Consumer处理逻辑的更多相关文章
- Kafka 0.8 Consumer设计解析
摘要 本文主要介绍了Kafka High Level Consumer,Consumer Group,Consumer Rebalance,Low Level Consumer实现的语义,以及适用场景 ...
- Kafka 0.8 Consumer Rebalance
1 Rebalance时机 0.10kafka的rebalance条件 条件1:有新的consumer加入 条件2:旧的consumer挂了 条件3:coordinator挂了,集群选举出新的coor ...
- Kafka 0.8 Producer处理逻辑
Kafka Producer产生数据发送给Kafka Server,具体的分发逻辑及负载均衡逻辑,全部由producer维护. 1.Kafka Producer默认调用逻辑 1.1 默认Partiti ...
- Kafka 0.9+Zookeeper3.4.6集群搭建、配置,新Client API的使用要点,高可用性测试,以及各种坑 (转载)
Kafka 0.9版本对java client的api做出了较大调整,本文主要总结了Kafka 0.9在集群搭建.高可用性.新API方面的相关过程和细节,以及本人在安装调试过程中踩出的各种坑. 关于K ...
- Kafka 0.10.0
2.1 Producer API We encourage all new development to use the new Java producer. This client is produ ...
- Kafka 0.8 配置参数解析
http://kafka.apache.org/documentation.html#configuration Broker Configs 4个必填参数, broker.id Each bro ...
- Kafka 0.10 KafkaConsumer流程简述
ConsumerConfig.scala 储存Consumer的配置 按照我的理解,0.10的Kafka没有专门的SimpleConsumer,仍然是沿用0.8版本的. 1.从poll开始 消费的规则 ...
- 【译】Flink + Kafka 0.11端到端精确一次处理语义的实现
本文是翻译作品,作者是Piotr Nowojski和Michael Winters.前者是该方案的实现者. 原文地址是https://data-artisans.com/blog/end-to-end ...
- Kafka 0.11.0.0 实现 producer的Exactly-once 语义(中文)
很高兴地告诉大家,具备新的里程碑意义的功能的Kafka 0.11.x版本(对应 Confluent Platform 3.3)已经release,该版本引入了exactly-once语义,本文阐述的内 ...
随机推荐
- Python写一个根据日期计算是星期几的模块
import datetimedef get_week_day(date): week_day = { 0: '星期一', 1: '星期二', 2: '星期三', 3: '星期四', 4: '星期五' ...
- 冲刺One之站立会议2
在确定了总体目标之后,我们先决定了实现的具体功能,包括一个登陆界面,一个聊天室的主界面和服务器端的内容.我们今天完成了一小部分内容,把每个内容的主体框架搭建了起来. 效果如下图所示: 燃尽图2
- 安卓开发神器vysor+adb wifi
准备: 1.vysor需要FQ从google应用商店下载,装在google上,目前知道的免费的vysor的作用是电脑显示手机屏幕并且能操控手机. 步骤:FQ后就能下载了,FQ方法不赘述.
- Matlab图像匹配问题
已知一个任意形状,查找在大图像中最接近的形状位置. 输入:一个小图形状和一张大图 输出:最接近的形状在大图中的位置 假设: (1)已知形状与目标形状有一定的形变. (2)形状与大图像均为二值图像,图中 ...
- 信安实践——CSRF攻击与防御
1.实验原理 CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在未授权的 ...
- Hadoop HA 深度解析
社区hadoop2.2.0 release版本开始支持NameNode的HA,本文将详细描述NameNode HA内部的设计与实现. 为什么要Namenode HA? 1. NameNode High ...
- C++ socket网络爬虫(1)
C++写的socket网络爬虫,代码会在最后一次讲解中提供给大家,同时我也会在写的同时不断的对代码进行完善与修改 我首先向大家讲解如何将网页中的内容,文本,图片等下载到电脑中. 我会教大家如何将百度首 ...
- 评论alpha发布以及PSP
讲解顺序: 1. 俄罗斯方块 武志远 俄罗斯方块有自己新颖的玩法加在里面 ,可以进行游戏,界面友好但不美观,与传统玩法相比增加了经验值,这是一个很好的创意,游戏运行也很流畅,并找到两名同学现场体 ...
- appium启动sdk的android模拟器
(1)启动sdk安装目录下的AVD Manager.exe (2)如下图,点击[create]按钮 (3)如下图,设置虚拟机的配置,至于Target中的:Android 4.4.2是在安装sdk的时候 ...
- node入门学习(一)
一.安装node.js 方式很多npm,git等,新手建议从官网上直接去下载node的安装包.一键安装. 二.创建一个web服务器. const http = require('http'); htt ...