如何使用 LogsDB 降低 Elasticsearch 日志存储成本

0 阅读9分钟

作者:来自 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写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

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写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

这一行 "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写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

两个索引现在包含完全相同的文档,因此下一步的存储对比只反映索引模式(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-standard111,81815.37 MB
apache-logsdb111,8188.6 MB
减少比例44%

从这个角度来看:在 1 TB 的日志数据下,LogsDB 可以将其压缩到约 560 GB。这意味着在不修改任何查询的情况下节省了 450 GB。在生产规模(数十亿文档并启用 synthetic _source)下,节省比例可达到 76%——在我们的基准测试中,从 162.7 GB 降低到 39.4 GB。

在 Kibana 中可视化

要直观查看存储差异,请打开 Kibana,进入 ManagementStack ManagementIndex 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写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

选项 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 生效,无需重新索引,也不会有数据丢失。

下一步

原文:www.elastic.co/observabili…