「时序数据与 TSDB:从数据流到生命周期治理」

讲解 Elasticsearch 时序数据处理:数据流与索引生命周期、TSDB 索引模式、采样与降维、date_histogram 时序聚合,以及预测与异常检测的落地。

指标监控、设备遥测、访问日志构成了典型的时序数据:随时间追加、按时间查询、老数据价值递减。Elasticsearch 用数据流承载时序数据,用 ILM 管理生命周期,并在 8.x 引入 TSDB 模式压缩维度基数。本文从数据流讲起,覆盖 TSDB 索引、采样降维、时序聚合与预测异常检测。

1. 时序数据特征与数据流

一句话总结: 时序数据只追加、按时间查询、老数据降冷,数据流把多个滚动索引包装成一个可写可查的逻辑单元。

1.1 时序数据的三个特征

时序数据有三个典型特征:只追加写入、按时间范围查询、价值随时间衰减。它不像业务数据那样频繁更新,也不要求随机点查,因此可以按时间滚动索引、分阶段压缩与淘汰。

1.2 数据流的概念

数据流(Data Stream)由多个按时间滚动的后备索引组成,对外是单一写入口。写入时自动落到当前活跃索引,查询时跨全部后备索引。创建数据流需要先定义索引模板:

PUT _index_template/metrics_template
{
  "index_patterns": ["metrics-*"],
  "data_stream": {},
  "template": {
    "settings": { "number_of_shards": 2 },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "host": { "type": "keyword" },
        "cpu": { "type": "float" },
        "memory": { "type": "float" }
      }
    }
  }
}

1.3 写入与查询

数据流写入无需指定索引名,直接 PUT 到数据流名即可,ES 自动路由到当前写索引:

curl -X POST "localhost:9200/metrics/_doc" -H "Content-Type: application/json" -d'
{
  "@timestamp": "2026-10-01T08:00:00Z",
  "host": "web-01",
  "cpu": 0.42,
  "memory": 0.61
}
'

查询同样直接查数据流名,等价于查全部后备索引,按时间范围过滤天然高效。

2. 数据流与生命周期管理

一句话总结: ILM 把索引按年龄滚动到热、温、冷、冻结阶段,自动完成关合并、迁移与删除。

2.1 ILM 四阶段

ILM 生命周期分 hot、warm、cold、frozen、delete 五阶段:hot 负责写入,warm 关掉写入只读合并,cold 迁移到低配存储,frozen 只保留索引片段,delete 到期删除。每阶段可挂动作,到达条件自动触发。

2.2 一个完整的时序生命周期

PUT _ilm/policy/metrics-lifecycle
{
  "policy": {
    "phases": {
      "hot": { "actions": { "rollover": { "max_age": "1d", "max_size": "50gb" } } },
      "warm": {
        "min_age": "7d",
        "actions": { "force_merge": { "max_num_segments": 1 }, "shrink": { "number_of_shards": 1 } }
      },
      "cold": { "min_age": "30d", "actions": { "searchable_snapshot": { "snapshot_repository": "s3-backup" } } },
      "delete": { "min_age": "90d", "actions": { "delete": {} } }
    }
  }
}

rollover 用 max_age 或 max_size 滚动新索引;warm 阶段 force_merge 收敛段数、shrink 减分片;cold 阶段转可搜索快照释放本地磁盘;delete 到期清理。

2.3 数据流与 ILM 绑定

索引模板通过 lifecycle.name 把数据流绑定到策略,并指定滚动别名:

PUT _index_template/metrics_template
{
  "index_patterns": ["metrics-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "number_of_shards": 2,
      "index.lifecycle.name": "metrics-lifecycle",
      "index.lifecycle.rollover_alias": "metrics"
    }
  }
}

3. TSDB 索引模式

一句话总结: TSDB 模式把时序维度存成稀疏 doc-values 并按维度排序,显著压缩存储、提升按维度范围扫描的性能。

3.1 TSDB 解决的问题

通用索引为随机点查设计,每条指标都重复存储主机名、区域等维度标签,存储膨胀且扫描低效。TSDB 把时间戳与维度独立编码,仅存变化值,并让同一维度序列相邻存放,压缩率大幅提升。

3.2 开启 TSDB

8.7+ 在索引设置里开启 TSDB,维度字段用 time_series_dimension 标注:

PUT _index_template/metrics_template
{
  "index_patterns": ["metrics-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "index.mode": "time_series",
      "index.routing_path": ["host", "region"]
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "host": { "type": "keyword", "time_series_dimension": true },
        "region": { "type": "keyword", "time_series_dimension": true },
        "cpu": { "type": "float" }
      }
    }
  }
}

3.3 排序与查询优势

TSDB 索引按 routing_path 维度 + 时间排序,同一(host, region)序列在段内连续,按维度范围查询只需扫描一段连续区间,而非全量过滤。聚合按维度分组时也能顺序读取,避免大量随机 IO。

4. 采样与降维

一句话总结: 采样把高频原始指标折叠成分钟级统计值,与原始明细分开存储,兼顾查询速度与存储成本。

4.1 为什么要采样

原始指标每秒一条,90 天后仍是每天数亿条。多数分析只需要分钟级均值或 p95,而非每条原始值。采样用聚合把原始指标降成低频汇总,原始明细短期保留、采样结果长期保留。

4.2 采样聚合

用 date_histogram 按分钟分桶,桶内计算均值、最大、p95 等,把结果写入采样索引:

{
  "size": 0,
  "aggs": {
    "per_minute": {
      "date_histogram": { "field": "@timestamp", "fixed_interval": "1m" },
      "aggs": {
        "avg_cpu": { "avg": { "field": "cpu" } },
        "max_cpu": { "max": { "field": "cpu" } },
        "p95_cpu": { "percentiles": { "field": "cpu", "percents": [95] } }
      }
    }
  }
}

