全部產品
Search
文件中心

Elasticsearch:TimeStream管理Elasticsearch時序資料快速入門

更新時間:Jun 30, 2024

TimeStream是Elasticsearch團隊自研,並結合Elastic社區時序類產品特性共建的時序引擎。Elasticsearch提供Aliyun-TimeStream時序增強功能外掛程式,支援通過API介面完成TimeStream索引的增刪改查,以及資料寫入和查詢。本文介紹如何使用TimeStream管理Elasticsearch時序資料。

背景資訊

Elasticsearch提供的TimeStream時序增強功能外掛程式,最佳化了Elasticsearch在儲存指標資料方面的DSL(Domain-Specific Language)查詢複雜且慢以及儲存成本過高等問題,詳細資料請參見TimeStream時序增強引擎介紹

本文主要介紹如何使用TimeStream,涉及到的API可通過查詢API文檔獲得完整資訊,詳細資料請參見TimeStream API功能介紹TimeStream整合Prometheus介面

前提條件

已建立Elasticsearch執行個體,且執行個體版本為通用商業版7.16及以上、核心版本為1.7.0及以上,或者執行個體版本為通用商業版7.10、核心版本為1.8.0及以上。具體操作請參見建立Elasticsearch執行個體

管理時序索引

建立時序索引

使用如下命令,通過TimeStream的建立索引介面建立一個名稱為test_stream的時序索引。
PUT _time_stream/test_stream

與直接通過Elasticsearch create index命令(PUT test_stream)建立的索引相比,通過TimeStream的建立索引介面建立的索引是DataStream索引,而不是一個具體的索引,並且自動整合了Elasticsearch在時序情境的最佳實務配置。

您可以通過如下命令,查看test_stream索引的具體配置。
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
    }
  }
}
從返回結果可以看到,TimeStream的建立索引介面預設會建立一個.timestream_test_streamindex_template,index_template settings中配置了以下關鍵參數。
參數說明
index.mode取值time_series,表示建立的索引類型是time_series索引,系統會自動整合Elasticsearch在時序情境的最佳實務配置。
index.codec取值ali,表示使用aliyun-codec索引壓縮外掛程式。與以下參數配合使用,可以極大減少磁碟儲存空間:
  • index.ali_codec_service.enabled=true:開啟codec壓縮功能。
  • index.doc_value.compression.default=zstd:doc_values使用zstd壓縮。
  • index.postings.compression=zstd:倒排資料使用zstd壓縮。
  • index.ali_codec_service.source_reuse_doc_values.enabled=true:不儲存source,使用doc_values拼裝source。
  • index.source.compression=zstd:正排資料使用zstd壓縮。
index_template mappings配置了時序模型對應的dynamic_templates配置:
  • 維度欄位:預設使用keyword類型,然後配置time_series_dimension=true,標識為維度欄位。index.mode=time_series會把所有time_series_dimension=true的欄位拼裝成一個時間軸id(_tsid)的內部欄位。
  • 指標欄位:支援double和long類型,只儲存doc_values,不儲存索引。
如果您需要自訂索引的模板資訊,可直接使用index_template文法,樣本如下:
  • 自訂索引的shard數量
    PUT _time_stream/test_stream
    {
      "template": {
        "settings": {
          "index": {
            "number_of_shards": "2"
          }
        }
      }
    }
                            
  • 自訂索引的資料模型
    PUT _time_stream/test_stream
    {
      "template": {
        "settings": {
          "index": {
            "number_of_shards": "2"
          }
        }
      },
      "time_stream": {
        "labels_fields": ["labels_*"],
        "metrics_fields": ["metrics_*"]
    }

更新時序索引

使用如下命令,更新test_stream時序索引的shard數量。
POST _time_stream/test_stream/_update
{
  "template": {
    "settings": {
      "index": {
        "number_of_shards": "4"
      }
    }
  }
}
重要
  • 更新內容會全量覆蓋索引的配置,因此在執行更新命令時,需要保留無需更新的配置。建議通過GET _time_stream/test_stream命令擷取索引的全量配置資訊,再在其基礎上進行修改。
  • 更新時序索引配置後,新配置不會立即生效,需要等到索引進行一次rollover,產生新索引後,在新索引上生效。您可以通過POST test_stream/_rollover命令手動執行rollover。

刪除時序索引

使用如下命令,刪除test_stream時序索引。
Delete _time_stream/test_stream
說明 刪除介面會直接刪除目標時序索引全部的資料和相關配置。

使用時序索引

時序索引的使用方式與普通索引一致,具體說明如下。

寫入時序資料

使用bulkindex API,按照時序模型寫入資料,樣本如下(@timestamp需調整為目前時間)。
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"
  }
}
時序索引的時間範圍是TimeStream使用DataStream功能在內部產生的,原理為:DataStream的每個索引都配置了index.time_series.start_timeindex.time_series.end_time兩個settings配置,索引只允許@timestamp在[start_time,end_time)區間範圍內的資料寫入,是一個前閉後開區間。這個是DataStream內部為索引產生的,無需使用者配置。索引一旦建立,index.time_series.start_time就固定不變了,而index.time_series.end_time會不斷擴大,直到rollover產生一個新索引,此時舊索引的index.time_series.end_time就固定不變了,新索引的index.time_series.start_time就是舊索引的index.time_series.end_time,這樣DataStream內部的索引就是時間範圍連續的多個索引。原理圖

寫入資料時,DataStream會根據@timestamp的值來決定寫到哪個索引,所以上述用例中@timestamp要設定在當前test_stream索引的時間區間上。

