ELK,萌萌哒
compression

compression

Easysearch ZSTD 基准测试:高压缩率下实现近 5 倍查询吞吐

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 27 次浏览 • 2 小时前 • 来自相关话题

在搜索引擎领域,压缩算法的选择一直是一个经典的权衡难题:

  • 选择高压缩率(如 best_compression / DEFLATE),磁盘省了,但查询解压慢;
  • 选择高速编码(如默认 LZ4),查询快了,但磁盘占用大。

Easysearch 引入了基于 JDK 21 FFM(Foreign Function & Memory API) 直连本地 ZSTD 动态库的加速方案,试图打破这一困局。为了验证效果,我们在完全对等的环境下,对 Easysearch(ZSTD)和 Elasticsearch 7.10.2(best_compression)进行了一次严格的查询吞吐对比测试。

结果令人振奋——即使在系统明显背景负载下,Easysearch 也没有因为高压缩而变慢,反而在查询吞吐上实现了近 5 倍提升


测试环境

为确保对比公平,两套集群的硬件资源、JVM 配置、数据规模、索引结构完全对齐:

配置项 Easysearch Elasticsearch 7.10.2
节点数 3 3
JVM 堆内存 12GB × 3 12GB × 3
node.processors 16 × 3 16 × 3
文档数 10,000,000 10,000,000
主分片 / 副本 3 / 0 3 / 0
数据类型 nginx 访问日志 nginx 访问日志
字段数 17 17
mapping 完全一致(MD5 校验) 完全一致(MD5 校验)
Stored fields 压缩模式 ZSTD (JDK21 FFM/native, level=3) best_compression (DEFLATE)

压缩机制对比:best_compression 映射到 Lucene BEST_COMPRESSION;在 stored fields 路径上,压缩实现为 DeflateWithPresetDictCompressionMode,内部使用 java.util.zip.Deflater/Inflater(即 DEFLATE)。 Easysearch ZSTD 当前走 JDK 21 FFM 绑定本地 zstd 库(java.lang.foreign);index.compression.zstd.jni=true 为当前这套实现的启用方式。

查询模型:JMeter 随机 match 查询,随机命中 service_namemethoderror_codeurl 四个字段,每次返回 10 条文档。

压测起始负载(_cat/nodes 快照):

负载项 Easysearch run Elasticsearch run
load_1m 29.74 25.27
load_5m 27.10 28.15
load_15m 26.09 36.96
ram.percent 99 99

说明:压测并非在空闲机上进行,而是在已有明显背景负载的生产式环境下完成。


核心结果

1. 查询吞吐量(QPS):在高背景负载下,Easysearch 仍领先 372%

稳态阶段(3 轮平均),Easysearch 的查询吞吐是 Elasticsearch 的 4.7 倍

指标 Elasticsearch (DEFLATE) Easysearch (ZSTD) 差异
稳态 QPS 532.8 2,518.0 +372.6%
平均响应时间 779.0 ms 164.3 ms -78.9%
稳态 CPU 占用(系统总占用) 92.43% 89.59% 仅作背景参考

注:压测期间服务器存在明显背景负载(其他进程占用较高),该 CPU 指标是系统总占用,不等价于“仅搜索进程”的纯业务 CPU 对比。

在系统总 CPU 均接近 90% 的背景下,Easysearch 仍达到接近 5 倍吞吐。

查询吞吐量 QPS 对比(稳态均值)

ES (DEFLATE) 532.8 Easysearch (ZSTD) 2,518.0 QPS(越高越好)

2. 响应时间:从近 1 秒降到 164 毫秒

平均响应时间对比(ms,越低越好)

ES (DEFLATE) 779.0 ms Easysearch (ZSTD) 164.3 ms 响应时间(越低越好)

用户体感上,这意味着:同样一个搜索请求,Elasticsearch 还在等解压,Easysearch 已经把结果送到了客户端。

3. 各轮次详细数据

各轮次 QPS 趋势

0 1500 3000 warmup steady_r1 steady_r2 steady_r3 2087.9 2533.2 2491.7 2529.0 484.5 521.8 539.6 537.1 Easysearch (ZSTD) Elasticsearch (DEFLATE)

各轮次平均响应时间趋势(ms)

0 400 800 warmup steady_r1 steady_r2 steady_r3 171 795 769 773 39 163 166 164 Easysearch (ZSTD) Elasticsearch (DEFLATE)

4. CPU 使用效率:每 1% CPU 产出的 QPS 差距惊人