4.3 双轨存储策略

热层保留原始明细供排查,采样结果进长期索引受 ILM 治理。查询仪表盘走采样索引,查询速度恒定;点查原始明细按需降级到明细索引,二者用别名切换,对上层透明。

5. 时序聚合

一句话总结: 时序分析以 date_histogram 为主轴,配合多维度分组与区间过滤,回答「随时间怎么变」与「按维度怎么分」。

5.1 按维度分组的时序

仪表盘最常见的形态:X 轴时间、Y 轴指标、按主机分组多线:

{
  "size": 0,
  "aggs": {
    "by_host": {
      "terms": { "field": "host", "size": 5 },
      "aggs": {
        "by_time": {
          "date_histogram": { "field": "@timestamp", "fixed_interval": "1m" },
          "aggs": { "avg_cpu": { "avg": { "field": "cpu" } } }
        }
      }
    }
  }
}

5.2 区间过滤与时区对齐

时序查询必须限定时间范围并指定时区,避免查询全量数据。日历粒度 month 会自动对齐月首,跨时区务必加 time_zone 参数,否则「北京时间凌晨」的数据会落入前一天:

{
  "size": 0,
  "query": { "range": { "@timestamp": { "gte": "now-1h" } } },
  "aggs": {
    "by_minute": {
      "date_histogram": {
        "field": "@timestamp",
        "fixed_interval": "1m",
        "time_zone": "+08:00"
      }
    }
  }
}

5.3 同比环比

同比环比用两个过滤桶分别统计当前区间与上个周期,交给应用计算增长率;或在应用侧对 date_histogram 结果做错位相减,避免一次请求塞入过多桶。

6. 预测与异常检测

一句话总结: 机器学习插件对时序做单变量异常检测,围绕季节性基线识别偏离点,配合告警完成主动运维。

6.1 单变量异常检测

Elastic ML 的单变量异常检测按时间序列建立基线,识别突发尖峰、下跌与周期性异常,无需标注样本。创建任务只需指定数据流与时间字段,ES 自动分桶统计:

PUT _ml/anomaly_detectors/metrics-cpu
{
  "analysis_config": {
    "bucket_span": "15m",
    "detectors": [ { "function": "mean", "field_name": "cpu", "partition_field_name": "host" } ]
  },
  "datafeed_config": {
    "indices": ["metrics-*"],
    "query": { "bool": { "filter": [ { "range": { "@timestamp": { "gte": "now-30d" } } } ] } }
  }
}

6.2 预测与基线

检测结果给出 anomaly_score 与影响度,score 超过阈值即可触发告警。周期性指标可叠加 forecast 对未来 24h 预测,把预测值与实际值对比,实现容量预警。

6.3 告警接入

用 Watcher 或 alerting 插件监听异常分,命中阈值发邮件或 webhook:

PUT _watcher/watch/cpu-anomaly
{
  "trigger": { "schedule": { "interval": "5m" } },
  "input": { "search": { "request": { "indices": [".ml-anomalies-*"], "body": { "size": 5, "query": { "bool": { "filter": [ { "range": { "anomaly_score": { "gte": 80 } } } ] } } } } } },
  "actions": { "webhook": { "webhook": { "method": "post", "host": "alert.example.com", "port": 443, "path": "/notify" } } }
}

7. 查询性能

一句话总结: 时序查询性能由时间过滤、维度预筛与索引排序决定,优先用路由与检索而非全量扫描。

7.1 时间范围永远前置

时序查询务必带时间 range 过滤,让 ES 只扫描相关段与分片。缺少时间条件的跨月查询会扫描全部后备索引,耗时与成本陡增,应在客户端强制要求时间范围参数。

7.2 利用维度路由

TSDB 的 routing_path 维度可做索引级裁剪:查询指定 host 或 region 时,ES 只扫描对应分区,多租户场景尤其有效。维度值枚举量要收敛,基数是 TSDB 存储与查询性能的核心变量。

7.3 聚合裁剪

时序聚合用 min_doc_count 补空桶会使结果膨胀,跨大时间窗慎用;terms 桶 size 够用即止。可把高频指标的常用分位数预聚合进采样索引,查询端直接读聚合值而非重算:

{
  "size": 0,
  "aggs": {
    "daily_p95": {
      "date_histogram": { "field": "@timestamp", "calendar_interval": "day" },
      "aggs": { "p95_cpu": { "max": { "field": "p95_cpu" } } }
    }
  }
}

8. 总结

环节要点
数据流滚动索引 + 单一写入口,模板定义后备索引
生命周期ILM 热温冷冻删五阶段自动流转
TSDB维度稀疏存储 + 按维度排序,压缩与扫描双赢
采样降维date_histogram 聚合降频,双轨存储
时序聚合时间主轴 + 维度分组 + 时区对齐
预测异常ML 单变量检测 + forecast 基线 + 告警
查询性能时间前置、维度路由、聚合裁剪

时序数据是 Elasticsearch 规模最大的场景之一,治理思路清晰:数据流管写入,ILM 管生命周期,TSDB 压存储,采样管长期,聚合管分析,ML 管异常。把「原始明细短期、汇总采样长期」的双轨模型落地,时序库就能在成本与查询速度间取得平衡。数据流的写入链路可阅读《ELK 日志分析体系》,聚合语法见《聚合分析》,索引设计参考《数据建模与 Mapping 设计》。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「elasticsearch」更多文章

  1. 可搜索快照与冻结层:把冷数据放进对象存储还能查
  2. 分页与深度分页:from/size、search_after、PIT 与 scroll
  3. 嵌套与父子关联查询:nested、join 字段与性能取舍