Druid中从kafka摄入数据,存在两种方式,一种是pull,需要依赖实时节点,一种是push,需要依赖Kafka Indexing Service(kafka索引服务)
注:在0.9.1.1版本前使用Tranquility-Kafka组件接入实时数据,由于存在时间窗口,即在时间窗口内的数据会被提交给Firehose,时间窗口外的数据则会被丢弃;如果Tranquility-Kafka临时下线,会导致Kafka中数据“过期”从而被丢弃,无法保证数据完整性,同时这种“copy service”的使用模式不仅占用大量CPU与内存,又不满足原子操作,所以在0.9.1.1版本后,建议使用Druid的新特性Kafka Indexing Service,Druid内部使用Kafka高级Consumer API保证exactly-once semantics,尽最大可能保证数据完整性。
步骤一:下载Kafka Indexing Service扩展,将扩张加入到druid目录下的extensions目录下。
步骤二:将扩展绑定在middlemanager以及overlord上,在开发中,实际配置方案为直接配置/opt/druid/conf/druid/_common/common.runtime.properties,在druid.extensions.loadList中加入Kafka Indexing Service,如图:
,如果不进行配置,无法使用kafka索引服务
步骤三:在druid目录下的var目录下新建tmp目录作为java.io.tmpdir(jvm.config配置文件)目录。如果目录不存在。Druid报错
步骤四:编写Json配置文件:示例如下
{
"type": "kafka",
"dataSchema": {
"dataSource": "kafka3",//Druid中的表名
"parser": {
"type": "string",
"parseSpec": {
"format": "json",
"timestampSpec": {//时间戳列
"column": "timestamp",
"format": "auto"
},
"dimensionsSpec": {//维度列
"dimensions": ["timestamp","from"],
"dimensionExclusions": []
}
}
},
"metricsSpec": [//指标列
{
"name": "count",
"type": "count"
},
{
"name": "PVSum",
"fieldName": "PVSum",
"type": "longSum"
},
{
"name": "UVSum",
"fieldName": "UVSum",
"type": "longSum"
}
],
"granularitySpec": {//查询维度
"type": "uniform",
"segmentGranularity": "DAY",
"queryGranularity": "NONE"
}
},
"tuningConfig": {//优化型配置
"type": "kafka",
"maxRowsPerSegment": 75000,
"workerThreads":2
},
"ioConfig": {//指明数据来源
"topic": "zhangzl",
"consumerProperties": {
"bootstrap.servers": "ip1:9092,ip2:9092,ip3:9092"
},
"useEarliestOffset":true,
"taskCount": 1,
"replicas": 1,
"taskDuration": "PT1M"
}
}
步骤五: 确认workerThreads配置为(taskCount * replicas +1);
步骤六:调整配置项useEarliestOffset为true,否则druid只会读取最新数据,不会从beginning开始读取数据。
实时节点使用步骤:
注:使用tranquility为0.8.2版本,在使用过程中尝试使用0.8.0版本以及0.8.1版本均为成功,具体原因不明,下载地址:http://static.druid.io/tranquility/releases/tranquility-distribution-0.8.2.tgz
步骤一:将下载好的tranquility-distribution-0.8.2.tgz解压后的目录移动到Druid的home目录下。
步骤二:编辑配置文件,示例如下:
{
"dataSources": [{
"spec": {
"dataSchema": {
"parser": {
"type": "string",
"parseSpec": {
"timestampSpec": {//时间戳列,必须指定,实时节点根据该列对时间窗口进行判断
"column": "timestamp",
"format": "auto"
},
"dimensionsSpec": {//维度列
"dimensions": ["timestamp", "from"],
"dimensionExclusions": []
},
"format": "json"
}
},
"dataSource": "twitter",//Druid中的表名
"granularitySpec": {
"type": "uniform",
"segmentGranularity": "DAY",
"queryGranularity": "NONE"
},
"metricsSpec": [{//指标列
"name": "count",
"type": "count"
},
{
"name": "PVSum",
"fieldName": "PVSum",
"type": "longSum"
},
{
"name": "UVSum",
"fieldName": "UVSum",
"type": "longSum"
}
]
},
"tuningConfig": {
"type": "realtime",
"maxRowsInMemory": "75000",//内存中存储的最大数据量,超过该数据量之后会刷新到Druid中
"intermediatePersistPeriod": "PT1M",//时间窗口
"windowPeriod": "PT10M"//延时窗口,超过时间窗口后的数据,如果还在延时窗口中,则还会被处理,超过延时窗口的数据会被丢弃
}
},
"properties": {
"task.partitions": "2",
"task.replicants": "2",
"topicPattern": "twitter"//kafka topic
}
}],
"properties": {
"zookeeper.connect": "ip1:2181,ip2:2181,ip3:2181",//druid zk
"zookeeper.timeout": "PT20S",
"druid.selectors.indexing.serviceName": "druid/overlord",
"druid.discovery.curator.path": "/druid/discovery",
"kafka.zookeeper.connect": "ip1:2182,ip2:2182,ip3:2182",//kafka zk
"kafka.group.id": "tranquility-kafka",
"consumer.numThreads": "2",
"commit.periodMillis": "15000",
"reportDropsAsExceptions": "false"
}
}
步骤三:进入到目录下使用如下命令:bin/tranquility kafka -configFile <配置文件路径>进行启动
步骤四:使用kafka生产消息,注:时间戳列采用yyyy-MM-ddTHH:mm:ssZ格式,否则数据无法解析,应该可以配置,但未找到配置点。
索引服务与实时节点比较:
在Druid重启时,索引服务不会丢数据,但是对于实时节点,如果重启太慢,数据超过了时间窗口以及延时窗口,这部分数据会被丢弃。
索引服务实际是在指定时间内处理数据,然后将数据积压,可以配置提交时间,到达提交时间时进行提交。
索引服务在Druid重启后,不会重读消费过的数据,也就是offset不会从begining开始,数据不会重叠。
索引服务出现在tranquility服务之后,实际是对实时节点的一个补充,但是索引服务只在0.9.1.1版本之后进行支持