时间序列数据流 (TSDS)

edit

时间序列数据流 (TSDS)

edit

时间序列数据流(TSDS)将带时间戳的指标数据建模为一个或多个时间序列。

您可以使用TSDS更高效地存储指标数据。在我们的基准测试中,存储在TSDS中的指标数据比常规数据流使用的磁盘空间减少了70%。具体影响将因数据集而异。

何时使用TSDS

edit

无论是常规数据流还是TSDS都可以存储带时间戳的指标数据。只有在通常以接近实时和@timestamp顺序向Elasticsearch添加指标数据时,才使用TSDS。

TSDS 仅用于指标数据。对于其他时间戳数据,例如日志或跟踪,请使用常规数据流。

与常规数据流的区别

edit

TSDS 的工作原理类似于常规数据流,但有一些关键区别:

  • TSDS的匹配索引模板需要一个包含index.mode: time_series选项的data_stream对象。此选项启用了大多数与TSDS相关的功能。
  • 除了一个@timestamp,TSDS中的每个文档必须包含一个或多个维度字段。TSDS的匹配索引模板必须包含至少一个keyword维度的映射。

    TSDS文档通常也包含一个或多个指标字段

  • Elasticsearch为TSDS中的每个文档生成一个隐藏的_tsid元数据字段。
  • TSDS使用时间界限的后备索引将同一时间段的数据存储在同一个后备索引中。
  • TSDS的匹配索引模板必须包含index.routing_path索引设置。TSDS使用此设置来执行基于维度的路由
  • TSDS使用内部的索引排序_tsid@timestamp对分片段进行排序。
  • TSDS文档仅支持自动生成的文档_id值。对于TSDS文档,文档_id是文档维度和@timestamp的哈希值。TSDS不支持自定义文档_id值。
  • TSDS使用合成_source,因此受到一些限制修改,这些限制和修改应用于_source字段。

时间序列索引可以包含除维度或指标之外的字段。

什么是时间序列?

edit

时间序列是特定实体的一系列观测值。这些观测值共同让你能够跟踪实体随时间的变化。例如,时间序列可以跟踪:

  • 计算机的CPU和磁盘使用情况
  • 股票的价格
  • 气象传感器测得的温度和湿度读数。
time series chart
Figure 3. Time series of weather sensor readings plotted as a graph

在时间序列数据存储(TSDS)中,每个Elasticsearch文档代表特定时间序列中的一个观测值或数据点。尽管TSDS可以包含多个时间序列,但一个文档只能属于一个时间序列。一个时间序列不能跨越多个数据流。

维度

edit

维度是字段名称和值,它们共同标识文档的时间序列。在大多数情况下,维度描述了您正在测量的实体的某些方面。例如,与同一气象传感器相关的文档可能总是具有相同的sensor_idlocation值。

TSDS 文档通过其时间序列和时间戳唯一标识,这两者都用于生成文档 _id。因此,具有相同维度和相同时间戳的两个文档被视为重复文档。当您使用 _bulk 端点向 TSDS 添加文档时,具有相同时间戳和维度的第二个文档会覆盖第一个文档。当您使用 PUT //_create/<_id> 格式添加单个文档且具有相同 _id 的文档已存在时,会生成错误。

您可以使用布尔值 time_series_dimension 映射参数将字段标记为维度。以下字段类型支持 time_series_dimension 参数:

对于扁平化字段,使用 time_series_dimensions 参数来配置作为维度的字段数组。 详情请参阅 flattened

维度定义可以通过透传字段来简化。

指标

edit

指标是包含数值测量值的字段,以及基于这些测量值的聚合和/或降采样值。虽然不是必需的,但TSDS中的文档通常包含一个或多个指标字段。

指标与维度不同,因为虽然维度通常保持不变,但指标预计会随时间变化,即使变化很少或很慢。

要将一个字段标记为指标,您必须使用time_series_metric映射参数指定一个指标类型。以下字段类型支持time_series_metric参数:

接受的度量类型因字段类型而异:

适用于 time_series_metric 的有效值
counter

一个仅单调递增或重置为 0(零)的累积指标。例如,错误计数或已完成任务的计数。

计数器字段具有额外的语义意义,因为它代表一个累积计数器。这与rate聚合非常匹配,因为可以从一个单调递增的累积计数器中得出速率。然而,许多聚合(例如sum)计算的结果对于计数器字段来说没有意义,因为它的累积性质。

仅数值和aggregate_metric_double字段支持counter指标类型。

由于计数器字段的累积性质,支持以下聚合并期望在使用counter字段时提供有意义的结果:ratehistogramrangeminmaxtop_metricsvariable_width_histogram。为了防止现有集成和自定义仪表板出现问题,我们还允许以下聚合,即使这些聚合在计数器上的结果可能没有意义:avgbox plotcardinalityextended statsmedian absolute deviationpercentile rankspercentilesstatssumvalue count

gauge

一个表示单个数值的指标,可以任意增加或减少。例如,温度或可用磁盘空间。

仅数值和 aggregate_metric_double 字段支持 gauge 指标类型。

null (Default)
不是时间序列指标。

时间序列模式

edit

TSDS的匹配索引模板必须包含一个data_stream对象,并带有index_mode: time_series选项。此选项确保TSDS创建的后备索引具有index.mode设置为time_series。此设置启用了后备索引中的大多数TSDS相关功能。

如果您将现有的数据流转换为TSDS,只有在转换后创建的备份索引才会具有index.modetime_series。您无法更改现有备份索引的index.mode

_tsid 元数据字段

edit

当您向TSDS添加文档时,Elasticsearch会自动为该文档生成一个_tsid元数据字段。_tsid是一个包含文档维度的对象。具有相同_tsid的同一TSDS中的文档属于同一时间序列。

_tsid 字段不可查询或更新。您也无法使用 获取文档 请求来检索文档的 _tsid。但是,您可以在聚合中使用 _tsid 字段,并使用 fields 参数 在搜索中检索 _tsid 值。

不应依赖 _tsid 字段的格式。它可能会随着版本的变化而变化。

时间绑定索引

edit

在TSDS中,每个支持索引,包括最新的支持索引,都有一个接受的@timestamp值范围。这个范围由index.time_series.start_timeindex.time_series.end_time索引设置定义。

当您向TSDS添加文档时,Elasticsearch会根据文档的@timestamp值将其添加到适当的底层索引中。因此,TSDS可以将文档添加到任何可以接收写入的TSDS底层索引中。即使该索引不是最新的底层索引,也适用此规则。

time bound indices

一些ILM操作会将源索引标记为只读,或者期望索引不再被主动写入以提供良好的性能。这些操作包括: - Delete - Downsample - Force merge - Read only - Searchable snapshot - Shrink 索引生命周期管理将不会继续执行这些操作,直到接受写入的上限时间,由index.time_series.end_time索引设置表示的时间已过。

如果没有后备索引可以接受文档的@timestamp值,Elasticsearch 会拒绝该文档。

Elasticsearch 自动配置 index.time_series.start_timeindex.time_series.end_time 设置作为索引创建和滚动更新过程的一部分。

