aliyun-timestream は、Elastic コミュニティが提供する時系列製品の機能に基づいて、Alibaba Cloud Elasticsearch チームによって開発されたプラグインです。 このプラグインを使用すると、API を使用して時系列インデックスの作成、削除、変更、およびクエリを実行し、インデックスにデータを書き込み、インデックス内のデータをクエリできます。 このトピックでは、aliyun-timestream プラグインを使用して Alibaba Cloud Elasticsearch クラスタ内の時系列データを管理する方法について説明します。
背景情報
aliyun-timestream プラグインは、ドメイン固有言語 ( DSL ) ステートメントではなく PromQL ステートメントを使用して、保存されているメトリックデータをクエリします。 これにより、クエリ操作が簡素化され、クエリ効率が向上します。 また、プラグインはストレージコストも削減します。 詳細については、「aliyun-timestream の概要」をご参照ください。このトピックでは、aliyun-timestream プラグインの使用方法について説明します。 関連 API の詳細については、「aliyun-timestream でサポートされている API の概要」および「aliyun-timestream と Prometheus API の統合」をご参照ください。
前提条件
次のバージョン要件を満たす Elasticsearch クラスタが作成されていること。クラスタのバージョンが V7.10 で、クラスタのカーネルバージョンが V1.8.0 以降であること、またはクラスタのバージョンが V7.16 以降で、クラスタのカーネルバージョンが V1.7.0 以降であること。Elasticsearch クラスタの作成方法については、「Alibaba Cloud Elasticsearch クラスタの作成」をご参照ください。
時系列インデックスの管理
時系列インデックスの作成
PUT _time_stream/test_streamAPI を呼び出して作成されたインデックスは、PUT test_stream コマンドを実行して作成されたインデックスとは異なります。 API を呼び出して作成されたインデックスは、特定のインデックスではなくデータストリームです。 このインデックスは、時系列シナリオにおける Elasticsearch ベストプラクティスの構成を統合しています。
GET _time_stream/test_stream{
"time_streams" : {
"test_stream" : {
"name" : "test_stream",
"data_stream_name" : "test_stream",
"time_stream_config" : {
"labels_fields" : {
"includes" : [
"labels.*"
],
"excludes" : [ ]
},
"metrics_fields" : {
"includes" : [
"metrics.*"
],
"excludes" : [ ]
},
"label_prefix" : "labels.",
"metric_prefix" : "metrics.",
"downsample" : [ ]
},
"template_name" : ".timestream_test_stream",
"template" : {
"index_patterns" : [
"test_stream"
],
"template" : {
"settings" : {
"index" : {
"mode" : "time_series",
"codec" : "ali",
"refresh_interval" : "10s",
"ali_codec_service" : {
"enabled" : "true",
"source_reuse_doc_values" : {
"enabled" : "true"
}
},
"translog" : {
"durability" : "ASYNC"
},
"doc_value" : {
"compression" : {
"default" : "zstd"
}
},
"postings" : {
"compression" : "zstd"
},
"source" : {
"compression" : "zstd"
},
"routing_path" : [
"labels.*"
]
}
},
"mappings" : {
"numeric_detection" : true,
"dynamic_templates" : [
{
"labels_template_match_labels.*" : {
"path_match" : "labels.*",
"mapping" : {
"time_series_dimension" : "true",
"type" : "keyword"
},
"match_mapping_type" : "*"
}
},
{
"metrics_double_match_metrics.*" : {
"path_match" : "metrics.*",
"mapping" : {
"index" : "false",
"type" : "double"
},
"match_mapping_type" : "double"
}
},
{
"metrics_long_match_metrics.*" : {
"path_match" : "metrics.*",
"mapping" : {
"index" : "false",
"type" : "long"
},
"match_mapping_type" : "long"
}
}
],
"properties" : {
"@timestamp" : {
"format" : "epoch_millis||strict_date_optional_time",
"type" : "date"
}
}
}
},
"composed_of" : [ ],
"data_stream" : {
"hidden" : false
}
},
"version" : 1
}
}
}| パラメーター | 説明 |
| index.mode | 値 time_series は、インデックスタイプが time_series であることを示します。システムは、時系列シナリオにおける Elasticsearch ベストプラクティスの構成をインデックスに自動的に統合します。 |
| index.codec | 値 ali は、aliyun-codec インデックス圧縮プラグイン が使用されることを示します。このパラメーターは、以下のパラメーターと共に使用して、占有されるディスク容量を削減できます。
|
- ディメンションフィールド: デフォルトでは、keyword タイプが使用されます。 ディメンションフィールドの time_series_dimension の値は true です。 index.mode の値が time_series の場合、time_series_dimension が true であるすべてのフィールドは、_tsid という名前の内部タイムラインフィールドに結合されます。
- メトリックフィールド: double タイプと long タイプがサポートされています。 メトリックフィールドは doc 値のみを保存し、インデックスデータは保存しません。
- インデックスのプライマリシャード数をカスタマイズする
PUT _time_stream/test_stream { "template": { "settings": { "index": { "number_of_shards": "2" // プライマリシャード数を 2 に設定 } } } } - インデックスのデータモデルをカスタマイズする
PUT _time_stream/test_stream { "template": { "settings": { "index": { "number_of_shards": "2" // プライマリシャード数を 2 に設定 } } }, "time_stream": { "labels_fields": ["labels_*"], // ラベルフィールドのプレフィックスを指定 "metrics_fields": ["metrics_*"] // メトリックフィールドのプレフィックスを指定 }
時系列インデックスの更新
POST _time_stream/test_stream/_update
{
"template": {
"settings": {
"index": {
"number_of_shards": "4" // プライマリシャード数を 4 に更新
}
}
}
}- 更新コマンドを実行する際は、更新する必要のない構成は保持する必要があります。 そうしないと、インデックスのすべての構成が更新されます。
GET _time_stream/test_streamコマンドを実行してインデックスのすべての構成を取得し、必要な構成を変更してインデックスを更新することをお勧めします。 - 時系列インデックスの構成を更新した後、新しい構成はインデックスにすぐには反映されません。 新しい構成を反映させるには、インデックスをロールオーバーする必要があります。 ロールオーバー後、新しいインデックスが生成されます。 新しい構成は、新しいインデックスに反映されます。
POST test_stream/_rolloverコマンドを実行して、インデックスをロールオーバーできます。
時系列インデックスの削除
Delete _time_stream/test_stream時系列インデックスの使用
時系列インデックスは、一般的なインデックスと同じ方法で使用されます。
時系列データの書き込み
POST test_stream/_doc
{
"@timestamp": 1630465208722, // タイムスタンプ
"metrics": { // メトリック
"cpu.idle": 79.67298116109929,
"disk_ioutil": 17.630910821570456,
"mem.free": 75.79973639970004
},
"labels": { // ラベル(ディメンション)
"disk_type": "disk_type2",
"namespace": "namespaces1",
"clusterId": "clusterId3",
"nodeId": "nodeId5"
}
}
データストリーム内のインデックスにデータを書き込むと、データストリームは @timestamp の値に基づいてデータ書き込みのインデックスを決定します。 したがって、前の例では、@timestamp を test_stream インデックスの時間範囲内の値に設定する必要があります。
時間範囲の時刻は UTC で、2022-06-21T00:00:00.000Z などです。 タイムゾーンが UTC+8 の場合は、時刻を UTC+8 の時刻に変換する必要があります。 この例では、変換された時刻は 2022-06-21T08:00:00.000 で、これは 2022-06-21T00:00:00.000+08:00 に基づいて取得されます。
時系列データのクエリ
GET test_stream/_searchGET _cat/indices/test_stream?v&s=i時系列インデックスのメトリックのクエリ
GET _time_stream/test_stream/_stats{
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"time_stream_count" : 1,
"indices_count" : 1,
"total_store_size_bytes" : 19132,
"time_streams" : [
{
"time_stream" : "test_stream",
"indices_count" : 1,
"store_size_bytes" : 19132,
"tsid_count" : 2
}
]
}Prometheus API を使用したデータのクエリ
- Grafana コンソールでデータソースを構成するGrafana コンソールで Prometheus データソースを構成し、URL に
/_time_stream/prom/test_streamURI を指定して、時系列インデックスを Grafana の Prometheus データソースとして直接使用します(次の図を参照)。
- Prometheus API を呼び出してデータソースを構成する
Prometheus API を呼び出して、メトリックフィールドとディメンションフィールドのキーワードのプレフィックスとサフィックスを削除します。 Prometheus API を使用してデフォルトの時系列データモデルに基づいて書き込まれたデータをクエリする場合、返されるメトリックフィールドのプレフィックス metrics. は表示されず、返されるディメンションフィールドのプレフィックス labels. は表示されません。
時系列インデックスを作成するときにデータモデルをカスタマイズする場合は、メトリックフィールドとディメンションフィールドのプレフィックスとサフィックスを指定する必要があります。 そうしないと、Prometheus API を使用して時系列インデックス内のデータをクエリすると、実際のデータが返されます。 次のコードは、プレフィックスとサフィックスを指定する方法の例を示しています。PUT _time_stream/{name} // 時系列インデックス名 { "time_stream": { "labels_fields": "@labels.*_l", // ラベルフィールドのプレフィックスとサフィックスを指定 "metrics_fields": "@metrics.*_m", // メトリックフィールドのプレフィックスとサフィックスを指定 "label_prefix": "@labels.", // ラベルのプレフィックス "label_suffix": "_l", // ラベルのサフィックス "metric_prefix": "@metrics.", // メトリックのプレフィックス "metric_suffix": "_m" // メトリックのサフィックス } }
メタデータのクエリ
- test_stream インデックス内のすべてのメトリックフィールドを表示します。
GET /_time_stream/prom/test_stream/metadataコマンドが正常に実行されると、次の結果が返されます。{ "status" : "success", "data" : { "cpu.idle" : [ { "type" : "gauge", "help" : "", "unit" : "" } ], "disk_ioutil" : [ { "type" : "gauge", "help" : "", "unit" : "" } ], "mem.free" : [ { "type" : "gauge", "help" : "", "unit" : "" } ] } } - test_stream インデックス内のすべてのディメンションフィールドを表示します。
GET /_time_stream/prom/test_stream/labelsコマンドが正常に実行されると、次の結果が返されます。{ "status" : "success", "data" : [ "__name__", "clusterId", "disk_type", "namespace", "nodeId" ] } - test_stream インデックス内の特定のディメンションフィールドのすべての値を表示します。
GET /_time_stream/prom/test_stream/label/clusterId/valuesコマンドが正常に実行されると、次の結果が返されます。{ "status" : "success", "data" : [ "clusterId1", "clusterId3" ] } - test_stream インデックス内の cpu.idle メトリックフィールドのすべてのタイムラインを表示します。
GET /_time_stream/prom/test_stream/series?match[]=cpu.idleコマンドが正常に実行されると、次の結果が返されます。{ "status" : "success", "data" : [ { "__name__" : "cpu.idle", "disk_type" : "disk_type1", "namespace" : "namespaces2", "clusterId" : "clusterId1", "nodeId" : "nodeId2" }, { "__name__" : "cpu.idle", "disk_type" : "disk_type1", "namespace" : "namespaces2", "clusterId" : "clusterId1", "nodeId" : "nodeId5" }, { "__name__" : "cpu.idle", "disk_type" : "disk_type2", "namespace" : "namespaces1", "clusterId" : "clusterId3", "nodeId" : "nodeId5" } ] }
データのクエリ
- Prometheus インスタントクエリ API を呼び出してデータをクエリする
GET /_time_stream/prom/test_stream/query?query=cpu.idle&time=1655769837説明 time の単位は秒です。 このパラメータを構成しない場合、デフォルトでは過去 5 分以内のデータがクエリされます。コマンドが正常に実行されると、次の結果が返されます。{ "status" : "success", "data" : { "resultType" : "vector", "result" : [ { "metric" : { "__name__" : "cpu.idle", "clusterId" : "clusterId1", "disk_type" : "disk_type1", "namespace" : "namespaces2", "nodeId" : "nodeId2" }, "value" : [ 1655769837, "79.672981161" ] }, { "metric" : { "__name__" : "cpu.idle", "clusterId" : "clusterId1", "disk_type" : "disk_type1", "namespace" : "namespaces2", "nodeId" : "nodeId5" }, "value" : [ 1655769837, "79.672981161" ] }, { "metric" : { "__name__" : "cpu.idle", "clusterId" : "clusterId3", "disk_type" : "disk_type2", "namespace" : "namespaces1", "nodeId" : "nodeId5" }, "value" : [ 1655769837, "79.672981161" ] } ] } } - Prometheus 範囲クエリ API を呼び出してデータをクエリする
GET /_time_stream/prom/test_stream/query_range?query=cpu.idle&start=1655769800&end=16557699860&step=1mコマンドが正常に実行されると、次の結果が返されます。{ "status" : "success", "data" : { "resultType" : "matrix", "result" : [ { "metric" : { "__name__" : "cpu.idle", "clusterId" : "clusterId1", "disk_type" : "disk_type1", "namespace" : "namespaces2", "nodeId" : "nodeId2" }, "value" : [ [ 1655769860, "79.672981161" ] ] }, { "metric" : { "__name__" : "cpu.idle", "clusterId" : "clusterId1", "disk_type" : "disk_type1", "namespace" : "namespaces2", "nodeId" : "nodeId5" }, "value" : [ [ 1655769860, "79.672981161" ] ] }, { "metric" : { "__name__" : "cpu.idle", "clusterId" : "clusterId3", "disk_type" : "disk_type2", "namespace" : "namespaces1", "nodeId" : "nodeId5" }, "value" : [ [ 1655769860, "79.672981161" ] ] } ] } }
ダウンサンプリング機能の使用
PUT _time_stream/test_stream
{
"time_stream": {
"downsample": [ // ダウンサンプリングルール
{
"interval": "1m" // 1 分間隔
},
{
"interval": "10m" // 10 分間隔
},
{
"interval": "60m" // 60 分間隔
}
]
}
}- 元のインデックスに対してダウンサンプリングを実行して、ダウンサンプリングインデックスを生成します。 元のインデックスがロールオーバーされると、新しいインデックスが生成され、特定の期間内に元のインデックスにデータは書き込まれません。 その後、元のインデックスに対してダウンサンプリングが実行されます。 デフォルトでは、現在の時刻が元のインデックスの end_time で示される時刻より 2 時間後であれば、ダウンサンプリングが開始されます。 この効果をシミュレートするために、インデックスを作成するときに start_time と end_time を手動で構成できます。 重要 システムは、新しいインデックスの end_time の値を最新の時間に更新します。これはダウンサンプリングのデモに影響します。 デフォルトでは、値は 5 分間隔で変更されます。 ダウンサンプリングのデモでは、end_time の値が変更されていないことを確認する必要があります。 終了時刻
GET {index}/_settingsコマンドを実行して、 の値を表示できます。PUT _time_stream/test_stream { "template": { "settings": { "index.time_series.start_time": "2022-06-20T00:00:00.000Z", // 開始時刻 "index.time_series.end_time": "2022-06-21T00:00:00.000Z" // 終了時刻 } }, "time_stream": { "downsample": [ { "interval": "1m" }, { "interval": "10m" }, { "interval": "60m" } ] } } - インデックスの end_time を現在の時刻より 2 時間以上前の時点に設定し、インデックスにデータを書き込みます。 また、@timestamp を start_time と end_time の間の時刻を示す値に設定します。
POST test_stream/_doc { "@timestamp": 1655706106000, // タイムスタンプ "metrics": { "cpu.idle": 79.67298116109929, "disk_ioutil": 17.630910821570456, "mem.free": 75.79973639970004 }, "labels": { "disk_type": "disk_type2", "namespace": "namespaces1", "clusterId": "clusterId3", "nodeId": "nodeId5" } } - インデックスにデータが書き込まれたら、インデックスから start_time と end_time を削除します。
POST _time_stream/test_stream/_update { "time_stream": { "downsample": [ { "interval": "1m" }, { "interval": "10m" }, { "interval": "60m" } ] } } - インデックスをロールオーバーします。
POST test_stream/_rollover - ロールオーバーが完了したら、
GET _cat/indices/test_stream?v&s=iコマンドを実行して、test_stream インデックスによって生成されたダウンサンプリングインデックスを表示します。コマンドが正常に実行されると、次の結果が返されます。health status index uuid pri rep docs.count docs.deleted store.size pri.store.size green open .ds-test_stream-2022.06.21-000001 vhEwKIlwSGO3ax4RKn**** 1 1 9 0 18.5kb 12.1kb green open .ds-test_stream-2022.06.21-000001_interval_10m r9Tsj0v-SyWJDc64oC**** 1 1 1 0 15.8kb 7.9kb green open .ds-test_stream-2022.06.21-000001_interval_1h cKsAlMK-T2-luefNAF**** 1 1 1 0 15.8kb 7.9kb green open .ds-test_stream-2022.06.21-000001_interval_1m L6ocasDFTz-c89KjND**** 1 1 1 0 15.8kb 7.9kb green open .ds-test_stream-2022.06.21-000002 42vlHEFFQrmMAdNdCz**** 1 1 0 0 452b 226b

GET test_stream/_search?size=0&request_cache=false
{
"aggs": { // 集計
"1": { // 集計 1
"terms": { // ラベルの disk_type フィールドでグループ化
"field": "labels.disk_type",
"size": 10
},
"aggs": { // 集計 2
"2": {
"date_histogram": { // タイムスタンプでヒストグラムを作成
"field": "@timestamp",
"fixed_interval": "120m" // 120 分間隔
}
}
}
}
}
}{
"took" : 15,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"1" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "disk_type2",
"doc_count" : 9,
"2" : {
"buckets" : [
{
"key_as_string" : "2022-06-20T06:00:00.000Z",
"key" : 1655704800000,
"doc_count" : 9
}
]
}
}
]
}
}
}
hits.total.value の値は 1 です。 これは、ヒットしたデータレコードが 1 つだけであることを示しています。 集計部分の doc_count の値は 9 です。 これは、実際のデータレコード数が 9 であることを示しています。 クエリされたインデックスが元のインデックスではなくダウンサンプリングインデックスであると判断できます。
fixed_interval の値を 20s に変更すると、hits.total.value の値は 9 になり、集計部分の doc_count の値と同じになります。 これは、クエリされたインデックスが元のインデックスであることを示しています。
ダウンサンプリングインデックスの設定とマッピングは元のインデックスと同じですが、データは時間範囲に基づいてダウンサンプリングされます。