单看 CPU 占用率,两者似乎差不多(89.59% vs 92.43%)。但如果换一个视角——每消耗 1% CPU 能产出多少 QPS,差距就一目了然了:

指标 Elasticsearch (DEFLATE) Easysearch (ZSTD) 倍数
稳态 QPS 532.8 2,518.0
稳态 CPU 92.43% 89.59%
QPS / 1% CPU 5.76 28.10 4.88×

CPU 使用效率:每 1% CPU 产出的 QPS

ES (DEFLATE) 5.76 Easysearch (ZSTD) 28.10 QPS / 1% CPU(越高越好)── 效率差距 4.88 倍

这意味着什么?

  • ES 使用 DEFLATE(best_compression)时,解压路径更可能成为 CPU 热点;结合 ES 的高 CPU(92.43%)与较低 QPS,说明单位 CPU 产出偏低;
  • Easysearch 使用 ZSTD(JDK21 FFM/native)时,解压开销更小;在相近 CPU 水位(89.59%)下获得更高 QPS,单位 CPU 产出明显更高。

换句话说,当前这组实测更支持“ZSTD 在该查询模型下单位 CPU 产出更高”。

5. 存储空间:ZSTD 并未膨胀

索引 压缩算法 磁盘占用
nginx_best_10m (ES) best_compression (DEFLATE) 1.8 GB
nginx_zstd3 (Easysearch) ZSTD (level=3, JDK21 FFM/native) 1.9 GB

两者存储空间接近。若按 _cat/indices 的 1 位小数展示是 1.8GB vs 1.9GB;若按 _stats/store 字节值计算,差异约 2.5%。因此可以认为 ZSTD 在 level=3 下与 DEFLATE best_compression 压缩率接近。

磁盘占用对比(GB)

ES (DEFLATE) 1.8 GB Easysearch (ZSTD) 1.9 GB 按字节口径约 +2.5%,整体接近

为什么 ZSTD 能做到"又小又快"?

传统认知中,压缩率和解压速度是一对矛盾。但 ZSTD 算法天然具备非对称压缩的特性:

压缩算法特性对比

算法 压缩率 解压速度 LZ4 快但不紧凑 DEFLATE 紧凑但解压慢 ZSTD 两者兼得

在搜索引擎场景中,查询会触发存储字段(_source)读取与解压路径,命中文件系统页缓存时,可能不发生实际磁盘 I/O,但仍需进行 _source 解压。 当查询涉及较多 _source 读取时:

  • DEFLATE 的解压开销成为 CPU 瓶颈,拖慢了整体吞吐;
  • ZSTD(JDK21 FFM/native) 的解压速度在该场景下明显更优,单次请求的解压 CPU 成本更低,从而释放出更多 CPU 资源用于并发查询处理。

这就是为什么 Easysearch 在 CPU 占用更低(89.59% vs 92.43%)的情况下,反而能处理近 5 倍的查询量。


一张图总结

Easysearch ZSTD vs Elasticsearch DEFLATE — 全维度对比

查询吞吐 +372.6% ↑ 响应时间 -78.9% ↓ CPU 效率 (QPS/CPU%) +387.8% ↑ 磁盘占用 +2.5% ≈ CPU 占用 -2.84pp ↓ 压缩率几乎相同,查询性能提升近 4 倍,CPU 效率提升近 5 倍

结论

Easysearch 的 ZSTD 压缩方案证明了一个事实:即使在高背景负载下,高压缩率和高查询性能依然可以兼得

在 1000 万条 nginx 日志、且系统存在明显背景负载的实测中:

  • 查询吞吐提升 372%,从 533 QPS 跃升至 2518 QPS
  • 平均响应时间下降 79%,从 779ms 降至 164ms
  • CPU 使用效率提升 388%,每 1% CPU 产出 28.10 QPS vs 5.76 QPS
  • CPU 占用绝对值下降 2.84 个百分点(相对下降约 3.07%)
  • 磁盘占用与 DEFLATE best_compression 接近(按字节口径约 +2.5%)

对于日志分析、可观测性、安全审计等需要兼顾存储成本和查询性能的场景,Easysearch ZSTD 是一个不需要妥协的选择。


ZSTD 使用方法

1) 新建索引时启用 ZSTD

curl -k -u 'admin:<password>' -X PUT 'https://127.0.0.1:9200/<index-name>' \
  -H 'Content-Type: application/json' -d '{
    "settings": {
      "index.codec": "ZSTD",
      "index.compression.zstd.jni": true
    }
  }'