提前时间

edit

使用 index.look_ahead_time 索引设置来配置您可以将文档添加到索引中的未来时间。当您为TSDS创建一个新的写入索引时,Elasticsearch会计算索引的 index.time_series.end_time 值为:

now + index.look_ahead_time

在时间序列轮询间隔(通过time_series.poll_interval设置控制), Elasticsearch检查写入索引是否在其索引生命周期策略中满足滚动更新条件。如果没有,Elasticsearch刷新now值并更新写入索引的index.time_series.end_time为:

now + index.look_ahead_time + time_series.poll_interval

这个过程会一直持续,直到写入索引滚动更新。当索引滚动更新时,Elasticsearch 会为该索引设置一个最终的 index.time_series.end_time 值。这个值与新写入索引的 index.time_series.start_time 相邻。这确保了相邻的后备索引的 @timestamp 范围总是相邻但不会重叠。

回溯时间

edit

使用 index.look_back_time 索引设置来配置可以向索引中添加文档的过去时间范围。当你为TSDS创建数据流时,Elasticsearch会计算索引的 index.time_series.start_time 值为:

now - index.look_back_time

此设置仅在创建数据流时使用,并控制第一个支持索引的 index.time_series.start_time 索引设置。配置此索引设置可能有助于接受 @timestamp 字段值早于 2 小时(index.look_back_time 默认值)的文档。

添加数据的可接受时间范围

edit

TSDS 旨在摄取当前的指标数据。当 TSDS 首次创建时,初始的后备索引具有:

  • 一个设置为 now - index.look_back_timeindex.time_series.start_time
  • 一个设置为 now + index.look_ahead_timeindex.time_series.end_time

只有落在该范围内的数据才能被索引。

您可以使用获取数据流 API来检查写入任何TSDS的接受时间范围。

基于维度的路由

edit

在每个TSDS后备索引中,Elasticsearch使用index.routing_path索引设置将具有相同维度的文档路由到相同的分片。

当您为TSDS创建匹配的索引模板时,必须在index.routing_path设置中指定一个或多个维度。TSDS中的每个文档必须包含一个或多个与index.routing_path设置匹配的维度。

设置 index.routing_path 接受通配符模式(例如 dim.*) 并且可以动态匹配新字段。然而,Elasticsearch 将拒绝任何添加脚本化、运行时或非维度字段 的映射更新,这些字段与 index.routing_path 值匹配。

透传字段可以配置为维度容器。在这种情况下,它们的子字段会自动包含到路由路径中。

TSDS 文档不支持自定义 _routing 值。同样,您不能在 TSDS 的映射中要求 _routing 值。

索引排序

edit

Elasticsearch 使用 压缩算法 来压缩重复的值。 这种压缩在重复值存储在彼此附近时效果最佳 — 在同一个索引、同一个分片以及同一个分片段中。

大多数时间序列数据包含重复的值。维度在同一时间序列的文档中重复。时间序列的指标值也可能随时间缓慢变化。

在内部,每个TSDS后备索引使用索引排序来按_tsid@timestamp对其分片段进行排序。这使得这些重复的值更有可能存储在彼此附近,以获得更好的压缩效果。TSDS不支持任何index.sort.*索引设置。

下一步是什么?

edit

现在你已经了解了基础知识,你可以准备创建一个TSDS将现有数据流转换为TSDS

设置时间序列数据流 (TSDS)

edit

要设置一个时间序列数据流 (TSDS),请按照以下步骤操作:

先决条件

edit
  • 在创建TSDS之前,您应该熟悉数据流TSDS概念
  • 要学习本教程,您必须具备以下权限:

    • 集群权限: manage_ilmmanage_index_templates
    • 索引权限: create_doccreate_index 对于您创建或转换的任何TSDS。要滚动TSDS,您必须具有 manage 权限。

创建索引生命周期策略

edit

虽然可选,但我们建议使用 ILM 来自动管理您的 TSDS 的后备索引。ILM 需要一个索引生命周期策略。

我们建议您在策略中为rollover操作指定一个max_age标准。这确保了TSDS的后备索引的@timestamp范围是一致的。例如,为rollover操作设置max_age1d,可以确保您的后备索引始终包含一天的数据。

