Kafka—Storm之KafkaSpout和KafkaBolt源码解释
来源:互联网 发布:whisper是什么软件 编辑:程序博客网 时间:2024/06/07 03:34
转载来自:http://blog.csdn.net/ransom0512/article/details/50497261
另一个比较详细的KafkaSpout详解见:http://www.cnblogs.com/cruze/p/4241181.html
Storm-Kafka源代码解析
说明:本文所有代码基于Storm 0.10版本,本文描述内容只涉及KafkaSpout和KafkaBolt相关,不包含trident特性。
Kafka Spout
KafkaSpout的构造函数如下:
- 1
- 2
- 3
- 1
- 2
- 3
其构造参数来自于SpoutConfig对象,Spout中用到的所有参数都来自于该对象。该对象参数说明如下:
SpoutConfig
SpoutConfig继承自KafkaConfig。两个类内部所有参数及说明如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
ZKHost中保存了kafka集群所在的zookeeper地址等信息
ZKHost
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
KafkaSpout初始化
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
以上是kafkaSpout的初始化方法,主要是完成对自身管理分区信息的刷新。
这里有一个问题,就是会创建3个zookeeper客户端连接,一个用来从kafka中读取数据,一个保存offset,一个是metrics监控信息,每个zookeeper客户端连接会创建3个线程,这样,光一个kafkaSpout就会存在9个zookeeper线程!当worker进程中有多个spout实例的时候,就会产生更多的线程,这就会很消耗性能,这个还是建议对zookeeper连接进行合并处理。
系统通过KafkaUtils.calculatePartitionsForTask方法来获取自己需要管理的分区列表:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
其中,taskIndex就对应自身spout实例的序号,比如该spout并发度为3,那么这个spout实例就可能为0,1,2。当kafka的topic有5个分区的时候,第一个spout实例管理0,3的分区;第二个spout实例管理编号为1,4的分区,第三个spout实例管理编号为2的分区。
taskId保存在Spout的Open方法的context参数中。context.getThisTaskIndex()
KafkaSpout从Kafka中如何读取数据并发送
kafkaSpout主要在nextTuple方法中读取数据并emit。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
数据发送状态EmitState一共有三种状态
- EMITTED_MORE_LEFT
上次取到的数据还没有emit完毕- EMITTED_END,
上次取到的数据已经全部emit完毕- NO_EMITTED
本次没有取到数据,没有可供emit的数据
再来看下PartitionManager.next方法,里面就包含如何获取数据已经如何emit
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
当有数据发送失败的时候,失败的数据又会重新加入到_waitingToEmit队列中,这样就会产生一个问题,就是当数据发送失败的时候,kakfaSpout会永远只读一个分区,前天分区都不会读取,从而产生数据消费不均匀的问题。
在0.9.6以前老版本的时候哟一个问题,就是当较多数据emit失败的时候,会有很多的数据在不断重试,然后重试不断超时,又不断重新加入重试列表,从而导致一个数据发送的死循环。这个问题也就是offset超时的问题。见Storm-643, 这个问题目前在最新版本中已经解决。
KafkaBolt
KafkaBolt就比较简单,0.10版本还是使用old Producer API。
Storm所有的配置属性,都在kafka.broker.properties中保存着,这就要求在submitTopology的时候,在topologyConf中再put一个kafka.broker.properties属性,形成一个map中套map的结构。这样有一点不好的就是一个拓扑中数据只能写到一个kafka集群中,不支持同事写到多个kafka集群中。不过这个在0.11新版本中已经解决了,kafka.broker.properties被作为了一个局部变量,可以在不同的bolt实例中保存不同的配置属性。
数据写入方法如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
Storm-Kafka FAQ
KafkaSpout
- KafkaSpout excutor数量和Kafka topic分区数量的关系
当executor并发度大于topic数量的时候,就会存在有的spout实例可以读到数据, 有的spout实例读不到数据。
当executor并发度小于topic数量的时候,就会存在一个spout实例对应多个分区的情况;kafka会先从一个分区中取一次数据,当这次获取的数据emit完毕之后,就会再从下个分区中取数据。
当executor并发度等于topic数量的时候,一个spout实例对应一个分区。在实际应用中,我们也推荐这种配置方式。- 如何从kafka中读取数据,每次读取多少数据
根据fetchSizeBytes参数的配置,默认每次取1MB数据。- 数据读取失败如何处理
KafkaSpout每个PartitionManager内部保存一个重试队列,当数据发送失败的时候,加入重试队列,然后重新发送,直到成功为止。
通过maxOffsetBehind参数来解决failed数量过多导致内存溢出问题。- Topic不存在如何处理
直接报错。- 拓扑重新提交,会不会接着上次位置继续读取数据
重新提交的时候,只要id这个参数不变,那么就会沿着上次位置继续读取数据。- zookeeper中保存的kafka的offset位置有错误怎么办?
会抛出offsetOutofRange异常,然后默认从kafka分区队列最早位置开始读取数据。- 能不能在一个spout中从多个topic读取数据?
在0.10版本不行,在0.11版本中,支持按照正则方式匹配topic名称,可以从所有满足正则条件的topic中读取数据。- topic分区主备信息发生变化,如何处理
抛出异常,然后马上更新分区信息,再次读取数据。
KafkaBolt
- 写入数据,kafka topic不存在怎么办?
如果kakfa服务端允许自动创建topic,那么就会自动创建topic。
如果不允许自动创建,那么就会抛出异常- 如何写数据到指定分区?
取决于tupleToKafkaMapper的接口实现。
kafka 0.10版本使用的是old producer的API,0.11版本使用的是new Producer的API
对于old Producer
如果key == null,那么在kafka中,会随机寸照一个分区去写入数据,之后只要不重启,就都会往这个分区写入数据
如果key != null,那么就会在写入数据的时候,以utils.abs(key.hashCode)%numPartitions规则计算分区id
对于New Producer
如果key = null,那么就会使用一个递增的int值,每次发送数据的时候递增,然后执行utils.abs(nextValue)%availablePartitions.size(),数据写入会比较均衡。
如果key != null,那么就会按照Utils.abs(Utils.murmur2(record.key()))%numPartitions的规则计算分区。
当然,New Producer API也可以手工指定分区id。
- Kafka—Storm之KafkaSpout和KafkaBolt源码解释
- (五)storm-kafka源码走读之KafkaSpout
- 【配置】Storm和Kafka的对接:KafkaSpout
- (三)storm-kafka源码走读之如何构建一个KafkaSpout
- Storm-Kafka模块之写入kafka-KafkaBolt的使用及实现
- STORM入门之(集成KafkaBolt)
- kafkaspout+storm
- STORM入门之(集成KafkaSpout)
- storm的kafkaSpout实例
- 解析storm的KafkaSpout
- storm-kafka源码分析
- (一)storm-kafka源码走读之前言
- (四)storm-kafka源码走读之自定义Scheme
- (六)storm-kafka源码走读之PartitionManager
- Storm之——Kafka+Storm+HDFS整合实战
- storm-kafka-plus源码阅读
- KafkaSpout之PartitionManager
- storm和kafka整合案例
- 浅谈JavaScript继承
- Audio
- 字符串的属性应用
- 安卓滑动导航栏
- 基本UI
- Kafka—Storm之KafkaSpout和KafkaBolt源码解释
- BTrace使用
- 【技术】Eclipse加入JSON文件校验插件
- Android子线程更新UI的方法
- 在 Ubuntu 14.04 安装 MySQL 5.7 和 Python 2.7.12
- leetcode 167. Two Sum II
- 事件机制
- [lintcode]-链表 删除链表中的元素
- 使用FileProvider