索引管理:给HSM日志安个家

说实话,很多人在Kibana里折腾可视化,第一步就卡在索引管理上。数据倒进去了,查不到,或者查得慢,十有八九是索引没管好。HSM审计日志这个场景尤其典型——数据量大、写入频率高、还得长期保存。我今天就把索引管理的四个核心动作掰开讲清楚。

创建索引:不只是PUT一下

创建索引最简单的方式,确实就是发个PUT请求。但我建议你养成一个习惯:创建时就把配置写清楚。

PUT /hsm-audit-logs-2025-01
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}

这里面有两个关键参数:shards和replicas。我遇到过有人把分片数设成20,觉得越大越快。其实分片越多,管理开销越大。HSM日志这种场景,每天一个索引,3个主分片完全够用。副本数设1,保证高可用就行。

我个人的习惯:日志类数据我会提前创建好索引模板,而不是手动一个一个PUT。后面讲数据流的时候会详细说。

索引映射:字段类型决定一切

映射(mapping)定义了字段的类型和属性。映射设错了,查询结果就全歪了。

我曾经踩过一个坑:审计日志里有个event_time字段,没指定类型,Elasticsearch自动识别成了text。结果Kibana时间筛选器死活不认,查个时间段的数据都得手动写范围查询。后来我强制指定为date类型,问题秒解。

PUT /hsm-audit-logs-2025-01/_mapping
{
  "properties": {
    "event_time": {
      "type": "date",
      "format": "yyyy-MM-dd HH:mm:ss"
    },
    "user_id": {
      "type": "keyword"
    },
    "operation": {
      "type": "keyword"
    },
    "key_id": {
      "type": "keyword"
    },
    "status": {
      "type": "keyword"
    },
    "message": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    }
  }
}

注意看上面的映射:user_id、operation这些字段我全用keyword。为什么?因为这些字段用于聚合查询、分组统计,text会先分词再聚合,结果完全不对。说白了,精确匹配用keyword,全文搜索用text。

字段 推荐类型 原因
event_time date 时间序列分析、范围筛选
user_id, operation, key_id keyword 精确匹配、聚合统计
message, details text + keyword子字段 既支持全文搜索,也支持精确聚合
ip_address, hostname ip, keyword IP范围查询用ip,分组统计用keyword
注意:映射一旦创建,某些类型的字段就不能改了。比如keyword改成text没问题,但text改成keyword需要重建索引。所以提前规划好映射是索引管理的第一课。

索引生命周期管理:让数据自己动起来

HSM审计日志不能一直堆在一个索引里。时间一长,查询慢、存储贵。索引生命周期管理(ILM)就是用来解决这个问题的。

ILM把数据分为四个阶段:

  • Hot阶段:频繁写入和查询的数据。用SSD盘,分片分配优化写入性能。
  • Warm阶段:不再写入,偶尔查询。可以降低副本数,挪到HDD。
  • Cold阶段:很少查询。可以合并分片,甚至只保留一份数据。
  • Delete阶段:超过保存期限,直接删掉。
PUT _ilm/policy/hsm_audit_log_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "7d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "30d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "set_priority": {
            "priority": 50
          },
          "allocate": {
            "require": {
              "data_type": "warm"
            }
          }
        }
      },
      "cold": {
        "min_age": "90d",
        "actions": {
          "freeze": {},
          "set_priority": {
            "priority": 0
          },
          "allocate": {
            "require": {
              "data_type": "cold"
            }
          }
        }
      },
      "delete": {
        "min_age": "365d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

这里有个关键点:rollover。它会在索引达到50GB或7天时自动创建一个新索引。我有个项目就是没配这个,一个索引写了200GB,查询直接超时。

你想想看,有了ILM,你只需要操心业务逻辑。数据什么时候挪、什么时候删,交给策略去执行。这才是工程化的做法。

经验之谈:ilM不只是一套规则,它背后是集群资源的高效利用。Hot节点用SSD,Warm用HDD,Cold用对象存储,每GB成本能差出10倍。

数据流:日志写入的标准化姿势

数据流(Data Stream)是ELK 7.x之后推荐的方式。它的背后是一组按时间滚动的隐藏索引,你用数据流名就能读取到所有数据。

为什么要用数据流?

  • 自动滚动:不需要手动创建索引,达到容量或时间阈值自动新建。
  • 统一别名:对用户透明,写入和查询都指向同一个名字。
  • 和ILM无缝集成:一个策略挂上去,全自动管理。
PUT _index_template/hsm_audit_log_template
{
  "index_patterns": ["hsm-audit-logs-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "hsm_audit_log_policy",
      "index.lifecycle.rollover_alias": "hsm-audit-logs"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "event_time": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"
        },
        "user_id": {
          "type": "keyword"
        },
        "operation": {
          "type": "keyword"
        },
        "key_id": {
          "type": "keyword"
        },
        "status": {
          "type": "keyword"
        },
        "message": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  },
  "priority": 200
}

看到没?我把映射、ILM策略、滚动别名全写在一个模板里。以后写入数据,只需要往 hsm-audit-logs 这个数据流名写,它自动创建索引、自动滚动、自动迁移。

嗯,这里要注意:索引模板中的priority越高,匹配优先级越高。我建议你给HSM日志专门的模板设一个高优先级,避免被其他通用模板覆盖掉。

避坑提醒:数据流要求写入的文档必须包含@timestamp字段,否则会报错。我以前调试时没注意这个,日志全写丢了,排查了好久才发现是少了这个字段。

一张图看懂索引管理全流程

我把上面四个步骤串成了一张流程图。你看看数据从写入到删除,是怎么流转的。

HSM审计日志索引管理全流程 HSM审计日志数据源 索引模板 + ILM策略 + 映射定义 Data Stream(数据流) 写入(滚动索引) ILM:Hot → Warm → Cold → Delete 查询(统一数据流名) 所有管理操作对用户透明,只需往数据流写入/查询

这张图的核心逻辑就是:一次定义,全自动运转。数据源头进来,模板负责定义结构,ILM负责管理生命周期,数据流负责对外统一接口。你只需要关心业务,不用再操心索引翻来覆去的手动操作。

以上就是索引管理的核心内容。从创建索引到定义映射,从ILM策略到数据流,每一步都直接影响Kibana的查询性能和存储成本。我个人建议,新项目直接上数据流+ILM,老项目逐步迁移。这是最稳妥的路径。