3. 日志存储与索引:Elasticsearch 集群搭建、索引生命周期管理、分片与副本策略、冷热数据分层存储
日志存进来,怎么存得稳、查得快,是审计日志分析绕不开的核心问题。我见过不少团队,日志一股脑全塞进 ES,结果集群一个月就撑爆了。说白了,存储和索引不是「能存就行」,而是得从一开始就规划好。
这一章,我们聚焦四个实战点:集群怎么搭、索引怎么管生命周期、分片副本怎么配、冷热数据怎么分层。嗯,都是我在生产环境里踩过坑之后总结出来的。
3.1 Elasticsearch 集群搭建:别小看基础配置
搭建 ES 集群,很多人觉得就是装个包、改个配置文件。其实不然。我刚开始带团队时,就因为在 elasticsearch.yml 里漏了 discovery.seed_hosts,结果节点互相找不到,折腾了一下午。
这里给出一份我常用的最小化生产配置(3 节点集群示例):
# elasticsearch.yml - 节点 1
cluster.name: audit-logs-prod
node.name: node-1
path.data: /data/elasticsearch/data
path.logs: /data/elasticsearch/logs
network.host: 192.168.1.10
http.port: 9200
transport.port: 9300
discovery.seed_hosts: ["192.168.1.10:9300", "192.168.1.11:9300", "192.168.1.12:9300"]
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
gateway.recover_after_nodes: 2
action.destructive_requires_name: true
action.destructive_requires_name 设为 true。否则一个 DELETE * 就能让你哭。我曾经在测试环境手滑过,嗯,就一次。
节点角色分配也很关键。我建议这样分:
| 节点角色 | 职责 | 推荐配置 |
|---|---|---|
| Master | 集群元数据管理、节点心跳 | 3 台,4C8G,SSD |
| Data | 数据存储、查询、聚合 | 按需扩展,16C64G+,SSD |
| Ingest | 数据预处理管道 | 2 台,8C16G |
| Coordinating | 请求分发、结果合并 | 2 台,8C16G |
你想想看,如果让一个节点既当 master 又扛大量写入,集群稳定性就会打折扣。我见过一个案例,就是因为 master 节点压力过大导致脑裂,日志丢了整整 2 小时。
3.2 索引生命周期管理:让日志自动「退休」
审计日志有个特点:越老的日志查得越少。如果所有索引都保持同样的副本数和分片数,存储成本会直线上升。索引生命周期管理(ILM)就是解决这个问题的。
ILM 有四个阶段:Hot → Warm → Cold → Delete。我一般这样配置:
PUT _ilm/policy/audit_logs_policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "1d"
},
"set_priority": {
"priority": 100
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"allocate": {
"require": {
"data_tier": "warm"
}
},
"forcemerge": {
"max_num_segments": 1
},
"shrink": {
"number_of_shards": 1
},
"set_priority": {
"priority": 50
}
}
},
"cold": {
"min_age": "30d",
"actions": {
"allocate": {
"require": {
"data_tier": "cold"
}
},
"freeze": {},
"set_priority": {
"priority": 0
}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}
为什么 warm 阶段要 shrink 到 1 个分片?因为老索引查询频率低,不需要那么多分片并行。我曾在项目中做过测试,shrink 后查询性能几乎没下降,但磁盘占用少了将近一半。
3.3 分片与副本策略:多一分则肥,少一分则瘦
分片和副本,是 ES 性能调优的重头戏。很多人上来就设 10 个分片、2 个副本,结果集群负载不均。我个人的经验是:
- 分片数 = (数据总量 / 每个分片期望大小) × 节点数因子
- 每个分片大小:建议 20GB ~ 50GB
- 副本数:生产环境至少 1,关键数据 2
举个例子:每天产生 500GB 审计日志,保留 7 天热数据。总数据量 3.5TB。按每个分片 40GB 算,大约需要 90 个分片。如果集群有 6 个数据节点,每个节点分 15 个分片,压力比较均衡。
cluster.max_shards_per_node: 50。
副本策略也有讲究。写入密集的场景,副本数不宜过多,否则写入放大效应明显。我一般这样权衡:
| 场景 | 副本数 | 说明 |
|---|---|---|
| 热数据(写入频繁) | 1 | 保证高可用,同时控制写入开销 |
| 温数据(查询为主) | 1 | 查询负载均衡,节省存储 |
| 冷数据(极少查询) | 0 | 只保留一份,用快照备份 |
| 关键审计数据 | 2 | 防止节点故障导致数据丢失 |
3.4 冷热数据分层存储:把钱花在刀刃上
审计日志的访问模式很规律:最近 7 天的日志查得最多,30 天前的几乎没人看。如果所有数据都用 SSD 存,成本太高。冷热分层就是让热数据跑在 SSD 上,冷数据放在 HDD 或对象存储里。
实现方式很简单:给节点打标签。
# 热节点 elasticsearch.yml
node.attr.data_tier: hot
# 温节点 elasticsearch.yml
node.attr.data_tier: warm
# 冷节点 elasticsearch.yml
node.attr.data_tier: cold
然后在 ILM 策略里,通过 allocate action 指定数据迁移到对应层级的节点。前面 ILM 配置里已经展示了这部分。
这里我画了一张流程图,帮你理清整个数据流转:
这套架构我在一个日处理 2TB 日志的项目里跑了一年多,存储成本降低了 70%,查询热数据依然在 200ms 以内。嗯,效果很理想。
最后提一句,分片和副本策略不是一成不变的。我建议每季度 review 一次集群的健康状况,根据实际写入量和查询模式做调整。别怕改,ES 支持动态调整大部分参数。