背景
數據採集時,爲了避免在 kafka 中創建大量的 Topic ,採集時會將小的數據源寫入一個共享 Topic 中,以某個字段作爲標識。這裏有兩種方式:
- 直接將標識寫入消息體中
- 將標識寫入 record header 中 (kafka 0.11版本後支持)
Druid 使用 druid-kafka-indexing-service 消費該 Topic 時如何根據 code 寫入不同的 druid 數據源中?
本文基於 druid-0.14.0-incubating
版本實現。
解決辦法
一. 過濾標識在消息體中
這種方式 kafka-index-server 支持原始解析,在數據導入時使用 JSON Flatten Spec 對嵌套 Json 進行轉換,使用 Transform Specs 對字段進行過濾即可。
消息體:其中 code 字段爲標識符,msg 爲真正的消息體
{
"DL_CODE": "code1",
"msg": {
"ts": "1554345838000",
"value": "v1"
}
}
任務描述: 將 DL_CODE = code1
過濾出來並打平 msg 字段,ts字段 作爲時間戳,value 字段作爲維度值。
{
"type": "kafka",
"dataSchema": {
"dataSource": "share_code1",
"parser": {
"type": "string",
"parseSpec": {
"format": "json",
"flattenSpec": {
"fields": [{
"type": "path",
"name": "ts",
"expr": "$.msg.ts"
},
{
"type": "path",
"name": "value",
"expr": "$.msg.value"
}
]
},
"timestampSpec": {
"column": "ts",
"format": "auto"
},
"dimensionsSpec": {
"dimensions": ["value"]
}
}
},
"transformSpec": {
"filter": {
"type": "selector",
"dimension": "code",
"value": "code1"
}
},
"granularitySpec": {
"type": "uniform",
"segmentGranularity": "hour",
"queryGranularity": "none"
}
},
"ioConfig": {
"topic": "metrics",
"consumerProperties": {
"bootstrap.servers": "dp88:9092",
"group.id": "kafka-indexing-service"
},
"taskCount": 1,
"replicas": 1,
"taskDuration": "PT1H"
}
}
二. 過濾標識在 header 中
將過濾標識記錄在 record header 中可以避免對消息體本身進行入侵,不過 kafka-index-server 本身並不支持對 header 的過濾,可以通過修改 druid 源碼的方式實現
消息體本身:
{
"ts": "1554345838000",
"value": "v1"
}
爲消息體增加額外 header 信息, “DL_CODE”
new RecordHeader("DL_CODE", "code2".getBytes())
源碼修改邏輯
- 修改 kafka-indexing-service pom.xml ,將 kafka 依賴版本提高到 1.0 (默認爲 0.10,在 0.11 後才支持 record header 功能)
- 定義 header 過濾參數格式,消費時增加一段邏輯判斷,增加參數的方式有不少,下面說兩種
- 較爲正規的方式是修改 KafkaSupervisorSpec 的內容,擴展新的參數信息,不過該方式改動代碼量較大
- 該改動合進社區的可能性不大,因此可以只需要修改
KafkaRecordSupplier
一個文件,通過在ioConfig.consumerProperties
增加相應字段,並在poll
方法中實現相應過濾邏輯即可(這種方式實現並不優雅,勝在修改代碼量較少,實現方便)
例如增加了 header.filter.*
字段,運行時會首先檢測是否包含相應配置,如果沒有則走默認的消費邏輯,其中 header.filter.key
爲過濾字段,header.filter.value
爲過濾值。
"ioConfig": {
"topic": "metrics",
"consumerProperties": {
"bootstrap.servers": "...",
"group.id": "kafka-indexing-service",
"header.filter.key":"DL_CODE",
"header.filter.value":"code1"
}
從 web console 上可以看到,已經根據不同的 header 信息,寫入了不同的 resource