ES索引切分方案3:数据流实现自动化管理(适合日志归档场景,少更新情况)

文章目录

前言

博主介绍:✌目前全网粉丝4W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。

涵盖技术内容:Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。

博主所有博客文件目录索引:博客目录索引(持续更新)

CSDN搜索:长路

视频平台:b站-Coder长路

背景

基于当前的配置(index_patterns, rollover_alias)【前面一篇时序数据自动化管理】已经非常接近数据流的配置模式。如果未来您的系统需要扩展,同样也可以考虑迁移到数据流,能简化管理并利用更多 ES 8 的新特性。

核心需求点

  1. 数据不能删除:需要永久保存。
  2. 每个主分片大小控制在 30GB:为了性能和管理均衡。

(数据不删除、全局查询、性能均衡)和硬件环境(3节点,每年1000万文档增长),设计一个从初始部署到未来扩展的完整方案。

数据流介绍

官方文档:https://www.elastic.co/docs/manage-data/data-store/data-streams

数据流(Data Stream)在 ES8 中是一组隐藏且自动生成的后备索引的抽象,对外暴露为单一命名资源。它满足以下特征:

  • 时间戳驱动 :每个文档必须含 **@timestamp** 字段
  • 仅追加写入:默认禁止更新/删除,保证顺序写性能
  • 自动滚动:通过 ILM 或手动 rollover 生成新写入索引

官方建议:当数据极少更新持续增长时,优先使用数据流。

适合场景

数据流不适合频繁更新的场景。直接在数据流上进行频繁更新会带来严重的性能问题和管理复杂性。

数据流的设计哲学是 "Append-Only"(仅追加),它为时序数据(如日志、指标、事件)而生,这类数据一旦写入就几乎不会改变。

当您在 Elasticsearch 中执行"更新"操作时,它内部执行的是 "删除旧文档 + 插入新文档"。在数据流上频繁这样做,会产生以下问题:

  1. 性能急剧下降
    • 产生大量小段:每次"删除+插入"都会创建新的 Lucene 段文件。频繁更新会导致一个索引中产生海量的、未合并的小段。
    • 查询变慢:查询时需要扫描所有这些段,导致查询性能严重下降。
    • 合并压力巨大:ES 的后台合并进程会疯狂工作,试图合并这些小段,这会消耗大量的 CPU 和 I/O,进一步影响整个集群的稳定性。
  1. 生命周期管理(ILM)混乱
    • Warm/Cold 阶段的只读冲突 :当索引进入 warmcold 阶段,ILM 通常会将其设置为只读(例如,通过 allocate 操作)。此时,如果您尝试更新这个索引中的文档,更新会失败
    • 强制回退 :即使配置允许写入,对一个处于 warm 阶段的索引进行更新,也可能会触发 ILM 将其强制移回 hot 阶段,这完全打乱了您设计的成本优化和性能分层架构。
  1. 存储空间浪费:在后台合并完成之前,旧版本的文档和新版本的文档会同时占用磁盘空间。

数据增长与容量分析

  • 年增长:1000万条记录。
  • 单条记录估算 :假设一个非结构化文档(如PDF、Word)包含元数据(1KB)和部分或全部文本内容(平均19KB),单条记录在ES中(包含**_source**和索引)大小约为 20KB
  • 年数据量:10,000,000 条 * 20 KB/条 = 200 GB (原始数据)
  • ES存储开销 :考虑到索引、副本(1个副本)、操作系统开销等,实际存储需求大约是原始数据的 2-3倍
  • 年存储需求 :200 GB * 2.5 = 500 GB/年

结论 :您当前3节点 * 1TB/节点 = 3TB 的总存储空间,在不做任何优化的情况下,大约可以支撑 5-6年 的数据增长。但考虑到性能和扩展,我们不能等到空间用尽才行动。

第一阶段

目标:立即部署一个高性能、稳定、易于管理的系统,满足当前业务需求,并为未来扩展打下良好基础。

步骤 1: 创建"Hot-Only"的 ILM 策略

"全局查询"需求,我们暂时放弃warm/cold阶段,确保所有数据都在高性能节点上,以获得最快、最稳定的查询响应。

  • 初步测试场景使用1gb一个分片
json 复制代码
PUT /_ilm/policy/file_document_lifecycle_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "1gb", // 🎯 核心参数:整个索引达到30GB时滚动
            // "max_age": "90d"    // 保险策略:即使数据量少,90天也滚动一次,防止索引过大
          }
        }
      }
      // 🎯 注意:没有 warm, cold, delete 阶段,数据永久保留在 hot 节点
    }
  }
}

步骤 2: 创建数据流索引模板

这个模板将数据流、ILM策略和您的数据结构绑定。

