作者:来自 Elastic Jeffrey Rengifo
了解如何在 Elasticsearch 中启用 LogsDB 索引模式并衡量实际存储节省效果。我们将使用 Apache 日志对比标准索引与 LogsDB 索引,并展示可以节省多少存储空间。
LogsDB 是一种专门的 Elasticsearch 索引模式,它以更低的存储成本提供完整功能。你的 Kibana 仪表板、搜索、告警和可视化都可以像以前一样正常工作,不会丢失任何数据,也不需要修改查询或工作流。只需一个配置,就能让所有东西变得更便宜。
在基准测试中,LogsDB 将一个数据集从 162.7 GB 降低到 39.4 GB —— 减少了 76% 的存储空间。你可以在 elasticsearch-benchmarks.elastic.co 查看完整的夜间基准测试结果。
在本教程中,你将使用 Kibana Dev Tools 和 Apache logs 数据集复现这个实验。你会创建两个完全相同的索引,将相同的数据写入两个索引,并使用 _stats API 测量存储差异。最终你会在测试数据上看到 44% 的存储减少,并理解为什么在生产环境中节省幅度会更高。
如果你已经在使用 Elasticsearch 9.2+,任何以 logs- 开头的数据流默认已经启用了 LogsDB。你可以直接跳到 “What about your existing logs?” 来验证你的配置。
想了解完整背景?关于这些节省背后的工程演进 —— 包括 Lucene doc values、synthetic _source、index sorting 和 ZSTD 是如何在十二年间逐步叠加实现的——可以参考 “Elasticsearch 多年来的发展:LogsDB 如何将索引大小最多降低 75%”。
前提条件
- Elasticsearch 8.17+ 集群、Elastic Cloud 部署或 Serverless
- 具有 Dev Tools 访问权限的 Kibana
- 一些日志数据
- 对在 Kibana Dev Tools 中运行 API 调用有基本了解
LogsDB 如何节省存储
LogsDB 通过叠加三种机制来实现存储压缩:
- 索引排序(Index sorting)——按照 host.name 和 @timestamp 对文档排序,将相似日志行聚集在一起,使压缩算法更容易找到重复模式。单这一项就能带来大约 30% 的节省。
- ZSTD 压缩 + delta/GCD/运行长度编码——best_compression 会从 LZ4 切换到 Zstandard,并对每个 doc values 列应用数值编码。本教程中的标准索引使用的是 LZ4,因此你测量到的差异中,有一部分来自 LogsDB 自动启用的完整优化组合。
- Synthetic _source——Elasticsearch 不再存储原始 JSON blob,而是在需要时通过 doc values 重建 _source,从而额外带来 20–40% 的存储节省。
Synthetic _source 的权衡:返回文档中的字段顺序可能与原始数据不同,并且在多值数组字段的一些边缘情况下行为会有所差异。对于大多数日志分析工作负载,这些差异是不可见的,但在延迟敏感应用中启用前仍需参考 synthetic _source 文档。
关于这些机制背后的架构细节,可以查看 “Elasticsearch 多年来的发展:LogsDB 如何将索引大小最多降低 75%”。
接下来,我们将一步步讲解如何启用 LogsDB 并测量存储节省效果。
步骤 1:使用 Elastic Agent 收集日志
将 Apache 日志导入 Elasticsearch 的推荐方式是通过 Elastic Agent 并使用 Apache 集成。它可以自动处理采集、解析、ECS 字段映射以及路由。
浏览 Elastic integrations 目录中的所有可用集成。
一旦 Elastic Agent 开始收集日志并将其路由到 logs-apache.access-*,就可以进入下一步。
步骤 2:创建两个索引
本教程中的所有命令都在 Kibana Dev Tools 中运行。
创建一个标准索引和一个 LogsDB 索引,两者具有完全相同的字段映射。唯一的区别是 "index.mode": "logsdb"。
标准索引:
`
1. PUT /apache-standard
2. {
3. "mappings": {
4. "properties": {
5. "@timestamp": { "type": "date" },
6. "host.name": { "type": "keyword" },
7. "http.request.method": { "type": "keyword" },
8. "url.path": { "type": "keyword" },
9. "http.version": { "type": "keyword" },
10. "http.response.status_code": { "type": "integer" },
11. "http.response.bytes": { "type": "integer" },
12. "http.request.referrer": { "type": "keyword" },
13. "user_agent.original": { "type": "keyword" }
14. }
15. }
16. }
`AI写代码
LogsDB 索引:
`
1. PUT /apache-standard
2. {
3. "mappings": {
4. "properties": {
5. "@timestamp": { "type": "date" },
6. "host.name": { "type": "keyword" },
7. "http.request.method": { "type": "keyword" },
8. "url.path": { "type": "keyword" },
9. "http.version": { "type": "keyword" },
10. "http.response.status_code": { "type": "integer" },
11. "http.response.bytes": { "type": "integer" },
12. "http.request.referrer": { "type": "keyword" },
13. "user_agent.original": { "type": "keyword" }
14. }
15. }
16. }
`AI写代码
这一行 "index.mode": "logsdb" 会自动启用所有三种存储机制。Elasticsearch 会在后台开启以下额外设置——你无需手动配置任何一项:
`
1. {
2. "index.sort.field": ["host.name", "@timestamp"],
3. "index.sort.order": ["asc", "desc"],
4. "index.codec": "best_compression",
5. "index.mapping.ignore_malformed": true,
6. "index.mapping.ignore_above": 8191
7. }
`AI写代码
步骤 3:重新索引日志
使用 _reindex API 将相同的文档复制到两个测试索引中:
`
1. POST /_reindex
2. {
3. "source": { "index": "logs-apache.access-*" },
4. "dest": { "index": "apache-standard" }
5. }
7. POST /_reindex
8. {
9. "source": { "index": "logs-apache.access-*" },
10. "dest": { "index": "apache-logsdb" }
11. }
`AI写代码
两个索引现在包含完全相同的文档,因此下一步的存储对比只反映索引模式(index mode)的差异。
步骤 4:强制合并以确保公平对比
在测量之前,对两个索引执行 force merge,将其合并为单个 segment:
`
1. POST /apache-standard/_forcemerge?max_num_segments=1
3. POST /apache-logsdb/_forcemerge?max_num_segments=1
`AI写代码
这些请求会阻塞直到合并完成。请等待两个请求都返回后再继续。
为什么这一步很重要:Elasticsearch 在写入数据时会先生成多个 Lucene segment,并在后台逐步合并。如果在合并过程中进行测量,会因为每个 segment 单独压缩而导致存储数据被高估。强制合并为单一 segment 可以展示索引在稳定状态下的真实存储占用,这更接近生产环境中的最终表现。
注意:只有在索引不再写入时才应执行 _forcemerge。对仍在写入的索引执行 force merge 会消耗大量资源,并可能影响 ingestion 性能。在生产环境中,可以通过 Index Lifecycle Management(ILM)在 warm 或 cold 阶段自动执行 force merge,此时索引通常已经 rollover,不再承载写入。
步骤 5:测量差异
`
1. GET /apache-standard/_stats?filter_path=indices.*.primaries.store
3. GET /apache-logsdb/_stats?filter_path=indices.*.primaries.store
`AI写代码
filter_path 参数可以让响应更聚焦。请在每个响应中查看 primaries.store.size_in_bytes。
在我们使用 Apache 日志数据的测试中,结果如下:
| 索引 | 文档数 | 大小 |
|---|---|---|
| apache-standard | 111,818 | 15.37 MB |
| apache-logsdb | 111,818 | 8.6 MB |
| 减少比例 | 44% |
从这个角度来看:在 1 TB 的日志数据下,LogsDB 可以将其压缩到约 560 GB。这意味着在不修改任何查询的情况下节省了 450 GB。在生产规模(数十亿文档并启用 synthetic _source)下,节省比例可达到 76%——在我们的基准测试中,从 162.7 GB 降低到 39.4 GB。
在 Kibana 中可视化
要直观查看存储差异,请打开 Kibana,进入 Management → Stack Management → Index Management。你会看到两个索引并排列出,并显示各自的当前大小。
为什么 Kibana 显示的数值比 _stats 更大:Kibana Index Management 显示的是包含所有 replica shards 在内的索引总大小。而上面的 _stats 查询使用的是 primaries,只报告 primary shards 的大小。无论采用哪种方式,两种索引之间的比例关系是保持一致的。
那你现有的日志呢?
Elasticsearch 9.2+(默认已启用)
从 9.2 开始,任何匹配 logs-* 命名模式的数据流都会自动使用 LogsDB。你很可能已经在没有任何配置改动的情况下节省了存储空间。
验证你现有的数据流:
`GET /.ds-logs-*/_settings?filter_path=*.settings.index.mode` AI写代码
如果你在响应中看到 "index.mode": "logsdb",说明你已经在享受存储节省了。
Elasticsearch 8.x 或 9.0–9.1(通过 index template 为每个 data stream 启用)
在较早版本中,需要通过更新 index template 来为 data stream 启用 LogsDB。此配置会影响所有由该模板创建的新索引——已有索引不会被修改,因此迁移是安全且渐进的。
选项 A —— 更新现有模板:
`
1. PUT _index_template/logs-myapp-template
2. {
3. "index_patterns": ["logs-myapp-*"],
4. "data_stream": {},
5. "template": {
6. "settings": {
7. "index.mode": "logsdb"
8. }
9. },
10. "priority": 200
11. }
`AI写代码
选项 B —— 检查并修补现有的集成模板:
首先,找到管理你数据流的模板:
`GET _index_template/logs-apache*` AI写代码
然后在 template.settings 代码块中添加 index.mode 设置,使用 PUT _index_template/ 调用,并包含完整的模板 body(包括你新增的配置)。
更新模板之后,下一个 rollover 生成的索引就会使用 LogsDB。如果你不想等待,可以立即触发一次 rollover:
`POST /logs-myapp-default/_rollover` AI写代码
从 8.x 升级到 9.0+:现有的数据流不会被自动修改。只有新的 rollover 才会使用 LogsDB。不需要重新索引,也不会有数据丢失——随着新的索引逐步滚动生成,节省效果会逐渐累积。
查询性能怎么样?
LogsDB 对于典型日志分析工作负载来说,不会对查询性能产生显著影响。由于按照 host.name 和 @timestamp 进行索引排序,这在某些情况下反而能提升 range 查询和聚合性能,因为匹配的数据会在磁盘上更紧密地存放在一起。对于不依赖这些字段过滤的查询,其性能与标准索引基本一致。
关于跨版本的索引写入吞吐性能数据,可以参考配套文章中的 performance 部分。
结论
LogsDB 只需一个 "index.mode": "logsdb" 配置即可启用,并立即带来可观的存储节省:在我们的实测中减少 44%,在生产基准测试中(启用 synthetic _source)可达 76%(162.7 GB → 39.4 GB)。在 Elasticsearch 9.2+ 中,所有 logs-* 数据流默认已启用 LogsDB。对于 8.x 或更早的 9.x 集群,只需在 index template 中添加一行配置,即可在下一次 rollover 生效,无需重新索引,也不会有数据丢失。