PUT _ilm/policy/my-weather-sensor-lifecycle-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_age": "1d",
            "max_primary_shard_size": "50gb"
          }
        }
      },
      "warm": {
        "min_age": "30d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          }
        }
      },
      "cold": {
        "min_age": "60d",
        "actions": {
          "searchable_snapshot": {
            "snapshot_repository": "found-snapshots"
          }
        }
      },
      "frozen": {
        "min_age": "90d",
        "actions": {
          "searchable_snapshot": {
            "snapshot_repository": "found-snapshots"
          }
        }
      },
      "delete": {
        "min_age": "735d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

创建索引模板

edit

要设置TSDS,请使用以下详细信息创建一个索引模板:

  • 一个或多个与TSDS名称匹配的索引模式。我们建议使用我们的数据流命名方案
  • 启用数据流。
  • 指定一个映射,定义您的维度和指标:

    • 一个或多个维度字段,其time_series_dimension值为true。或者,一个或多个配置为维度容器的透传字段,前提是它们将包含至少一个子字段(静态或动态映射)。
    • 一个或多个指标字段,使用time_series_metric映射参数标记。
    • 可选:@timestamp字段的datedate_nanos映射。如果您不指定映射,Elasticsearch会将@timestamp映射为具有默认选项的date字段。
  • 定义索引设置:

    • index.mode设置为time_series
    • index.lifecycle.name索引设置中的生命周期策略。
    • 可选:其他索引设置,例如index.number_of_replicas,用于TSDS的支持索引。
  • 优先级高于200,以避免与内置模板发生冲突。请参阅避免索引模式冲突
  • 可选:包含您的映射和其他索引设置的组件模板。
PUT _index_template/my-weather-sensor-index-template
{
  "index_patterns": ["metrics-weather_sensors-*"],
  "data_stream": { },
  "template": {
    "settings": {
      "index.mode": "time_series",
      "index.lifecycle.name": "my-lifecycle-policy"
    },
    "mappings": {
      "properties": {
        "sensor_id": {
          "type": "keyword",
          "time_series_dimension": true
        },
        "location": {
          "type": "keyword",
          "time_series_dimension": true
        },
        "temperature": {
          "type": "half_float",
          "time_series_metric": "gauge"
        },
        "humidity": {
          "type": "half_float",
          "time_series_metric": "gauge"
        },
        "@timestamp": {
          "type": "date"
        }
      }
    }
  },
  "priority": 500,
  "_meta": {
    "description": "Template for my weather sensor data"
  }
}

创建TSDS

edit

索引请求 将文档添加到TSDS。 TSDS中的文档必须包括:

  • 一个 @timestamp 字段
  • 一个或多个维度字段。至少一个维度必须匹配 index.routing_path 索引设置,如果指定了的话。如果没有明确指定,index.routing_path 会自动设置为那些将 time_series_dimension 设置为 true 的映射。

要自动创建您的TSDS,请提交一个索引请求,该请求的目标是TSDS的名称。此名称必须与您的索引模板中的一个索引模式匹配。

要测试以下示例,请将时间戳更新为当前时间的三小时以内。添加到TSDS的数据必须始终落在接受时间范围内。

PUT metrics-weather_sensors-dev/_bulk
{ "create":{ } }
{ "@timestamp": "2099-05-06T16:21:15.000Z", "sensor_id": "HAL-000001", "location": "plains", "temperature": 26.7,"humidity": 49.9 }
{ "create":{ } }
{ "@timestamp": "2099-05-06T16:25:42.000Z", "sensor_id": "SYKENET-000001", "location": "swamp", "temperature": 32.4, "humidity": 88.9 }

POST metrics-weather_sensors-dev/_doc
{
  "@timestamp": "2099-05-06T16:21:15.000Z",
  "sensor_id": "SYKENET-000001",
  "location": "swamp",
  "temperature": 32.4,
  "humidity": 88.9
}

您也可以使用创建数据流 API手动创建 TSDS。TSDS 的名称必须仍然与您的模板中的一个索引模式匹配。

PUT _data_stream/metrics-weather_sensors-dev

保护TSDS

edit

使用索引权限来控制对TSDS的访问。 授予TSDS的权限会同时授予其支持索引的相同权限。

有关示例,请参阅数据流权限

将现有数据流转换为TSDS

edit

您还可以使用上述步骤将现有的常规数据流转换为TSDS。在这种情况下,您需要:

  • 编辑您现有的索引生命周期策略、组件模板和索引模板,而不是创建新的。
  • 不要创建TSDS,而是手动滚动其写入索引。这确保当前写入索引和任何新的后备索引具有index.modetime_series

    您可以手动使用rollover API来滚动写索引。

    POST metrics-weather_sensors-dev/_rollover

关于组件模板和index.mode设置的说明

edit

通过使用组件模板配置TSDS的索引模板稍微复杂一些。通常,使用组件模板时,映射和设置会分散在多个组件模板中。如果定义了index.routing_path,它引用的字段需要在同一个组件模板中定义,并启用time_series_dimension属性。

这样做的原因是每个组件模板都需要在其自身上是有效的。当在索引模板中配置index.mode设置时,index.routing_path设置会自动配置。它是从启用了time_series_dimension属性的字段映射中派生出来的。

下一步是什么?

edit

现在您已经设置好了TSDS,您可以像管理常规数据流一样管理和使用它。更多信息,请参阅:

时间序列索引设置

edit

时间序列数据流(TSDS)中的后备索引支持以下索引设置。

index.mode
(静态, 字符串) 索引的模式。 有效值为 time_seriesnull(无模式)。 默认为 null
index.time_series.start_time
(静态, 字符串) 索引接受的最早的 @timestamp 值(包含)。只有 index.modetime_series 的索引支持此设置。更多信息,请参阅 时间界限索引
index.time_series.end_time
(动态, 字符串) 索引接受的最新 @timestamp 值(不包括)。只有 index.modetime_series 的索引支持此设置。更多信息,请参阅 时间界限索引
index.look_ahead_time
(静态, 时间单位) 用于计算TSDS写入索引的index.time_series.end_time的时间间隔。默认为30m(30分钟)。接受1m(一分钟)到2h(两小时)。只有index.modetime_series的索引支持此设置。 有关更多信息,请参阅前瞻时间。此外,此设置不能小于time_series.poll_interval集群设置。

增加 look_ahead_time 也会增加索引生命周期管理在执行预期索引不再接收任何写入操作之前等待的时间。更多信息,请参阅 Time-bound indices

index.look_back_time
(静态, 时间单位) 用于计算TSDS的第一个后备索引的index.time_series.start_time的时间间隔,当创建tsdb数据流时。默认为2h(2小时)。接受1m(一分钟)到7d(七天)。只有index.modetime_series的索引支持此设置。更多信息,请参阅回溯时间
index.routing_path
(静态, 字符串或字符串数组) 纯 keyword 字段,用于在 TSDS 中将文档路由到索引分片。支持通配符 (*)。只有 index.modetime_series 的索引支持此设置。 默认为空列表,除非是数据流,则默认为组件和索引模板中定义的 维度字段 列表,且 time_series_dimension 值为 true。有关更多信息,请参阅 基于维度的路由
index.mapping.dimension_fields.limit
(动态, 整数) 索引的最大时间序列维度数量。默认为32768

对时间序列数据流进行下采样

edit

下采样提供了一种方法,通过以降低的粒度存储数据来减少您的时间序列数据的占用空间。

指标解决方案收集大量随时间增长的时间序列数据。 随着数据的陈旧,它对系统当前状态的相关性降低。 下采样过程将固定时间间隔内的文档汇总为 单个摘要文档。每个摘要文档包括原始数据的统计 表示:每个指标的最小值最大值总和值计数。数据流时间序列维度 保持不变。

下采样实际上允许你用数据分辨率和精度来换取存储大小。你可以将其包含在索引生命周期管理(ILM)策略中,以自动管理随着时间推移的指标数据量及其相关成本。

查看以下部分以了解更多信息:

工作原理

edit

一个时间序列是一个特定实体在时间上的一系列观测结果。观测样本可以表示为一个连续函数,其中时间序列的维度保持不变,而时间序列的指标随时间变化。

time series function

在Elasticsearch索引中,每个时间戳都会创建一个单独的文档,其中包含不可变的时间序列维度,以及指标名称和变化的指标值。对于单个时间戳,可能会存储多个时间序列维度和指标。

time series metric anatomy

对于您最新和最相关的数据,指标系列通常具有较低的采样时间间隔,因此它针对需要高数据分辨率的查询进行了优化。

time series original
Figure 4. Original metrics series

下采样通过用更高采样间隔的数据流和该数据的统计表示来替换原始时间序列,适用于较旧、访问频率较低的数据。例如,原始指标样本可能每十秒采集一次,随着数据的老化,您可以选择将采样粒度减少到每小时或每天。您可以选择将归档数据的粒度减少到每月或更少。

time series downsampled
Figure 5. Downsampled metrics series

对时间序列数据进行降采样

edit

要下采样时间序列索引,请使用下采样API并将fixed_interval设置为您所需的粒度级别:

POST /my-time-series-index/_downsample/my-downsampled-time-series-index
{
    "fixed_interval": "1d"
}

要在ILM过程中对时间序列数据进行下采样,请在您的ILM策略中包含一个 下采样操作,并将fixed_interval 设置为您所需的粒度级别:

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "downsample" : {
            "fixed_interval": "1h"
          }
        }
      }
    }
  }
}

查询降采样索引

edit

您可以使用 _search_async_search 端点来查询降采样索引。可以在单个请求中查询多个原始数据和降采样索引,并且单个请求可以包括不同粒度(不同的时间跨度)的降采样索引。也就是说,您可以查询包含具有多个降采样间隔(例如,15m1h1d)的降采样索引的数据流。

