Elasticsearch 日志索引设计:按小时切分 + 小时内 Rollover 兜底(ILM 实战,附完整脚本)

Elasticsearch 日志索引设计:按小时切分 + 小时内 Rollover 兜底(ILM 实战,附完整脚本)

日志场景下 Elasticsearch 索引怎么切?按天建索引,大流量日单索引轻松突破几百 GB,merge 变慢、查询抖动;只靠 ILM 按大小 rollover,索引边界又和业务时间对不上,排障时想拉某个小时的日志都费劲。本文给出一套外层按整点小时切分 + 内层 Rollover 兜底的双层别名方案,ILM 策略、索引模板、cron 脚本、应用层写入路由全部可复制。

一、为什么日志索引推荐按小时切分

先看两种常见做法的坑:

做法 问题
单一大索引(按月/永久) 索引无限膨胀,segment merge 停不下来,删除只能 delete_by_query,集群越用越慢
按天切分 常规流量没问题,但高峰日单索引可到几百 GB;排查问题想精确定位某小时,仍要在巨型索引里扫
只用 ILM rollover 索引边界由数据量决定,与时间无关,对账、归档、按时间段删除都不方便

日志数据有强时间特征:排查看小时、对账按小时、归档删过期也按时间。所以理想方案是索引边界严格对齐整点小时,同时在单小时数据突增时还能自动拆分------这就是双层设计。

二、方案总览:双层别名架构

  • 外层(小时级):每整点由 cron 新建一个独立索引,名字带小时戳
  • 内层(rollover 级):同一小时内数据量超阈值时自动 rollover 出新物理索引
  • 双层 alias:外层别名按小时命名,承载写入和查询;内层 rollover 由 ILM 维护
text 复制代码
logs-2026061114-000001 ─┐
logs-2026061114-000002 ─┼─ alias: logs-2026061114 (is_write_index: 当前可写)
logs-2026061115-000001 ──── alias: logs-2026061115 (is_write_index: 当前可写)

应用层只认 logs-YYYYMMDDHH 这个小时级别名,rollover 发生时别名自动切换,写入方零改动

需要的资源一共 5 项:

资源类型 名称 数量 作用
ILM Policy logs-policy 1 份 全集群共用,管 rollover 和过期删除
Index Template logs-template 1 份 自动应用 mappings + settings
Cron 脚本 create_hourly_index.sh 1 个 每整点执行
外层 Alias logs-YYYYMMDDHH 每小时 1 个 写入与查询入口
内层 Alias 索引名即别名 每物理索引 1 个 rollover 维护

三、部署步骤

3.1 创建 ILM 策略(全集群一份)

bash 复制代码
PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "20gb",
            "max_docs": 100000000
          }
        }
      },
      "warm": {
        "min_age": "3d",
        "actions": {
          "forcemerge": { "max_num_segments": 1 }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": { "delete": {} }
      }
    }
  }
}

阶段说明:

  • hot:可写阶段,单索引到 20GB 或 1 亿文档即 rollover,防止索引过大
  • warm:3 天后强制段合并为 1 段,省存储、提查询
  • delete:30 天后自动删除

⚠️ 不要配 max_age 。整点切索引已经承担了时间维度的切分,ILM 里再配 max_age 会和小时边界冲突,出现"不到整点就滚"的脏边界。

3.2 创建索引模板

bash 复制代码
PUT _index_template/logs-template
{
  "index_patterns": ["logs-*"],
  "priority": 100,
  "template": {
    "settings": {
      "number_of_shards": 10,
      "number_of_replicas": 1
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "level":      { "type": "keyword" },
        "message":    { "type": "text" },
        "service":    { "type": "keyword" },
        "host":       { "type": "keyword" }
      }
    }
  }
}

注:mappings 按实际日志字段补充。ILM 绑定和 rollover_alias 不要 写在模板里,留到每小时的种子索引上单独指定,避免污染所有 logs-* 索引。

