Druid 消費一個 kafka topic 發送到不同數據源

背景

數據採集時,爲了避免在 kafka 中創建大量的 Topic ,採集時會將小的數據源寫入一個共享 Topic 中,以某個字段作爲標識。這裏有兩種方式:

  1. 直接將標識寫入消息體中
  2. 將標識寫入 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())

源碼修改邏輯

  1. 修改 kafka-indexing-service pom.xml ,將 kafka 依賴版本提高到 1.0 (默認爲 0.10,在 0.11 後才支持 record header 功能)
  2. 定義 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
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章