基于时间的直方图聚合结果具有统一的桶大小,并且每个下采样索引返回数据时忽略下采样时间间隔。例如,如果您在已按小时分辨率下采样的索引上运行带有"fixed_interval": "1m"date_histogram聚合,查询将返回一个包含所有数据的桶,时间为0分钟,然后是59个空桶,接着是下一个小时的数据桶。

降采样查询的注意事项

edit

关于查询下采样索引,有几点需要注意:

  • 当您在Kibana和通过Elastic解决方案运行查询时,会返回一个正常的响应,而不会通知您某些查询的索引已被降采样。
  • 对于 日期直方图聚合, 仅支持fixed_intervals(而不是日历感知的间隔)。
  • 时区支持有一些注意事项:

    • 以小时倍数为间隔的日期直方图基于UTC生成的值。这对于整点时区(例如+5:00或-3:00)效果良好,但需要调整报告的时间桶,例如 2020-01-01T10:30:00.000 而不是 2020-03-07T10:00:00.000 对于时区+5:30(印度),如果降采样按小时聚合值。在这种情况下, 结果中包含字段 downsampled_results_offset: true,以指示时间桶已偏移。如果使用15分钟的降采样间隔,则可以避免这种情况,因为它允许正确计算偏移桶的小时值。
    • 以天倍数为间隔的日期直方图同样受到影响,如果降采样按天聚合值。在这种情况下,每天的开始总是以UTC计算生成的降采样值,因此需要调整时间桶,例如报告为 2020-03-07T19:00:00.000 而不是 2020-03-07T00:00:00.000 对于时区 America/New_York。 在这种情况下也会添加字段 downsampled_results_offset: true
    • 夏令时和时区周围的类似特殊情况会影响报告的结果,如 文档 中所述的日期直方图聚合。此外,按每日间隔降采样会妨碍跟踪与夏令时变化相关的任何信息。

限制和限制

edit

以下是下采样的限制和限制:

  • 仅支持在时间序列数据流中的索引。
  • 数据仅基于时间维度进行降采样。所有其他维度将复制到新索引中,不做任何修改。
  • 在一个数据流中,降采样索引将替换原始索引,并且原始索引将被删除。给定时间段内只能存在一个索引。
  • 源索引必须处于只读模式,降采样过程才能成功。有关详细信息,请查看手动运行降采样示例。
  • 支持对同一时间段多次进行数据降采样(对降采样索引进行降采样)。降采样间隔必须是降采样索引间隔的倍数。
  • 降采样作为ILM操作提供。请参阅降采样
  • 新的降采样索引在原始索引的数据层上创建,并继承其设置(例如,分片和副本的数量)。
  • 支持数值类型的gaugecounter度量类型
  • 降采样配置从时间序列数据流的索引映射中提取。唯一需要的额外设置是降采样fixed_interval

试一试

edit

要进行下采样的测试运行,请尝试我们的示例,即手动运行下采样

下采样可以轻松添加到您的 ILM 策略中。要了解如何操作,请尝试我们的 使用 ILM 进行下采样 示例。

使用ILM运行下采样

edit

这是一个简化的示例,让您快速了解如何将降采样作为ILM策略的一部分,以减少采样指标集的存储大小。该示例使用了典型的Kubernetes集群监控数据。要使用ILM测试降采样,请按照以下步骤操作:

先决条件

edit

请参阅时间序列数据流先决条件

在运行此示例之前,您可能想要尝试 手动运行降采样 示例。

创建索引生命周期策略

edit

为您的时序数据创建一个ILM策略。虽然不是必需的,但建议使用ILM策略来自动管理您的时序数据流索引。

要启用降采样,请添加一个降采样操作并设置 fixed_interval为你要聚合原始时间序列数据的降采样间隔。

在这个示例中,为hot阶段配置了一个ILM策略。降采样在索引滚动更新并且索引时间序列结束时间已过期后进行,因为源索引在此之前仍预计会接收主要的写入操作。索引生命周期管理不会执行任何期望索引不再接收写入的操作,直到索引的结束时间已过。在继续之前等待结束时间的索引生命周期管理操作包括: - 删除 - 降采样 - 强制合并 - 只读 - 可搜索快照 - 收缩

PUT _ilm/policy/datastream_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover" : {
            "max_age": "5m"
          },
          "downsample": {
  	        "fixed_interval": "1h"
  	      }
        }
      }
    }
  }
}

创建索引模板

edit

这为基本数据流创建了一个索引模板。索引模板的可用参数在设置时间序列数据流中有详细描述。

为简单起见,在时间序列映射中,所有 time_series_metric 参数都被设置为类型 gauge,但也可以使用 counter 指标类型。time_series_metric 值决定了在降采样期间使用的统计表示类型。

索引模板包含一组静态的时间序列维度hostnamespacenodepod。时间序列维度不会因降采样过程而改变。

