時間序列資料庫武鬥大會之 KairosDB 篇

OneAPM官方技術部落格發表於2016-04-11

【編者按】 劉斌,OneAPM後端研發工程師,擁有10多年程式設計經驗,參與過大型金融、通訊以及Android手機操作系的開發,熟悉Linux及後臺開發技術。曾參與翻譯過《第一本Docker書》、《GitHub入門與實踐》、《Web應用安全權威指南》、《WEB+DB PRESS》、《Software Design》等書籍,也是Docker入門與實踐課程主講人。本文所闡述的「時間序列資料庫」,系筆者所負責產品 Cloud Insight 對效能指標進行聚合、分組、過濾過程中的梳理和總結。

今天我們來介紹一下 KairosDB.

按照官方的說明,KairosDB 是一個 “Fast Time Series Database on Cassandra”,即基於 Cassandra 的高速時序列資料庫。

特點

資料採集

資料可以通過多種協議寫入 KairosDB,比如 Telnet 的按行寫入,HTTP API,Graphite 以及批處理匯入。此外,還可以使用或者自己編寫外掛。

儲存

KairosDB 採用了 Cassandra 作為資料儲存方式,Cassandra 也是一個比較流行的NoSQL資料庫,很多開源軟體基於此資料庫。

Rest API

KairosDB 提供了 REST API,已完成對 metric 名稱,tag 等的查詢,當然,也少不了儲存和查詢資料點(data points)。

自定義資料型別(Custom Data)

KairosDB 支援儲存和聚合自定義資料型別。預設情況下 KairosDB 支援 long、double 和字串的 value,這比 OpenTSDB 要豐富一些。

分組和聚合

作為資料分析系統,分組和聚合則是必不可少的功能。 KairosDB的聚合(也就是down samples)功能,支援的標準函式有 min、max、sum、count、mean、histogram、gaps 等,而且都非常實用。

比如 percentile,可以計算一個指標值大概的百分比位置,非常適合儲存類似“你打敗了xx%的人”這種需求場景。

支援工具

KairosDB 提供了進行資料匯入匯出的命令列工具。根據官方文件的說明,在一臺分配了 2Gig 記憶體的 SSD Cassandra 上,1 秒鐘能匯入 13 萬條資料。

外掛機制

KairosDB 也提供多種基於 Guice 的外掛機制來進行擴充套件(data point 監聽器,資料儲存,協議處理等。)

KairosDB 是從 OpenTSDB fork 過來的,因此最初它是支援 HBase 的,不過現在 HBase 已經不能完全支援 KairosDB 所需的特性,將來會取消對 HBase 的支援。

入門 KairosDB

安裝 KairosDB

這裡我們以當前最新的1.1.1版本為例進行說明。

首先,需要確保你的JAVA_HOME已經設定好了,且Java版本高於1.6。

$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home

然後需要到 GitHub 上去下載安裝包。我用的是 OS X 系統,因此我選擇了kairosdb-1.1.1-1.tar.gz (注意:點選這個連結即可下載)

解壓後可以看看它的配置檔案conf/kairosdb.properties,有一些東西適合 OpenTSDB 一樣的,比如 4242 埠。

KairosDB 整合了 jetty,你可以通過 jetty 訪問 WEB UI,而且還支援新增 SSL 支援,這樣安全性上比 OpenTSDB 高了一個層級。

配置檔案中還能對 Cassandra 進行設定,比如伺服器地址、keyspace 等。不過預設的話 KairosDB 使用 H2 作為資料儲存,這樣在開發環境下我們就不必配置Cassandra 了。這裡我們也以 H2 為例來初步認識一下 KairosDB,這也是 KairosDB 的預設配置。

所以在這個例子裡,我們不必修改配置檔案,直接啟動 KairosDB 即可:

$ bin/kairosdb.sh run
# 或者
$ bin/kairosdb.sh start

其中run引數會以前臺執行的方式啟動 KairosDB,而start則以後臺程式的方式啟動 KairosDB。