可选参数:

  • index.compression.zstd.level(默认 3

说明:

  • index.compression.zstd.dict 固定为 true,无需单独配置
  • index.compression.zstd.dict 不作为独立开关来调整

2) 老索引切换到 ZSTD(推荐 reindex)

index.codec 是静态设置(打开状态不可动态改;可在关闭索引后调整)。
index.compression.zstd.jnifinal 设置(关闭索引后也不可修改)。
如果老索引要启用 index.compression.zstd.jni=true,建议新建目标索引后 reindex 迁移: 如果对已有索引执行 PUT /<index-name>/_settings 直接修改,会报错:final <index-name> setting [index.compression.zstd.jni], not updateable

# 先创建目标索引(启用 ZSTD)
curl -k -u 'admin:<password>' -X PUT 'https://127.0.0.1:9200/<target-index>' \
  -H 'Content-Type: application/json' -d '{
    "settings": {
      "index.codec": "ZSTD",
      "index.compression.zstd.jni": true
    }
  }'

# 再迁移数据
curl -k -u 'admin:<password>' -X POST 'https://127.0.0.1:9200/_reindex' \
  -H 'Content-Type: application/json' -d '{
    "source": { "index": "<source-index>" },
    "dest":   { "index": "<target-index>" }
  }'

3) 校验是否生效

curl -k -u 'admin:<password>' \
  'https://127.0.0.1:9200/<index-name>/_settings?include_defaults=true&pretty'

重点确认:

  • index.codec = ZSTD
  • index.compression.zstd.jni = true

关于 Easysearch

INFINI Easysearch 是一个分布式的搜索型数据库,实现非结构化数据检索、全文检索、向量检索、地理位置信息查询、组合索引查询、多语种支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同时添加和完善多项企业级功能。Easysearch 助您拥有简洁、高效、易用的搜索体验。

官网文档:https://docs.infinilabs.com/easysearch

作者:张磊,极限科技(INFINI Labs)搜索引擎研发负责人,对 Elasticsearch 和 Lucene 源码比较熟悉,目前主要负责公司的 Easysearch 产品的研发以及客户服务工作。


相关文章:

Easysearch ZSTD 基准测试:高压缩率下实现近 5 倍查询吞吐

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 27 次浏览 • 2 小时前 • 来自相关话题

在搜索引擎领域,压缩算法的选择一直是一个经典的权衡难题:

  • 选择高压缩率(如 best_compression / DEFLATE),磁盘省了,但查询解压慢;
  • 选择高速编码(如默认 LZ4),查询快了,但磁盘占用大。

Easysearch 引入了基于 JDK 21 FFM(Foreign Function & Memory API) 直连本地 ZSTD 动态库的加速方案,试图打破这一困局。为了验证效果,我们在完全对等的环境下,对 Easysearch(ZSTD)和 Elasticsearch 7.10.2(best_compression)进行了一次严格的查询吞吐对比测试。

结果令人振奋——即使在系统明显背景负载下,Easysearch 也没有因为高压缩而变慢,反而在查询吞吐上实现了近 5 倍提升


测试环境

为确保对比公平,两套集群的硬件资源、JVM 配置、数据规模、索引结构完全对齐:

配置项 Easysearch Elasticsearch 7.10.2
节点数 3 3
JVM 堆内存 12GB × 3 12GB × 3
node.processors 16 × 3 16 × 3
文档数 10,000,000 10,000,000
主分片 / 副本 3 / 0 3 / 0
数据类型 nginx 访问日志 nginx 访问日志
字段数 17 17
mapping 完全一致(MD5 校验) 完全一致(MD5 校验)
Stored fields 压缩模式 ZSTD (JDK21 FFM/native, level=3) best_compression (DEFLATE)

压缩机制对比:best_compression 映射到 Lucene BEST_COMPRESSION;在 stored fields 路径上,压缩实现为 DeflateWithPresetDictCompressionMode,内部使用 java.util.zip.Deflater/Inflater(即 DEFLATE)。 Easysearch ZSTD 当前走 JDK 21 FFM 绑定本地 zstd 库(java.lang.foreign);index.compression.zstd.jni=true 为当前这套实现的启用方式。

查询模型:JMeter 随机 match 查询,随机命中 service_namemethoderror_codeurl 四个字段,每次返回 10 条文档。