PUT _index_template/datastream_template
{
    "index_patterns": [
        "datastream*"
    ],
    "data_stream": {},
    "template": {
        "settings": {
            "index": {
                "mode": "time_series",
                "number_of_replicas": 0,
                "number_of_shards": 2
            },
            "index.lifecycle.name": "datastream_policy"
        },
        "mappings": {
            "properties": {
                "@timestamp": {
                    "type": "date"
                },
                "kubernetes": {
                    "properties": {
                        "container": {
                            "properties": {
                                "cpu": {
                                    "properties": {
                                        "usage": {
                                            "properties": {
                                                "core": {
                                                    "properties": {
                                                        "ns": {
                                                            "type": "long"
                                                        }
                                                    }
                                                },
                                                "limit": {
                                                    "properties": {
                                                        "pct": {
                                                            "type": "float"
                                                        }
                                                    }
                                                },
                                                "nanocores": {
                                                    "type": "long",
                                                    "time_series_metric": "gauge"
                                                },
                                                "node": {
                                                    "properties": {
                                                        "pct": {
                                                            "type": "float"
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                },
                                "memory": {
                                    "properties": {
                                        "available": {
                                            "properties": {
                                                "bytes": {
                                                    "type": "long",
                                                    "time_series_metric": "gauge"
                                                }
                                            }
                                        },
                                        "majorpagefaults": {
                                            "type": "long"
                                        },
                                        "pagefaults": {
                                            "type": "long",
                                            "time_series_metric": "gauge"
                                        },
                                        "rss": {
                                            "properties": {
                                                "bytes": {
                                                    "type": "long",
                                                    "time_series_metric": "gauge"
                                                }
                                            }
                                        },
                                        "usage": {
                                            "properties": {
                                                "bytes": {
                                                    "type": "long",
                                                    "time_series_metric": "gauge"
                                                },
                                                "limit": {
                                                    "properties": {
                                                        "pct": {
                                                            "type": "float"
                                                        }
                                                    }
                                                },
                                                "node": {
                                                    "properties": {
                                                        "pct": {
                                                            "type": "float"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "workingset": {
                                            "properties": {
                                                "bytes": {
                                                    "type": "long",
                                                    "time_series_metric": "gauge"
                                                }
                                            }
                                        }
                                    }
                                },
                                "name": {
                                    "type": "keyword"
                                },
                                "start_time": {
                                    "type": "date"
                                }
                            }
                        },
                        "host": {
                            "type": "keyword",
                            "time_series_dimension": true
                        },
                        "namespace": {
                            "type": "keyword",
                            "time_series_dimension": true
                        },
                        "node": {
                            "type": "keyword",
                            "time_series_dimension": true
                        },
                        "pod": {
                            "type": "keyword",
                            "time_series_dimension": true
                        }
                    }
                }
            }
        }
    }
}

摄取时间序列数据

edit

使用批量API请求来自动创建您的TSDS并索引一组十个文档。

重要: 在运行此批量请求之前,您需要将时间戳更新为当前时间后的三到五小时。即,搜索 2022-06-21T15 并替换为当前日期,并将小时调整为当前时间加三小时。

PUT /datastream/_bulk?refresh
{"create": {}}
{"@timestamp":"2022-06-21T15:49:00Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":91153,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":463314616},"usage":{"bytes":307007078,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":585236},"rss":{"bytes":102728},"pagefaults":120901,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:45:50Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":124501,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":982546514},"usage":{"bytes":360035574,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1339884},"rss":{"bytes":381174},"pagefaults":178473,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:44:50Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":38907,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":862723768},"usage":{"bytes":379572388,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":431227},"rss":{"bytes":386580},"pagefaults":233166,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:44:40Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":86706,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":567160996},"usage":{"bytes":103266017,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1724908},"rss":{"bytes":105431},"pagefaults":233166,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:44:00Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":150069,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":639054643},"usage":{"bytes":265142477,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1786511},"rss":{"bytes":189235},"pagefaults":138172,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:42:40Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":82260,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":854735585},"usage":{"bytes":309798052,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":924058},"rss":{"bytes":110838},"pagefaults":259073,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:42:10Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":153404,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":279586406},"usage":{"bytes":214904955,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1047265},"rss":{"bytes":91914},"pagefaults":302252,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:40:20Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":125613,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":822782853},"usage":{"bytes":100475044,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":2109932},"rss":{"bytes":278446},"pagefaults":74843,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:40:10Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":100046,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":567160996},"usage":{"bytes":362826547,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1986724},"rss":{"bytes":402801},"pagefaults":296495,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:38:30Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":40018,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":1062428344},"usage":{"bytes":265142477,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":2294743},"rss":{"bytes":340623},"pagefaults":224530,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}

查看结果

edit

现在您已经创建并添加了文档到数据流中,请检查以确认新索引的当前状态。

GET _data_stream

如果ILM策略尚未应用,您的结果将如下所示。注意原始的index_name.ds-datastream--000001

{
  "data_streams": [
    {
      "name": "datastream",
      "timestamp_field": {
        "name": "@timestamp"
      },
      "indices": [
        {
          "index_name": ".ds-datastream-2022.08.26-000001",
          "index_uuid": "5g-3HrfETga-5EFKBM6R-w"
        },
        {
          "index_name": ".ds-datastream-2022.08.26-000002",
          "index_uuid": "o0yRTdhWSo2pY8XMvfwy7Q"
        }
      ],
      "generation": 2,
      "status": "GREEN",
      "template": "datastream_template",
      "ilm_policy": "datastream_policy",
      "hidden": false,
      "system": false,
      "allow_custom_routing": false,
      "replicated": false,
      "rollover_on_write": false,
      "time_series": {
        "temporal_ranges": [
          {
            "start": "2022-08-26T13:29:07.000Z",
            "end": "2022-08-26T19:29:07.000Z"
          }
        ]
      }
    }
  ]
}

接下来,运行一个搜索查询:

GET datastream/_search

查询返回您新添加的十个文档。

{
  "took": 17,
  "timed_out": false,
  "_shards": {
    "total": 4,
    "successful": 4,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10,
      "relation": "eq"
    },
...

默认情况下,索引生命周期管理每十分钟检查一次符合策略标准的索引。等待大约十分钟(也许可以快速泡一杯咖啡或茶 ☕ ),然后重新运行 GET _data_stream 请求。

GET _data_stream

在ILM策略生效后,原始的 .ds-datastream-2022.08.26-000001 索引被一个新的、降采样的索引所替换,在这个例子中是 downsample-6tkn-.ds-datastream-2022.08.26-000001

{
  "data_streams": [
    {
      "name": "datastream",
      "timestamp_field": {
        "name": "@timestamp"
      },
      "indices": [
        {
          "index_name": "downsample-6tkn-.ds-datastream-2022.08.26-000001",
          "index_uuid": "qRane1fQQDCNgKQhXmTIvg"
        },
        {
          "index_name": ".ds-datastream-2022.08.26-000002",
          "index_uuid": "o0yRTdhWSo2pY8XMvfwy7Q"
        }
      ],
...

在数据流上运行搜索查询(请注意,在查询下采样索引时,有一些需要注意的细微差别)。

GET datastream/_search

新的下采样索引仅包含一个文档,该文档包括基于原始采样指标的最小值最大值总和值计数统计信息。

{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 4,
    "successful": 4,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "downsample-6tkn-.ds-datastream-2022.08.26-000001",
        "_id": "0eL0wC_4-45SnTNFAAABgtpz0wA",
        "_score": 1,
        "_source": {
          "@timestamp": "2022-08-26T14:00:00.000Z",
          "_doc_count": 10,
          "kubernetes.host": "gke-apps-0",
          "kubernetes.namespace": "namespace26",
          "kubernetes.node": "gke-apps-0-0",
          "kubernetes.pod": "gke-apps-0-0-0",
          "kubernetes.container.cpu.usage.nanocores": {
            "min": 38907,
            "max": 153404,
            "sum": 992677,
            "value_count": 10
          },
          "kubernetes.container.memory.available.bytes": {
            "min": 279586406,
            "max": 1062428344,
            "sum": 7101494721,
            "value_count": 10
          },
          "kubernetes.container.memory.pagefaults": {
            "min": 74843,
            "max": 302252,
            "sum": 2061071,
            "value_count": 10
          },
          "kubernetes.container.memory.rss.bytes": {
            "min": 91914,
            "max": 402801,
            "sum": 2389770,
            "value_count": 10
          },
          "kubernetes.container.memory.usage.bytes": {
            "min": 100475044,
            "max": 379572388,
            "sum": 2668170609,
            "value_count": 10
          },
          "kubernetes.container.memory.workingset.bytes": {
            "min": 431227,
            "max": 2294743,
            "sum": 14230488,
            "value_count": 10
          },
          "kubernetes.container.cpu.usage.core.ns": 12828317850,
          "kubernetes.container.cpu.usage.limit.pct": 0.000027790500098490156,
          "kubernetes.container.cpu.usage.node.pct": 0.000027790500098490156,
          "kubernetes.container.memory.majorpagefaults": 0,
          "kubernetes.container.memory.usage.limit.pct": 0.00009923134348355234,
          "kubernetes.container.memory.usage.node.pct": 0.017700377851724625,
          "kubernetes.container.name": "container-name-44",
          "kubernetes.container.start_time": "2021-03-30T07:59:06.000Z"
        }
      }
    ]
  }
}

使用数据流统计API获取数据流的统计信息,包括存储大小。

GET /_data_stream/datastream/_stats?human=true
{
  "_shards": {
    "total": 4,
    "successful": 4,
    "failed": 0
  },
  "data_stream_count": 1,
  "backing_indices": 2,
  "total_store_size": "16.6kb",
  "total_store_size_bytes": 17059,
  "data_streams": [
    {
      "data_stream": "datastream",
      "backing_indices": 2,
      "store_size": "16.6kb",
      "store_size_bytes": 17059,
      "maximum_timestamp": 1661522400000
    }
  ]
}

此示例演示了作为ILM策略的一部分,降采样如何工作,以减少随着时间推移变得不再那么当前且查询频率降低的指标数据的存储大小。

您还可以尝试我们的手动运行降采样示例,了解如何在ILM策略之外进行降采样。

手动运行降采样

edit

推荐的降采样一个时间序列数据流 (TSDS)的方法是通过索引生命周期管理 (ILM)。然而,如果你没有使用ILM,你可以手动降采样一个TSDS。本指南将向你展示如何操作,使用典型的Kubernetes集群监控数据。

要测试手动下采样,请按照以下步骤操作:

先决条件

edit
  • 请参考TSDS 先决条件
  • 无法直接对数据流进行降采样,也无法同时对多个索引进行降采样。只能对一个时间序列索引(TSDS 后备索引)进行降采样。
  • 为了对索引进行降采样,它需要是只读的。对于 TSDS 写入索引,这意味着需要先对其进行滚动更新并设置为只读。
  • 降采样使用 UTC 时间戳。
  • 降采样需要时间序列索引中至少存在一个度量字段。

创建时间序列数据流

edit

首先,您将创建一个TSDS。为了简单起见,在时间序列映射中,所有time_series_metric参数都被设置为类型gauge,但也可以使用其他值,例如counterhistogramtime_series_metric值决定了在降采样期间使用的统计表示类型。

索引模板包含一组静态的 时间序列维度hostnamespacenodepod。时间序列维度不会被降采样过程更改。

PUT _index_template/my-data-stream-template
{
  "index_patterns": [
    "my-data-stream*"
  ],
  "data_stream": {},
  "template": {
    "settings": {
      "index": {
        "mode": "time_series",
        "routing_path": [
          "kubernetes.namespace",
          "kubernetes.host",
          "kubernetes.node",
          "kubernetes.pod"
        ],
        "number_of_replicas": 0,
        "number_of_shards": 2
      }
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "kubernetes": {
          "properties": {
            "container": {
              "properties": {
                "cpu": {
                  "properties": {
                    "usage": {
                      "properties": {
                        "core": {
                          "properties": {
                            "ns": {
                              "type": "long"
                            }
                          }
                        },
                        "limit": {
                          "properties": {
                            "pct": {
                              "type": "float"
                            }
                          }
                        },
                        "nanocores": {
                          "type": "long",
                          "time_series_metric": "gauge"
                        },
                        "node": {
                          "properties": {
                            "pct": {
                              "type": "float"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "memory": {
                  "properties": {
                    "available": {
                      "properties": {
                        "bytes": {
                          "type": "long",
                          "time_series_metric": "gauge"
                        }
                      }
                    },
                    "majorpagefaults": {
                      "type": "long"
                    },
                    "pagefaults": {
                      "type": "long",
                      "time_series_metric": "gauge"
                    },
                    "rss": {
                      "properties": {
                        "bytes": {
                          "type": "long",
                          "time_series_metric": "gauge"
                        }
                      }
                    },
                    "usage": {
                      "properties": {
                        "bytes": {
                          "type": "long",
                          "time_series_metric": "gauge"
                        },
                        "limit": {
                          "properties": {
                            "pct": {
                              "type": "float"
                            }
                          }
                        },
                        "node": {
                          "properties": {
                            "pct": {
                              "type": "float"
                            }
                          }
                        }
                      }
                    },
                    "workingset": {
                      "properties": {
                        "bytes": {
                          "type": "long",
                          "time_series_metric": "gauge"
                        }
                      }
                    }
                  }
                },
                "name": {
                  "type": "keyword"
                },
                "start_time": {
                  "type": "date"
                }
              }
            },
            "host": {
              "type": "keyword",
              "time_series_dimension": true
            },
            "namespace": {
              "type": "keyword",
              "time_series_dimension": true
            },
            "node": {
              "type": "keyword",
              "time_series_dimension": true
            },
            "pod": {
              "type": "keyword",
              "time_series_dimension": true
            }
          }
        }
      }
    }
  }
}

摄取时间序列数据

edit

由于时间序列数据流已被设计为 仅接受最近的数据,在此示例中,您将 使用摄取管道来对数据进行时间偏移,因为它被索引。因此, 索引的数据将具有过去15分钟内的@timestamp

使用此请求创建管道:

PUT _ingest/pipeline/my-timestamp-pipeline
{
  "description": "Shifts the @timestamp to the last 15 minutes",
  "processors": [
    {
      "set": {
        "field": "ingest_time",
        "value": "{{_ingest.timestamp}}"
      }
    },
    {
      "script": {
        "lang": "painless",
        "source": """
          def delta = ChronoUnit.SECONDS.between(
            ZonedDateTime.parse("2022-06-21T15:49:00Z"),
            ZonedDateTime.parse(ctx["ingest_time"])
          );
          ctx["@timestamp"] = ZonedDateTime.parse(ctx["@timestamp"]).plus(delta,ChronoUnit.SECONDS).toString();
        """
      }
    }
  ]
}

接下来,使用批量 API 请求来自动创建您的 TSDS 并索引一组十个文档:

PUT /my-data-stream/_bulk?refresh&pipeline=my-timestamp-pipeline
{"create": {}}
{"@timestamp":"2022-06-21T15:49:00Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":91153,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":463314616},"usage":{"bytes":307007078,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":585236},"rss":{"bytes":102728},"pagefaults":120901,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:45:50Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":124501,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":982546514},"usage":{"bytes":360035574,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1339884},"rss":{"bytes":381174},"pagefaults":178473,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:44:50Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":38907,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":862723768},"usage":{"bytes":379572388,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":431227},"rss":{"bytes":386580},"pagefaults":233166,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:44:40Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":86706,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":567160996},"usage":{"bytes":103266017,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1724908},"rss":{"bytes":105431},"pagefaults":233166,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:44:00Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":150069,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":639054643},"usage":{"bytes":265142477,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1786511},"rss":{"bytes":189235},"pagefaults":138172,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:42:40Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":82260,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":854735585},"usage":{"bytes":309798052,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":924058},"rss":{"bytes":110838},"pagefaults":259073,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:42:10Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":153404,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":279586406},"usage":{"bytes":214904955,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1047265},"rss":{"bytes":91914},"pagefaults":302252,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:40:20Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":125613,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":822782853},"usage":{"bytes":100475044,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":2109932},"rss":{"bytes":278446},"pagefaults":74843,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:40:10Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":100046,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":567160996},"usage":{"bytes":362826547,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":1986724},"rss":{"bytes":402801},"pagefaults":296495,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}
{"create": {}}
{"@timestamp":"2022-06-21T15:38:30Z","kubernetes":{"host":"gke-apps-0","node":"gke-apps-0-0","pod":"gke-apps-0-0-0","container":{"cpu":{"usage":{"nanocores":40018,"core":{"ns":12828317850},"node":{"pct":2.77905e-05},"limit":{"pct":2.77905e-05}}},"memory":{"available":{"bytes":1062428344},"usage":{"bytes":265142477,"node":{"pct":0.01770037710617187},"limit":{"pct":9.923134671484496e-05}},"workingset":{"bytes":2294743},"rss":{"bytes":340623},"pagefaults":224530,"majorpagefaults":0},"start_time":"2021-03-30T07:59:06Z","name":"container-name-44"},"namespace":"namespace26"}}

您可以使用搜索 API 来检查文档是否已正确索引:

GET /my-data-stream/_search

对数据运行以下聚合以计算一些有趣的统计数据:

GET /my-data-stream/_search
{
    "size": 0,
    "aggs": {
        "tsid": {
            "terms": {
                "field": "_tsid"
            },
            "aggs": {
                "over_time": {
                    "date_histogram": {
                        "field": "@timestamp",
                        "fixed_interval": "1d"
                    },
                    "aggs": {
                        "min": {
                            "min": {
                                "field": "kubernetes.container.memory.usage.bytes"
                            }
                        },
                        "max": {
                            "max": {
                                "field": "kubernetes.container.memory.usage.bytes"
                            }
                        },
                        "avg": {
                            "avg": {
                                "field": "kubernetes.container.memory.usage.bytes"
                            }
                        }
                    }
                }
            }
        }
    }
}

对TSDS进行下采样

edit

TSDS 不能直接进行下采样。您需要对其支持索引进行下采样。您可以通过运行以下命令查看数据流的支持索引:

GET /_data_stream/my-data-stream

这将返回:

{
  "data_streams": [
    {
      "name": "my-data-stream",
      "timestamp_field": {
        "name": "@timestamp"
      },
      "indices": [
        {
          "index_name": ".ds-my-data-stream-2023.07.26-000001", 
          "index_uuid": "ltOJGmqgTVm4T-Buoe7Acg",
          "prefer_ilm": true,
          "managed_by": "Unmanaged"
        }
      ],
      "generation": 1,
      "status": "GREEN",
      "next_generation_managed_by": "Unmanaged",
      "prefer_ilm": true,
      "template": "my-data-stream-template",
      "hidden": false,
      "system": false,
      "allow_custom_routing": false,
      "replicated": false,
      "rollover_on_write": false,
      "time_series": {
        "temporal_ranges": [
          {
            "start": "2023-07-26T09:26:42.000Z",
            "end": "2023-07-26T13:26:42.000Z"
          }
        ]
      }
    }
  ]
}

此数据流的备份索引。

在降采样备份索引之前,TSDS 需要进行滚动更新,并且旧索引需要设置为只读。

使用rollover API滚动TSDS:

POST /my-data-stream/_rollover/

从响应中复制old_index的名称。在以下步骤中,将索引名称替换为您的old_index的名称。

旧索引需要设置为只读模式。运行以下请求:

PUT /.ds-my-data-stream-2023.07.26-000001/_block/write

接下来,使用降采样 API对索引进行降采样,将时间序列间隔设置为一小时:

POST /.ds-my-data-stream-2023.07.26-000001/_downsample/.ds-my-data-stream-2023.07.26-000001-downsample
{
  "fixed_interval": "1h"
}

现在你可以修改数据流,并用降采样后的索引替换原始索引:

POST _data_stream/_modify
{
  "actions": [
    {
      "remove_backing_index": {
        "data_stream": "my-data-stream",
        "index": ".ds-my-data-stream-2023.07.26-000001"
      }
    },
    {
      "add_backing_index": {
        "data_stream": "my-data-stream",
        "index": ".ds-my-data-stream-2023.07.26-000001-downsample"
      }
    }
  ]
}

你现在可以删除旧的备份索引。但请注意,这将删除原始数据。如果你将来可能需要原始数据,请不要删除该索引。

查看结果

edit

重新运行之前的搜索查询(注意,在查询下采样索引时,有一些细微差别需要注意):

GET /my-data-stream/_search

新的下采样后备索引中的TSDS仅包含一个文档。对于计数器,此文档仅包含最后一个值。对于仪表,字段类型现在是aggregate_metric_double。您可以看到基于原始采样指标的minmaxsumvalue_count统计信息:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 4,
    "successful": 4,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": ".ds-my-data-stream-2023.07.26-000001-downsample",
        "_id": "0eL0wC_4-45SnTNFAAABiZHbD4A",
        "_score": 1,
        "_source": {
          "@timestamp": "2023-07-26T11:00:00.000Z",
          "_doc_count": 10,
          "ingest_time": "2023-07-26T11:26:42.715Z",
          "kubernetes": {
            "container": {
              "cpu": {
                "usage": {
                  "core": {
                    "ns": 12828317850
                  },
                  "limit": {
                    "pct": 0.0000277905
                  },
                  "nanocores": {
                    "min": 38907,
                    "max": 153404,
                    "sum": 992677,
                    "value_count": 10
                  },
                  "node": {
                    "pct": 0.0000277905
                  }
                }
              },
              "memory": {
                "available": {
                  "bytes": {
                    "min": 279586406,
                    "max": 1062428344,
                    "sum": 7101494721,
                    "value_count": 10
                  }
                },
                "majorpagefaults": 0,
                "pagefaults": {
                  "min": 74843,
                  "max": 302252,
                  "sum": 2061071,
                  "value_count": 10
                },
                "rss": {
                  "bytes": {
                    "min": 91914,
                    "max": 402801,
                    "sum": 2389770,
                    "value_count": 10
                  }
                },
                "usage": {
                  "bytes": {
                    "min": 100475044,
                    "max": 379572388,
                    "sum": 2668170609,
                    "value_count": 10
                  },
                  "limit": {
                    "pct": 0.00009923134
                  },
                  "node": {
                    "pct": 0.017700378
                  }
                },
                "workingset": {
                  "bytes": {
                    "min": 431227,
                    "max": 2294743,
                    "sum": 14230488,
                    "value_count": 10
                  }
                }
              },
              "name": "container-name-44",
              "start_time": "2021-03-30T07:59:06.000Z"
            },
            "host": "gke-apps-0",
            "namespace": "namespace26",
            "node": "gke-apps-0-0",
            "pod": "gke-apps-0-0-0"
          }
        }
      }
    ]
  }
}

重新运行之前的聚合。即使聚合是在仅包含1个文档的降采样TSDS上运行的,它返回的结果与在原始TSDS上运行的早期聚合结果相同。

GET /my-data-stream/_search
{
    "size": 0,
    "aggs": {
        "tsid": {
            "terms": {
                "field": "_tsid"
            },
            "aggs": {
                "over_time": {
                    "date_histogram": {
                        "field": "@timestamp",
                        "fixed_interval": "1d"
                    },
                    "aggs": {
                        "min": {
                            "min": {
                                "field": "kubernetes.container.memory.usage.bytes"
                            }
                        },
                        "max": {
                            "max": {
                                "field": "kubernetes.container.memory.usage.bytes"
                            }
                        },
                        "avg": {
                            "avg": {
                                "field": "kubernetes.container.memory.usage.bytes"
                            }
                        }
                    }
                }
            }
        }
    }
}

此示例演示了如何在您选择的时间边界内,通过下采样显著减少时间序列数据存储的文档数量。还可以对已经下采样的数据进行下采样,以进一步减少存储和相关成本,因为随着时间序列数据的积累,数据分辨率变得不那么关键。

推荐的降采样TSDS的方法是使用ILM。了解更多信息,请尝试使用ILM进行降采样示例。

重新索引时间序列数据流 (TSDS)

edit

介绍

edit

通过重新索引,您可以将文档从一个旧的时间序列数据流 (TSDS)复制到一个新的数据流中。数据流通常支持重新索引,但有一些限制。然而,时间序列数据流由于对每个支持索引所接受的时间戳范围的严格控制,引入了额外的挑战。直接使用重新索引 API 可能会由于尝试插入时间戳超出当前接受窗口的文档而导致错误。

为避免这些限制,请使用下面概述的流程:

  1. 为目标数据流创建一个索引模板,该数据流将包含重新索引的数据。
  2. 更新模板为

    1. index.time_series.start_timeindex.time_series.end_time 索引设置设置为 与旧数据流中的最低和最高 @timestamp 值匹配。
    2. index.number_of_shards 索引设置设置为旧数据流所有后备索引的所有主分片的总和。
    3. index.number_of_replicas 设置为零,并取消设置 index.lifecycle.name 索引设置。
  3. 运行重新索引操作直至完成。
  4. 恢复目标索引模板中覆盖的索引设置。
  5. 调用 rollover API 以创建一个新的后备索引,该索引可以接收新文档。

此过程仅适用于未配置降采样的时间序列数据流。具有降采样的数据流只能通过分别重新索引其支持的索引并将它们添加到空的目标数据流中来进行重新索引。

在下文中,我们将通过示例详细阐述每个步骤。

创建一个TSDS模板以接受旧文档

edit

考虑一个具有以下模板的TSDS:

POST /_component_template/source_template
{
  "template": {
    "settings": {
      "index": {
        "number_of_replicas": 2,
        "number_of_shards": 2,
        "mode": "time_series",
        "routing_path": [ "metricset" ]
      }
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "metricset": {
          "type": "keyword",
          "time_series_dimension": true
        },
        "k8s": {
          "properties": {
            "tx": { "type": "long" },
            "rx": { "type": "long" }
          }
        }
      }
    }
  }
}

POST /_index_template/1
{
  "index_patterns": [
    "k8s*"
  ],
  "composed_of": [
    "source_template"
  ],
  "data_stream": {}
}

一个可能的输出 /k8s/_settings 如下:

{
  ".ds-k8s-2023.09.01-000002": {
    "settings": {
      "index": {
        "mode": "time_series",
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_hot"
            }
          }
        },
        "hidden": "true",
        "number_of_shards": "2",
        "time_series": {
          "end_time": "2023-09-01T14:00:00.000Z",
          "start_time": "2023-09-01T10:00:00.000Z"
        },
        "provided_name": ".ds-k9s-2023.09.01-000002",
        "creation_date": "1694439857608",
        "number_of_replicas": "2",
        "routing_path": [
          "metricset"
        ],
        ...
      }
    }
  },
  ".ds-k8s-2023.09.01-000001": {
    "settings": {
      "index": {
        "mode": "time_series",
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_hot"
            }
          }
        },
        "hidden": "true",
        "number_of_shards": "2",
        "time_series": {
          "end_time": "2023-09-01T10:00:00.000Z",
          "start_time": "2023-09-01T06:00:00.000Z"
        },
        "provided_name": ".ds-k9s-2023.09.01-000001",
        "creation_date": "1694439837126",
        "number_of_replicas": "2",
        "routing_path": [
          "metricset"
        ],
        ...
      }
    }
  }
}

