指标监控、设备遥测、访问日志构成了典型的时序数据:随时间追加、按时间查询、老数据价值递减。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 设计》。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。