压测起始负载(_cat/nodes 快照):

负载项 Easysearch run Elasticsearch run
load_1m 29.74 25.27
load_5m 27.10 28.15
load_15m 26.09 36.96
ram.percent 99 99

说明:压测并非在空闲机上进行,而是在已有明显背景负载的生产式环境下完成。


核心结果

1. 查询吞吐量(QPS):在高背景负载下,Easysearch 仍领先 372%

稳态阶段(3 轮平均),Easysearch 的查询吞吐是 Elasticsearch 的 4.7 倍

指标 Elasticsearch (DEFLATE) Easysearch (ZSTD) 差异
稳态 QPS 532.8 2,518.0 +372.6%
平均响应时间 779.0 ms 164.3 ms -78.9%
稳态 CPU 占用(系统总占用) 92.43% 89.59% 仅作背景参考

注:压测期间服务器存在明显背景负载(其他进程占用较高),该 CPU 指标是系统总占用,不等价于“仅搜索进程”的纯业务 CPU 对比。

在系统总 CPU 均接近 90% 的背景下,Easysearch 仍达到接近 5 倍吞吐。

查询吞吐量 QPS 对比(稳态均值)

ES (DEFLATE) 532.8 Easysearch (ZSTD) 2,518.0 QPS(越高越好)

2. 响应时间:从近 1 秒降到 164 毫秒

平均响应时间对比(ms,越低越好)

ES (DEFLATE) 779.0 ms Easysearch (ZSTD) 164.3 ms 响应时间(越低越好)

用户体感上,这意味着:同样一个搜索请求,Elasticsearch 还在等解压,Easysearch 已经把结果送到了客户端。

3. 各轮次详细数据

各轮次 QPS 趋势

0 1500 3000 warmup steady_r1 steady_r2 steady_r3 2087.9 2533.2 2491.7 2529.0 484.5 521.8 539.6 537.1 Easysearch (ZSTD) Elasticsearch (DEFLATE)

各轮次平均响应时间趋势(ms)

0 400 800 warmup steady_r1 steady_r2 steady_r3 171 795 769 773 39 163 166 164 Easysearch (ZSTD) Elasticsearch (DEFLATE)

4. CPU 使用效率:每 1% CPU 产出的 QPS 差距惊人

单看 CPU 占用率,两者似乎差不多(89.59% vs 92.43%)。但如果换一个视角——每消耗 1% CPU 能产出多少 QPS,差距就一目了然了:

指标 Elasticsearch (DEFLATE) Easysearch (ZSTD) 倍数
稳态 QPS 532.8 2,518.0
稳态 CPU 92.43% 89.59%
QPS / 1% CPU 5.76 28.10 4.88×

CPU 使用效率:每 1% CPU 产出的 QPS

ES (DEFLATE) 5.76 Easysearch (ZSTD) 28.10 QPS / 1% CPU(越高越好)── 效率差距 4.88 倍

这意味着什么?

  • ES 使用 DEFLATE(best_compression)时,解压路径更可能成为 CPU 热点;结合 ES 的高 CPU(92.43%)与较低 QPS,说明单位 CPU 产出偏低;
  • Easysearch 使用 ZSTD(JDK21 FFM/native)时,解压开销更小;在相近 CPU 水位(89.59%)下获得更高 QPS,单位 CPU 产出明显更高。

换句话说,当前这组实测更支持“ZSTD 在该查询模型下单位 CPU 产出更高”。

5. 存储空间:ZSTD 并未膨胀

索引 压缩算法 磁盘占用
nginx_best_10m (ES) best_compression (DEFLATE) 1.8 GB
nginx_zstd3 (Easysearch) ZSTD (level=3, JDK21 FFM/native) 1.9 GB

两者存储空间接近。若按 _cat/indices 的 1 位小数展示是 1.8GB vs 1.9GB;若按 _stats/store 字节值计算,差异约 2.5%。因此可以认为 ZSTD 在 level=3 下与 DEFLATE best_compression 压缩率接近。

磁盘占用对比(GB)

ES (DEFLATE) 1.8 GB Easysearch (ZSTD) 1.9 GB 按字节口径约 +2.5%,整体接近

为什么 ZSTD 能做到"又小又快"?

传统认知中,压缩率和解压速度是一对矛盾。但 ZSTD 算法天然具备非对称压缩的特性:

压缩算法特性对比

算法 压缩率 解压速度 LZ4 快但不紧凑 DEFLATE 紧凑但解压慢 ZSTD 两者兼得