要重新索引此TSDS,请不要在目标数据流中重复使用其索引模板,以避免影响其功能。相反,克隆源TSDS的模板并应用以下修改:

  • 设置 index.time_series.start_timeindex.time_series.end_time 索引设置为显式值。它们的值应基于数据流中最低和最高的 @timestamp 值进行重新索引。这样,初始的后备索引可以加载源数据流中包含的所有数据。
  • index.number_of_shards 索引设置为源数据流所有后备索引的所有主分片之和。这有助于保持相同的搜索并行度,因为每个分片都在单独的线程中处理(或更多)。
  • 如果有,取消设置 index.lifecycle.name 索引设置。这可以防止ILM在重新索引期间修改目标数据流。
  • (可选)将 index.number_of_replicas 设置为零。这有助于加快重新索引操作。由于数据被复制,因此由于缺少副本而导致数据丢失的风险有限。

使用上述示例作为源TSDS,目标TSDS的模板将是:

POST /_component_template/destination_template
{
  "template": {
    "settings": {
      "index": {
        "number_of_replicas": 0,
        "number_of_shards": 4,
        "mode": "time_series",
        "routing_path": [ "metricset" ],
        "time_series": {
          "end_time": "2023-09-01T14:00:00.000Z",
          "start_time": "2023-09-01T06:00:00.000Z"
        }
      }
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "metricset": {
          "type": "keyword",
          "time_series_dimension": true
        },
        "k8s": {
          "properties": {
            "tx": { "type": "long" },
            "rx": { "type": "long" }
          }
        }
      }
    }
  }
}