3.3 Cron 脚本:每整点创建种子索引

脚本路径 /opt/scripts/create_hourly_index.sh

bash 复制代码
#!/bin/bash
set -euo pipefail

ES_HOST="${ES_HOST:-http://es-host:9200}"
HOUR=$(date -u +%Y%m%d%H)
INDEX="logs-${HOUR}-000001"
ALIAS="logs-${HOUR}"

# 幂等检查:索引已存在则跳过
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -u "${ES_USER}:${ES_PASS}" \
  -X HEAD "${ES_HOST}/${INDEX}")

if [ "$STATUS" = "200" ]; then
  echo "[$(date)] Index ${INDEX} already exists, skip."
  exit 0
fi

if [ "$STATUS" != "404" ]; then
  echo "[$(date)] Unexpected status ${STATUS} for ${INDEX}, abort."
  exit 1
fi

# 创建种子索引,同时挂外层 alias 和 ILM 配置
RESP=$(curl -s -u "${ES_USER}:${ES_PASS}" \
  -X PUT "${ES_HOST}/${INDEX}" \
  -H 'Content-Type: application/json' \
  -d "{
    \"aliases\": {
      \"${ALIAS}\": { \"is_write_index\": true }
    },
    \"settings\": {
      \"index.lifecycle.name\": \"logs-policy\",
      \"index.lifecycle.rollover_alias\": \"${ALIAS}\"
    }
  }")

echo "[$(date)] Create ${INDEX} alias ${ALIAS}: ${RESP}"

crontab 配置:

bash 复制代码
# 每小时 0 分 5 秒执行(避开整点集群压力尖峰)
5 * * * * /opt/scripts/create_hourly_index.sh >> /var/log/es-hourly-index.log 2>&1

两个细节:脚本里 date -u 用 UTC,全链路统一时区;crontab 建议主备双机部署,防止单点漏建。

四、应用层接入

4.1 写入路由:按当前小时选别名

Java 示例:

java 复制代码
String hour = ZonedDateTime.now(ZoneOffset.UTC)
    .format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
String alias = "logs-" + hour;

IndexRequest req = new IndexRequest(alias)
    .source(jsonMap, XContentType.JSON);

Python 示例:

python 复制代码
from datetime import datetime, timezone

def current_alias():
    hour = datetime.now(timezone.utc).strftime("%Y%m%d%H")
    return f"logs-{hour}"

es.index(index=current_alias(), document=log_entry)

4.2 查询姿势

bash 复制代码
# 单小时查询
GET logs-2026061114/_search

# 跨小时:明确列出,别用通配符(展开慢)
GET logs-2026061113,logs-2026061114/_search

# 时间范围查询兜底
GET logs-*/_search
{
  "query": {
    "range": { "@timestamp": { "gte": "now-2h", "lte": "now" } }
  }
}

五、Rollover 行为详解

触发时机:小时内数据满足任一条件自动 rollover------单索引 ≥20GB,或文档数 ≥1 亿。

状态变化

text 复制代码
触发前:
  logs-2026061114-000001 ← 可写 (is_write_index: true)

触发后:
  logs-2026061114-000001 ← 只读
  logs-2026061114-000002 ← 可写 (is_write_index: true)

小时别名 logs-2026061114 自动指向 000002,应用层无感知。

与下个整点的衔接

  • 14:59:59 数据仍写入 logs-2026061114-000002
  • 15:00:05 cron 执行,新建 logs-2026061115-000001
  • 应用层下次写入按当前小时自动切到 logs-2026061115-*

六、验证与日常运维命令

bash 复制代码
# 查看某小时索引的 ILM 进度
GET logs-2026061114/_ilm/explain

# 查看别名当前指向
GET _alias/logs-2026061114

# 列出最近索引的大小与文档数
GET _cat/indices/logs-*?h=index,docs.count,store.size&s=index

测试时手动触发一次 rollover 验证链路:

bash 复制代码
POST logs-2026061114/_rollover
{
  "conditions": { "max_docs": 1 }
}

七、监控告警配置

监控项 阈值 级别
某小时索引缺失 当前时间 +5 分钟该小时索引不存在 Critical
ILM 阶段卡住 phase 5 分钟无变化 Warning
集群分片数 接近 cluster.max_shards_per_node Warning
磁盘使用率 ≥80% Warning

监控建议接 Prometheus + ElastAlert 或自研 watcher,重点盯索引缺失------cron 失败意味着应用写入直接报错。

八、踩坑清单

后果 应对
cron 失败整点索引缺失 应用层写入失败 监控告警 + 应用层降级写 logs-* 通配兜底
单小时数据爆增 索引过大性能劣化 rollover 自动兜底(max_size 20gb)
rollover_alias 配置缺失 ILM 静默不工作 种子索引脚本里强制写入该配置
跨小时查询用 logs-* 通配展开慢 应用层按需拼接具体小时别名
应用节点时区不一致 写错小时索引 全链路统一 UTC

九、部署 Checklist

  • 创建 ILM policy logs-policy
  • 创建 Index template logs-template
  • 部署 create_hourly_index.sh 到独立调度机
  • 配置 crontab(主备双机)
  • 应用层改造写入路由逻辑
  • 配置监控告警(缺失索引、ILM 卡住、磁盘)
  • 测试环境完整跑一次 rollover 验证

十、版本兼容性

ES 版本 支持情况
7.8+ ✅ 推荐,ILM + rollover 稳定
7.0 - 7.7 ⚠️ 部分 API 行为有差异,建议升级
8.x ✅ 兼容本方案全部 API

总结

这套方案的本质是让时间边界和数据量边界各管各的:整点切分满足排障、对账、归档的时间对齐需求,ILM rollover 兜住流量突增,双层别名把两者对应用层透明。全部资源就一份 ILM 策略 + 一份模板 + 一个 cron 脚本,复制文中 DSL 即可落地。

你们的日志索引是按天切、按小时切,还是纯 rollover?有没有遇到过单索引几百 GB 的场面?评论区聊聊你的切法。


文中脚本与 DSL 在 ES 7.17/8.x 环境验证通过,字段映射请按实际业务调整。

相关推荐
龙亘川8 分钟前
科技决策分析报表平台:科技服务・项目・成果转化・政策四维报表全链路业务建模
大数据·科技·ai·信息可视化·智慧城市
四季豆332 小时前
工业大数据不只是“大”,更是制造业突围的“导航仪”
大数据
newsxun2 小时前
光智融合,空间新生|Jupiter SR 亮相光博会CIOE 2026
大数据·人工智能
大树883 小时前
液冷系统的真正瓶颈,藏在那层不到1毫米的材料里
大数据·运维·服务器·人工智能·ai
Vicky_time3 小时前
2026美国海外仓TOP5技术评测:FBA中转海外仓系统对接与操作方案
大数据·系统架构
北京晶数信息科技3 小时前
加油机数据采集设备加油机数据采集器加油机智能采集器液位仪数据采集设备原厂成品油流通数智化综合监管平台技术原理与落地应用解决方案
大数据·人工智能·物联网·需求分析
凌风的跨境分享3 小时前
Temu店群运维提效:定时策略自动化任务全场景实操指南
大数据·运维·前端·人工智能·架构·自动化
Elastic 中国社区官方博客4 小时前
Elasticsearch 向量数据库:几分钟内完成部署,以经济高效的方式扩展至数千亿规模
大数据·运维·数据库·elasticsearch·搜索引擎·ai·全文检索
A hao4 小时前
LED视频处理器中帧率与刷新率的区别
大数据·图像处理·人工智能·音视频
AgentMaster4 小时前
数据治理工具选型指南:一套可复用的四阶段决策框架
大数据·数据结构·人工智能·算法