時間區間中的時間為UTC時間格式,例如2022-06-21T00:00:00.000Z。如果您所在時區為東8區(北京時間),需要在UTC時間上加8小時轉換為北京時間,轉換後對應的時間為2022-06-21T00:00:00.000+08:00,即2022-06-21T08:00:00.000。

查詢時序資料

使用search介面查詢資料。
GET test_stream/_search
使用_cat/indices介面,查看索引的詳細資料。
GET _cat/indices/test_stream?v&s=i

查詢時序索引指標

使用TimeStream的_stats介面,查看索引stats資訊。
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
    }
  ]
}
說明 由於shard上擷取時間軸數量是從內部的時間軸id(_tsid)欄位的doc_values資料直接擷取,查詢代價過高,所以增加了緩衝策略。唯讀索引擷取一次後就不再擷取,正常索引緩衝預設失效時間是5分鐘,通過設定索引配置index.time_series.stats.refresh_interval可修改緩衝更新時間,最小為1分鐘。

使用Prometheus介面查詢資料

在使用Prometheus介面查詢資料前,您需要配置Prometheus資料來源,支援以下兩種方式:
  • 在Grafana控制台中配置
    通過在Grafana控制台中配置Prometheus資料來源,並在URL中指定/_time_stream/prom/test_stream URI,直接將TimeStream索引作為Grafana的Prometheus資料來源使用,如下圖所示。配置Grafana資料來源
  • 使用Prometheus API配置

    使用Prometheus API,去掉返回的指標和維度欄位的關鍵字前尾碼。例如,使用預設的資料模型,指標首碼metric.會被去掉,維度首碼label.會被去掉。

    如果自訂了資料模型,則需要額外配置前尾碼關鍵字,否則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索引中,某個具體維度全部value。
    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 instant query和range query介面,使用PromQL查詢Elasticsearch資料。PromQL的支援情況請參見TimeStream PromQL支援情況
  • 通過Prometheus instant query介面查詢資料
    GET /_time_stream/prom/test_stream/query?query=cpu.idle&time=1655769837
    說明 time的單位為秒,不傳遞時,預設查詢最新5分鐘內的資料。
    返回結果為Prometheus query介面的資料格式,如下所示。
    {
      "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 range query介面查詢資料
    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"
              ]
            ]
          }
        ]
      }
    }

使用DownSample功能

DownSample(降採樣)是在時序情境的常用功能,用來加速大範圍資料查詢的效能,DownSample功能的詳細介紹請參見DownSample使用說明。通過TimeStream的建立索引介面建立索引時,可直接指定DownSample規則,樣本如下。
PUT _time_stream/test_stream
{
  "time_stream": {
    "downsample": [
      {
        "interval": "1m"
      },
      {
        "interval": "10m"
      },
      {
        "interval": "60m"
      }
    ]
  }
}
產生DownSample索引的流程如下:
  1. DownSample操作是對一個原始索引執行DownSample,產生DownSample索引。DownSample操作是在索引rollover後產生了一個新索引,然後舊索引過了一段時間,不再寫入資料時進行的。目前預設是目前時間比舊索引的end_time大兩小時才開始進行DownSample。為了類比這個效果,建立索引時可以手動指定start_timeend_time
    重要 最新索引的end_time會被Elasticsearch修改為最新時間,影響DownSample示範,預設是5分鐘修改一次。DownSample示範操作要確保end_time不被修改,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"
          }
        ]
      }
    }
  2. 設定索引的end_time比目前時間至少小兩個小時,然後寫入一些資料(需要調整@timestampstart_timeend_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"
      }
    }
  3. 寫入一些資料後,需要更新TimeStream索引,去掉start_timeend_time
    POST _time_stream/test_stream/_update
    {
      "time_stream": {
        "downsample": [
          {
            "interval": "1m"
          },
          {
            "interval": "10m"
          },
          {
            "interval": "60m"
          }
        ]
      }
    }
  4. 對索引執行rollover命令。
    POST test_stream/_rollover
  5. rollover完成後,通過GET _cat/indices/test_stream?v&s=i命令,查看test_stream產生的DownSample索引。
    預期結果如下。
    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
DownSample查詢功能的原理:使用DownSample查詢功能時,您可以根據查詢資料的時間範圍,設定合理的interval值。如下圖所示,使用者傳遞原始的索引名稱(例如test_stream),並在date_histogram裡傳遞interval參數,TimeStream在進行DownSample操作時,能自動選擇最合適精度的索引查詢資料。
說明 下圖以1小時、4小時、1天和7天資料為例,您可以根據需求設定interval值。DownSample會根據您設定的fixed_interval值去自動匹配一個最大精度。例如設定fixed_interval值為120m,您自訂的interval值有1m、10m、60m,那麼TimeStream在進行DownSample操作時會自動取60m。
DownSample原理圖
例如,執行以下查詢:
GET test_stream/_search?size=0&request_cache=false
{
  "aggs": {
    "1": {
      "terms": {
        "field": "labels.disk_type",
        "size": 10
      },
      "aggs": {
        "2": {
          "date_histogram": {
            "field": "@timestamp",
            "fixed_interval": "120m"
          }
        }
      }
    }
  }
}
其中fixed_interval設定為120m,表示可以使用到DownSample最大精度為60分鐘的索引,預期返回結果如下。
{
  "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可以看到,只命中了一條記錄。aggs結果的doc_count=9,表示實際索引資料量是9,因此可以看到使用者查詢的不是原始索引,而是DownSample索引。

如果將fixed_interval改為20s,那麼可以看到結果的hits.total.value=9,與aggs結果的doc_count結果一致,說明查詢到了原始索引。

由此可見,這些DownSample索引跟原始索引的settings和mappings是一致的,只是資料是按時間範圍做了降採樣。