java 复制代码
PUT /_index_template/file_document_template
{
  "index_patterns": ["file-documents"], // 🎯 数据流名称,建议用复数
  "data_stream": { },                   // 🎯 声明为数据流模板
  "template": {
    "settings": {
      "number_of_shards": 1,            // 🎯 核心:1个主分片,确保每个索引约30GB
      "number_of_replicas": 1,          // 🎯 1个副本,保证数据高可用
      "index.lifecycle.name": "file_document_lifecycle_policy", // 🎯 关联策略
      "refresh_interval": "1s",
      "analysis": {
        "analyzer": {
          "path_analyzer": {
            "type": "custom",
            "tokenizer": "path_tokenizer"
          }
        },
        "tokenizer": {
          "path_tokenizer": {
            "type": "path_hierarchy"
          }
        }
      }
    },
    "mappings": {
      "properties": {
        "id": {
          "type": "keyword"
        },
        "fileName": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            },
            "raw": {
              "type": "text",
              "analyzer": "standard"
            }
          }
        },
        "fileContent": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        },
        "fileType": {
          "type": "keyword"
        },
        "filePath": {
          "type": "text",
          "analyzer": "path_analyzer",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "fileSize": {
          "type": "float"
        },
        "createUserId": {
          "type": "keyword"
        },
        "catalogStatus": {
          "type": "integer"
        },
        "tags": {
          "type": "keyword",
          "fields": {
            "text": {
              "type": "text",
              "analyzer": "ik_smart"
            }
          }
        },
        "catalogNames": {
          "type": "keyword",
          "fields": {
            "text": {
              "type": "text",
              "analyzer": "ik_smart"
            }
          }
        },
        "catalogFields": {
          "type": "keyword",
          "fields": {
            "text": {
              "type": "text",
              "analyzer": "ik_smart"
            }
          }
        },
        "catalogFieldValues": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "tagIds": {
          "type": "long"
        },
        "catalogIds": {
          "type": "long"
        },
        "updateTime": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
        },
        "createTime": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
        },
        "yearMonth": {
          "type": "date",
          "format": "yyyy-MM"
        }
      }
    }
  },
  "priority": 500 // 设置高优先级,确保覆盖默认模板
}

步骤 3: 创建数据流 & 使用

创建数据流:

sql 复制代码
PUT /_data_stream/file-documents

写入数据示范:

json 复制代码
POST /file-documents/_doc
{
  "id": "doc-001",
  "fileName": "项目规划书.docx",
  "createTime": "2023-10-27 10:00:00",
  "@timestamp": "2023-10-27T10:00:00.000Z"
}

注意写入数据还需要带有timestamp属性值

查询数据:

json 复制代码
GET /file-documents/_search
{
  "query": { "match_all": {} }
}

查询索引值:

shell 复制代码
GET /_cat/indices/file-documents

删除策略

shell 复制代码
# 删除索引模板
DELETE /_index_template/file_document_template

# 查询索引
GET /_cat/indices/file-documents

# 删除索引
# 先查看再删除(推荐)
GET /_data_stream/file-documents
# 确认无误后执行删除
DELETE /_data_stream/file-documents

# 删除策略
DELETE /_ilm/policy/file_document_lifecycle_policy

后续的一些策略

阶段 核心任务 架构特点 何时执行
第一阶段 (当前) 部署高性能、简单的归档系统 数据流 + Hot-Only ILM 立即执行
第二阶段 (扩展) 角色分离,扩展热节点 Master节点 + 专用Data节点 当热数据存储告急时
第三阶段 (优化) 引入温节点,实现分层存储 Hot节点 + Warm节点,ILM自动迁移 当存储成本成为主要矛盾时
步骤 1: 规划节点角色(为扩展做准备)

当前您的3个节点是"全能型"节点(兼具Master、Data、Ingest等角色)。扩展的第一步是角色分离

  • Master-eligible节点:负责集群状态管理,对CPU和内存要求高,对磁盘要求低。建议3台专用(利用现有机器)。
  • Data节点:负责数据存储和查询,对磁盘和内存要求高。
  • Coordinating-only节点(可选):负责接收请求、路由和聚合,对CPU和网络要求高。
步骤 2: 扩展热数据节点

当您的热数据(近期查询频繁的数据)总量接近当前SSD存储的70%时,开始扩展。

  1. 新增节点:购买新的、配置较高的机器(如更大的SSD),加入集群。
  2. 配置角色 :将新节点的 **elasticsearch.yml** 配置为纯数据节点。yaml自动换行折叠复制
shell 复制代码
node.roles: [ data, data_hot, ingest ]
  1. 数据迁移:Elasticsearch 会自动在新的数据节点上均衡分片,无需手动干预。

资料获取

大家点赞、收藏、关注、评论啦~

精彩专栏推荐订阅:在下方专栏👇🏻

更多博客与资料可查看👇🏻获取联系方式👇🏻,🍅文末获取开发资源及更多资源博客获取🍅