停止 KairosDB 只需要執行bin/kairosdb.sh stop就可以了。

寫入資料

和 OpenTSDB 一樣,KairosDB 也支援基於 telnet 和 HTTP API 的方式寫入資料。

Telnet

Telnet 的方式資料格式很簡單: put <metric_name> <time-stamp> <value> <tag> <tag>... \n 這裡我們就不做演示了。

HTTP API

只需要傳送 JSON 資料到 http://localhost:8080/api/v1/datapoints 就可以了。

這是我們寫入測試資料的方法:
$ curl -v -H "Content-type: application/json" -X POST  http://localhost:8080/api/v1/datapoints -d '
[{
"name": "cpu.load.1",
"timestamp": 1453109876000,
"type": "double",
"value": 0.32,
"tags":{"host":"test-1"}
},
{
"name": "cpu.load.1",
"timestamp": 1453109876000,
"type": "double",
"value": 0.21,
"tags":{"host":"test-2"}
}]
'
* Connected to localhost (::1) port 8080 (#0)
> POST /api/v1/datapoints HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Content-type: application/json
> Content-Length: 262
> 
* upload completely sent off: 262 out of 262 bytes
< HTTP/1.1 204 No Content
< Access-Control-Allow-Origin: *
< Pragma: no-cache
< Cache-Control: no-cache
< Expires: 0
< Content-Type: application/json; charset=UTF-8
< Server: Jetty(8.1.16.v20140903)
< 
* Connection #0 to host localhost left intact

從伺服器返回結果我們可以看到,HTTP 204 狀態碼,也是 KairosDB 成功寫入資料的結果。

查詢資料

同樣 KairosDB 提供了查詢用 API:

$ curl -H "Content-type: application/json" -X POST  http://localhost:8080/api/v1/datapoints/query -d '
{
"metrics": [
{
  "tags": {},
  "name": "cpu.load.1",
  "group_by": [
    {
      "name": JSON"tag",
      "tags": [
        "host"
      ]
    }
  ],
  "aggregators": [
    {
      "name": "sum",
      "align_sampling": true,
      "sampling": {
        "value": "1",
        "unit": "minutes"
      }
    }
  ]
}
],
"cache_time": 0,
"start_absolute": 1453046400000,
"end_absolute": 1453132800000,
"time_zone": "Asia/Chongqing"
}' | jq .

注意上面命令最後的 jq,這是用來對 JSON 資料進行格式化的工具。

最終結果可能像下面一樣:

{
"queries": [
{
  "sample_size": 2,
  "results": [
    {
      "name": "cpu.load.1",
      "group_by": [
        {
          "name": "tag",
          "tags": [
            "host"
          ],
          "group": {
            "host": "test-1"
          }
        },
        {
          "name": "type",
          "type": "number"
        }
      ],
      "tags": {
        "host": [
          "test-1"
        ]
      },
      "values": [
        [
          1453109876000,
          0.32
        ]
      ]
    },
    {
      "name": "cpu.load.1",
      "group_by": [
        {
          "name": "tag",
          "tags": [
            "host"
          ],
          "group": {
            "host": "test-2"
          }
        },
        {
          "name": "type",
          "type": "number"
        }
      ],
      "tags": {
        "host": [
          "test-2"
        ]
      },
      "values": [
        [
          1453109876000,
          0.21
        ]
      ]
    }
  ]
}
]
}

WEB UI

KairosDB 自帶了一個 Web 介面,你可以通過 http://localhost:8080 訪問。不過這個 UI 主要是以開發為目的的,可以看到查詢的 JSON 文字,方便除錯,比較直觀。預設的 UI 使用了 Flot 來畫圖,如果你願意,也可以使用 Highcharts 替換。

Library

KairosDB 目前有一個單獨的 Java Client,在官網還有一些其他語言的客戶端,比如 Python、PHP 等。

由於是 Java 客戶端,所以還是很容易上手的。比如寫入資料:

MetricBuilder builder = MetricBuilder.getInstance();
builder.addMetric("metric1")
    .addTag("host", "server1")
    .addTag("customer", "Acme")
    .addDataPoint(System.currentTimeMillis(), 10)
    .addDataPoint(System.currentTimeMillis(), 30L);
HttpClient client = new HttpClient("http://localhost:8080");
Response response = client.pushMetrics(builder);
client.shutdown();

讀取資料:

QueryBuilder builder = QueryBuilder.getInstance();
builder.setStart(2, TimeUnit.MONTHS)
   .setEnd(1, TimeUnit.MONTHS)
   .addMetric("metric1")
   .addAggregator(AggregatorFactory.createAverageAggregator(5, TimeUnit.MINUTES));
HttpClient client = new HttpClient("http://localhost:8080");
QueryResponse response = client.query(builder);
client.shutdown();

這應該會非常方便,開發起來比 OpenTSDB 要快不少了。

其他API

KairosDB 竟然支援 metric 刪除功能,這個功能會有多少人需要呢?

列出 metric 名、tag 列表、列出 tag 值,說不定有人會喜歡,比如在輸入框自動提示燈功能,可能需要這些後設資料。

列出指標名

這裡除了cpu.load.1是我們自己寫入的 metric,其餘的都是 KairosDB 自己的指標資料。

$ curl http://localhost:8080/api/v1/metricnames | jq .

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                             Dload  Upload   Total   Spent    Left  Speed
100   501    0   501    0     0  45058      0 --:--:-- --:--:-- --:--:-- 50100
{
"results": [
"kairosdb.datastore.query_time",
"kairosdb.protocol.telnet_request_count",
"kairosdb.http.ingest_count",
"kairosdb.datastore.query_row_count",
"cpu.load.1",
"kairosdb.protocol.http_request_count",
"kairosdb.http.ingest_time",
"kairosdb.jvm.thread_count",
"kairosdb.jvm.total_memory",
"kairosdb.jvm.max_memory",
"kairosdb.metric_counters",
"kairosdb.jvm.free_memory",
"kairosdb.datastore.query_sample_size",
"kairosdb.datastore.query_collisions",
"kairosdb.http.query_time",
"kairosdb.http.request_time"
]
}

列出 tag key

這個 API 能列出系統中所有的 tag key。不過遺憾的是它不支援只列出某一給定指標的所有 tag key。

$ curl http://localhost:8080/api/v1/tagnames | jq .

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                             Dload  Upload   Total   Spent    Left  Speed
100    67    0    67    0     0   4188      0 --:--:-- --:--:-- --:--:--  4466
{
"results": [
"method",
"metric_name",
"query_index",
"request",
"host"
]
}

列出 tag value

這個 API 能列出系統中所有的 tag value。同樣遺憾的是它也不支援只列出某一給定指標的所有 tag value。

所以這兩個 API 幾乎可以說是然並卵、無鳥用。

$ curl http://localhost:8080/api/v1/tagvalues | jq .

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                             Dload  Upload   Total   Spent    Left  Speed
100   163    0   163    0     0   5011      0 --:--:-- --:--:-- --:--:--  5093
{
"results": [
"1",
"lius-MacBook-Pro.local",
"tagnames",
"/datapoints/query",
"test-1",
"test-2",
"metricnames",
"query",
"tags",
"version",
"datapoints",
"putm",
"cpu.load.1"
]
}

總結

KairosDB 畢竟是 OpenTSDB 的一個 fork,因此根本上的功能都差不多,而且隨著 OpenTSDB 對 Cassandra 的支援,感覺 KairosDB 相比 OpenTSDB 也沒有什麼太大的優勢。

相關閱讀

這是本系列文章的其他部分:

Cloud Insight 集監控、管理、計算、協作、視覺化於一身,幫助所有 IT 公司,減少在系統監控上的人力和時間成本投入,讓運維工作更加高效、簡單。

本文轉自 OneAPM 官方部落格

相關文章