POST /_index_template/2
{
  "index_patterns": [
    "k8s*"
  ],
  "composed_of": [
    "destination_template"
  ],
  "data_stream": {}
}

重新索引

edit

调用重新索引API,例如:

POST /_reindex
{
  "source": {
    "index": "k8s"
  },
  "dest": {
    "index": "k9s",
    "op_type": "create"
  }
}

恢复目标索引模板

edit

一旦重新索引操作完成,按如下方式恢复目标TSDS的索引模板:

  • 移除对index.time_series.start_timeindex.time_series.end_time的覆盖。
  • 恢复index.number_of_shardsindex.number_of_replicasindex.lifecycle.name的值(如适用)。

使用前面的示例,目标模板修改如下:

POST /_component_template/destination_template
{
  "template": {
    "settings": {
      "index": {
        "number_of_replicas": 2,
        "number_of_shards": 2,
        "mode": "time_series",
        "routing_path": [ "metricset" ]
      }
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "metricset": {
          "type": "keyword",
          "time_series_dimension": true
        },
        "k8s": {
          "properties": {
            "tx": { "type": "long" },
            "rx": { "type": "long" }
          }
        }
      }
    }
  }
}

接下来,在目标数据流上调用rollover API,不设置任何条件。

POST /k9s/_rollover/

这将使用更新的索引设置创建一个新的后备索引。目标数据流现在已准备好接受新文档。

请注意,初始备份索引仍然可以在从源数据流派生的时间戳范围内接受文档。如果不希望如此,请明确将其标记为只读