Skip to content

时序数据建模 ​

1. 时序数据特点 ​

时序数据(Time Series Data)是按时间顺序产生的数据,如日志、监控指标、IoT 数据等。

特点说明
写入密集持续高频写入
时间有序数据按时间戳排列
查询模式固定通常按时间范围查询
数据老化近期数据查询频繁,历史数据逐渐变冷

2. 索引策略 ​

本文示例基于 Elasticsearch 8.x 及之后版本。时序数据在 ES 中有不同建模方式,应先判断数据形态再选型。

日志、事件及一般带时间戳的数据,按写入模式、查询方式和保留周期,选择普通索引加别名加 ILM,或 Data Stream。

持续写入、以时间戳和一组维度标识的指标数据,评估 Time Series Data Stream(TSDS)。TSDS 通过维度字段与指标字段优化存储和查询,与普通索引不是同一模型。

需要自定义 _id 或频繁覆盖更新的数据,评估普通索引或带写索引的别名更合适。

2.1 按时间滚动索引 ​

json
// 索引模板
PUT /_index_template/logs-template
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs-policy",
      "index.lifecycle.rollover_alias": "logs",
      "index.codec": "best_compression",
      "index.sort.field": ["@timestamp"],
      "index.sort.order": ["desc"]
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" },
        "service": { "type": "keyword" }
      }
    }
  }
}

// 创建初始索引
PUT /logs-000001
{
  "aliases": {
    "logs": { "is_write_index": true }
  }
}

2.2 ILM 策略(Index Lifecycle Management) ​

json
PUT /_ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "1d",
            "max_docs": 100000000
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "3d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "set_priority": { "priority": 0 }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

cold 阶段只保留 set_priority。数据层迁移由 ILM 自动完成,进入 warm 或 cold 阶段时,ILM 自动调整索引的 _tier_preference,把索引分配到 data_warm 或 data_cold 节点。实际能否迁移到目标层,还取决于集群是否存在符合要求的节点以及分片分配是否成功。set_priority 仅调整分片恢复优先级,不是迁移动作。

3. 冷热架构 ​

json
// Hot 节点配置(SSD,高性能)
node.roles: [data_hot, data_content]

// Warm 节点配置(HDD,大容量)
node.roles: [data_warm]

// Cold 节点配置(低成本存储)
node.roles: [data_cold]
txt
Hot(SSD)  →  Warm(HDD)  →  Cold(归档)  →  Delete
  0~3天         3~30天         30~90天          >90天

4. 数据压缩与优化 ​

index.codec 与 index.sort.* 都是索引设置,其中 index.sort.* 是静态设置,只能在创建索引或通过索引模板配置,无法对已存在的索引直接修改。这两项已合并进第 2.1 节的索引模板。

已存在的索引无法通过修改上述静态设置启用索引排序,确有需要时应新建索引并通过 reindex 迁移数据。

优化手段效果
best_compression以更高压缩率的编码方式降低存储占用,但读取 stored fields 的延迟可能增加,实际收益取决于数据特征与查询负载,应基于代表性数据对比测试
index.sort可能改善按时间范围查询的执行效率,实际收益取决于查询模式、数据分布与段结构
forcemerge减少 Segment 数量,提升查询性能
只读索引不需要写入的索引可设为只读

5. 查询时序数据 ​

json
GET /logs-*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "@timestamp": {
              "gte": "now-1h",
              "lte": "now"
            }
          }
        },
        {
          "term": { "level": "ERROR" }
        }
      ]
    }
  },
  "sort": [{ "@timestamp": "desc" }],
  "size": 100
}

6. 最佳实践 ​

  • 使用索引别名 + ILM 策略自动化管理索引生命周期
  • Hot/Warm/Cold 架构按数据温度分层存储
  • 以存储成本为主、查询延迟要求宽松的索引,评估 best_compression,用代表性数据测试存储收益与读取开销
  • 索引按时间滚动,避免单个索引过大
  • 对已停止写入、确定不再更新的索引,评估收益后执行 forcemerge
  • 以时间范围查询为主的索引,评估按 @timestamp 排序的收益,并在创建索引前通过代表性数据测试
  • 监控索引增长速度,提前规划存储容量

Released under the MIT License.