在搜索引擎场景中,查询会触发存储字段(_source)读取与解压路径,命中文件系统页缓存时,可能不发生实际磁盘 I/O,但仍需进行 _source 解压。 当查询涉及较多 _source 读取时:

  • DEFLATE 的解压开销成为 CPU 瓶颈,拖慢了整体吞吐;
  • ZSTD(JDK21 FFM/native) 的解压速度在该场景下明显更优,单次请求的解压 CPU 成本更低,从而释放出更多 CPU 资源用于并发查询处理。

这就是为什么 Easysearch 在 CPU 占用更低(89.59% vs 92.43%)的情况下,反而能处理近 5 倍的查询量。


一张图总结

Easysearch ZSTD vs Elasticsearch DEFLATE — 全维度对比

查询吞吐 +372.6% ↑ 响应时间 -78.9% ↓ CPU 效率 (QPS/CPU%) +387.8% ↑ 磁盘占用 +2.5% ≈ CPU 占用 -2.84pp ↓ 压缩率几乎相同,查询性能提升近 4 倍,CPU 效率提升近 5 倍

结论

Easysearch 的 ZSTD 压缩方案证明了一个事实:即使在高背景负载下,高压缩率和高查询性能依然可以兼得

在 1000 万条 nginx 日志、且系统存在明显背景负载的实测中:

  • 查询吞吐提升 372%,从 533 QPS 跃升至 2518 QPS
  • 平均响应时间下降 79%,从 779ms 降至 164ms
  • CPU 使用效率提升 388%,每 1% CPU 产出 28.10 QPS vs 5.76 QPS
  • CPU 占用绝对值下降 2.84 个百分点(相对下降约 3.07%)
  • 磁盘占用与 DEFLATE best_compression 接近(按字节口径约 +2.5%)

对于日志分析、可观测性、安全审计等需要兼顾存储成本和查询性能的场景,Easysearch ZSTD 是一个不需要妥协的选择。


ZSTD 使用方法

1) 新建索引时启用 ZSTD

curl -k -u 'admin:<password>' -X PUT 'https://127.0.0.1:9200/<index-name>' \
  -H 'Content-Type: application/json' -d '{
    "settings": {
      "index.codec": "ZSTD",
      "index.compression.zstd.jni": true
    }
  }'

可选参数:

  • index.compression.zstd.level(默认 3

说明:

  • index.compression.zstd.dict 固定为 true,无需单独配置
  • index.compression.zstd.dict 不作为独立开关来调整

2) 老索引切换到 ZSTD(推荐 reindex)

index.codec 是静态设置(打开状态不可动态改;可在关闭索引后调整)。
index.compression.zstd.jnifinal 设置(关闭索引后也不可修改)。
如果老索引要启用 index.compression.zstd.jni=true,建议新建目标索引后 reindex 迁移: 如果对已有索引执行 PUT /<index-name>/_settings 直接修改,会报错:final <index-name> setting [index.compression.zstd.jni], not updateable

# 先创建目标索引(启用 ZSTD)
curl -k -u 'admin:<password>' -X PUT 'https://127.0.0.1:9200/<target-index>' \
  -H 'Content-Type: application/json' -d '{
    "settings": {
      "index.codec": "ZSTD",
      "index.compression.zstd.jni": true
    }
  }'

# 再迁移数据
curl -k -u 'admin:<password>' -X POST 'https://127.0.0.1:9200/_reindex' \
  -H 'Content-Type: application/json' -d '{
    "source": { "index": "<source-index>" },
    "dest":   { "index": "<target-index>" }
  }'

3) 校验是否生效

curl -k -u 'admin:<password>' \
  'https://127.0.0.1:9200/<index-name>/_settings?include_defaults=true&pretty'

重点确认:

  • index.codec = ZSTD
  • index.compression.zstd.jni = true

关于 Easysearch

INFINI Easysearch 是一个分布式的搜索型数据库,实现非结构化数据检索、全文检索、向量检索、地理位置信息查询、组合索引查询、多语种支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同时添加和完善多项企业级功能。Easysearch 助您拥有简洁、高效、易用的搜索体验。

官网文档:https://docs.infinilabs.com/easysearch

作者:张磊,极限科技(INFINI Labs)搜索引擎研发负责人,对 Elasticsearch 和 Lucene 源码比较熟悉,目前主要负责公司的 Easysearch 产品的研发以及客户服务工作。


相关文章: