JVM 配置

JVM 配置 #

本页介绍 config/jvm.options 文件中的 JVM 启动参数。这些参数在 Easysearch 启动时由 JVM 读取,修改后需要重启节点生效。

Easysearch 2.5.0 默认使用并推荐 JDK 25,Bundle 包默认内置 JDK 25。 JDK 21 仅用于兼容已部署且暂不方便升级 JDK 的客户环境;两种运行时均使用安全 agent,并要求禁用 JDK SecurityManager。 请以目标发行包的默认配置为基础调整参数。下文保留的旧 JDK 版本条件仅用于解释配置语法和历史配置,不代表当前版本支持这些运行时。


堆内存设置 #

堆内存是 JVM 配置中最重要的参数。

# 堆大小设为物理内存的 50%,但不超过 31 GB
# -Xms 和 -Xmx 必须相同,避免运行时堆调整
-Xms16g
-Xmx16g
参数说明
-XmsJVM 初始堆大小
-XmxJVM 最大堆大小

设置原则 #

  1. -Xms 和 -Xmx 设为相同值:避免运行时堆大小调整带来的性能波动。
  2. 不超过物理内存的 50%:剩余内存留给操作系统文件缓存(Lucene 严重依赖 OS 页面缓存)。
  3. 不超过 31 GB(建议设为 31g 或 30g):超过约 32 GB 后 JVM 无法使用压缩对象指针(Compressed OOPs),实际可用内存反而减少。
  4. 不低于 1 GB:过小的堆会导致频繁 GC。

验证压缩指针 #

GET _nodes/stats/jvm?filter_path=**.using_compressed_ordinary_object_pointers

返回 true 表示压缩指针生效。

通过环境变量覆盖 #

如果不想修改 jvm.options 文件,可以通过环境变量覆盖:

ES_JAVA_OPTS="-Xms4g -Xmx4g" ./bin/easysearch

环境变量的优先级高于 jvm.options 文件中的设置。


垃圾回收器 #

Easysearch 2.5.0 在默认 JDK 25 和兼容运行时 JDK 21 上均使用 G1GC。发行配置中还保留以下版本条件:

  • JDK 8-10:使用 CMS(Concurrent Mark-Sweep)
  • JDK 11+:默认使用 G1GC
# JDK 8-10: CMS 垃圾回收器
8-10:-XX:+UseConcMarkSweepGC
8-10:-XX:CMSInitiatingOccupancyFraction=75
8-10:-XX:+UseCMSInitiatingOccupancyOnly

# JDK 11+: G1GC(推荐)
11-:-XX:+UseG1GC
11-:-XX:G1ReservePercent=25
11-:-XX:InitiatingHeapOccupancyPercent=30
参数说明
8-10:-XX:+UseConcMarkSweepGCJDK 8-10 使用 CMS 垃圾回收器
8-10:-XX:CMSInitiatingOccupancyFraction=75JDK 8-10:老年代占用 75% 时触发 CMS 回收
11-:-XX:+UseG1GCJDK 11+ 使用 G1GC,支持更大的堆和更稳定的暂停时间
11-:-XX:G1ReservePercent=25G1GC 预留 25% 堆用于浮动垃圾
11-:-XX:InitiatingHeapOccupancyPercent=30堆占用 30% 时启动并发回收

⚠️ 注意:版本号前缀(如 8-10:、11-)表示该参数仅在指定 JDK 版本范围内生效。除非有充分的理由和测试数据,不建议更改默认 GC 配置。


OOM 保护 #

# 发生 OutOfMemoryError 时生成堆转储文件
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data

# 发生 OOM 时的错误日志路径
-XX:ErrorFile=logs/hs_err_pid%p.log

Lucene 性能优化(JDK 9+) #

# JDK 9+:启用 Lucene 性能优化模块
# jdk.unsupported:提供 sun.misc.Unsafe 用于低级内存操作
# jdk.management:提供扩展的管理接口
9-:--add-modules=jdk.unsupported,jdk.management

Vector API 支持(JDK 20+) #

# JDK 20+:启用向量 API(孵化功能)用于 SIMD 支持
20-:--add-modules=jdk.incubator.vector

Vector API 可以加速搜索和 Lucene 索引操作,特别是在向量搜索场景中。


OOM 保护(旧语法) #

# 发生 OutOfMemoryError 时生成堆转储文件
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data

# 发生 OOM 时立即退出 JVM(让进程管理器自动重启)
-XX:+ExitOnOutOfMemoryError
参数说明
-XX:+HeapDumpOnOutOfMemoryErrorOOM 时自动生成 heap dump 文件,用于事后分析
-XX:HeapDumpPathHeap dump 文件的存储路径(相对于 $ES_HOME)
-XX:+ExitOnOutOfMemoryErrorOOM 时立即退出 JVM,而不是挂起

GC 日志 #

Easysearch 默认启用 GC 日志,不同 JDK 版本的配置方式不同:

JDK 8 GC 日志 #

8:-XX:+PrintGCDetails
8:-XX:+PrintGCDateStamps
8:-XX:+PrintTenuringDistribution
8:-XX:+PrintGCApplicationStoppedTime
8:-Xloggc:logs/gc.log
8:-XX:+UseGCLogFileRotation
8:-XX:NumberOfGCLogFiles=32
8:-XX:GCLogFileSize=64m

JDK 9+ GC 日志 #

9-:-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m
参数部分说明
gc*,gc+age=trace,safepoint记录 GC 事件、年龄分布、安全点
file=logs/gc.log输出到 logs/gc.log
utctime,pid,tags日志中包含 UTC 时间、进程 ID、标签
filecount=32,filesize=64m最多 32 个轮转文件,每个 64 MB

GC 日志对排查性能问题非常重要,建议保持默认开启。


其他常用 JVM 参数 #

临时目录 #

# 临时文件目录
-Djava.io.tmpdir=${ES_TMPDIR}

安全检查(默认 JDK 25,兼容 JDK 21) #

# Easysearch 2.5.0;其他发行版本使用对应包内的实际文件名
-Djava.security.manager=disallow
21:-javaagent:lib/easysearch-security-agent-2.5.0.jar
25:-javaagent:lib/easysearch-security-agent-2.5.0.jar

默认 JDK 25 和兼容运行时 JDK 21 加载同一个 Java agent 执行安全检查。 两种运行时均通过 java.security.manager=disallow 禁用 JDK 自身的 SecurityManager; 启动时会显式校验没有安装 JDK SecurityManager,且 java.security.manager 的值严格为 disallow。 缺少该参数、将其改为其他值,或已安装 JDK SecurityManager,都会拒绝启动;JDK 25 也必须保留该参数。 请保留发行包生成的 agent 参数及相邻的 bootstrap jar;缺少 agent 时服务会拒绝启动。 升级并保留旧 jvm.options 时,必须同步新发行包的 agent 文件名和必要参数,同时保留自己的堆大小等设置。 两种运行时都应保留发行配置中的 21-:--enable-preview 和 19-:--enable-native-access=ALL-UNNAMED; JDK 21 需要这些参数来加载相应的 Lucene 和 custom-codecs 实现。 这些版本配置不代表 JDK 22~24 或 JDK 26 已受支持。

easysearch.yml 中的 security.enabled 控制认证与 TLS 等安全模块功能,不用于关闭 JVM 安全 agent 或上述启动校验。

agent 读取核心策略和 plugin-security.policy,结合配置目录、数据目录等动态权限, 检查选定的文件操作、Socket/SocketChannel 连接及 System.exit/Runtime.halt 调用。 这些检查不覆盖所有文件或网络 API,也不复刻旧 SecurityManager 的反射、线程组或异步权限上下文。 插件安装时会标明已跳过的权限类型;声明这些权限不代表相应操作仍受强制检查。 第三方插件仍需作为可信代码管理。

Locale 配置 #

# JDK 9-20:使用 SPI 和系统兼容性 Provider
9-20:-Djava.locale.providers=SPI,COMPAT

# JDK 21+:使用 SPI 和 CLDR Provider
21-:-Djava.locale.providers=SPI,CLDR

编译优化(JDK 23+) #

# JDK 23:修复 MethodHandle 性能问题
23:-XX:CompileCommand=dontinline,java/lang/invoke/MethodHandle.setAsTypeCache
23:-XX:CompileCommand=dontinline,java/lang/invoke/MethodHandle.asTypeUncached

Native Access(JDK 19+) #

# JDK 19+:为所有未命名模块启用原生访问
19-:--enable-native-access=ALL-UNNAMED

# JDK 22+:禁用向量 API 警告
22-:-Djdk.incubator.vector.disableWarnings=true
参数说明
-Djava.io.tmpdirJVM 临时文件目录
-javaagentJDK 21、JDK 25 加载发行包提供的安全 agent
-Djava.security.manager=disallow禁用 JDK 自身的 SecurityManager
-Djava.locale.providersJVM 使用的 Locale 提供者

TLS 原生库加载(Linux/macOS) #

在 Linux/macOS 的 x86_64、ARM64 平台上,启动脚本会从安全模块的 tongsuo-openjdk-*.jar 中提取当前平台的 Conscrypt 原生库到 $ES_HOME/modules/security/native/,供 TLS 加载;目标文件已存在时复用。 首次提取时,启动用户需能创建并写入该目录,所选 JDK 也必须包含 jar 工具。


jvm.options 文件格式 #

jvm.options 文件中每行一个 JVM 参数,支持版本条件:

# 这是注释

# 无条件参数(所有 JVM 版本生效)
-Xms16g
-Xmx16g

# 版本条件参数
# JDK 8~10
8-10:-XX:+UseConcMarkSweepGC
# JDK 11+
11-:-XX:+UseG1GC
# JDK 9~20
9-20:-Djava.locale.providers=SPI,COMPAT
# JDK 21+
21-:-Djava.locale.providers=SPI,CLDR

版本条件语法 #

格式说明示例
无前缀所有版本生效-Xms16g
N仅 JDK N 生效25:-javaagent:lib/easysearch-security-agent-2.5.0.jar
N-JDK N 及以上版本11-:-XX:+UseG1GC (JDK 11+)
N-MJDK N 到 M 版本8-10:-XX:+UseConcMarkSweepGC (JDK 8-10)
  • 以 # 开头的行是注释。
  • 注释应单独占一行,不要放在 JVM 参数末尾。
  • 空行会被忽略。

jvm.options.d 目录 #

除了主 jvm.options 文件外,Easysearch 还会读取 config/jvm.options.d/ 目录下所有以 .options 结尾的文件。每个文件的格式与主 jvm.options 完全相同。

使用场景 #

  • 自定义参数与默认参数分离:将自定义 JVM 参数放在独立文件中,避免修改默认的 jvm.options 文件,便于升级时保留定制配置
  • 容器化部署:通过挂载配置文件到 jvm.options.d/ 目录,在不修改镜像的情况下调整 JVM 参数
  • 按关注点组织:将不同类型的参数(如 GC、调试、安全)放在不同文件中

示例 #

创建自定义堆内存配置:

# config/jvm.options.d/heap.options
-Xms16g
-Xmx16g

创建调试参数文件:

# config/jvm.options.d/debug.options
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/easysearch
-XX:ErrorFile=/var/log/easysearch/hs_err_pid%p.log

加载顺序 #

  1. 先读取 config/jvm.options 主文件
  2. 再按文件名字母顺序读取 config/jvm.options.d/*.options
  3. 如果同一参数出现多次,后加载的值会覆盖先加载的值

注意:jvm.options.d/ 目录中的文件必须以 .options 为扩展名,其他文件会被忽略。


配置示例 #

以下是局部参数示例,不可用来整份替换发行包的 jvm.options。调整时保留前述安全 agent、 -Djava.security.manager=disallow、preview、native access 等必要参数。

生产环境(64 GB 服务器,JDK 25) #

# 堆内存:物理内存的 50%,不超过 31 GB
-Xms31g
-Xmx31g

# G1GC(JDK 11+)
11-:-XX:+UseG1GC
11-:-XX:G1ReservePercent=25
11-:-XX:InitiatingHeapOccupancyPercent=30

# OOM 保护
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log

# GC 日志
9-:-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m

# 其他
-Djava.io.tmpdir=${ES_TMPDIR}

开发环境(8 GB 笔记本) #

-Xms1g
-Xmx1g

历史 CMS 配置(JDK 8-10,64 GB 服务器,不适用于 Easysearch 2.5.0) #

-Xms31g
-Xmx31g

# CMS GC(JDK 8-10)
8-10:-XX:+UseConcMarkSweepGC
8-10:-XX:CMSInitiatingOccupancyFraction=75
8-10:-XX:+UseCMSInitiatingOccupancyOnly

# OOM 保护
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log

常见问题 #

启动失败:堆内存分配失败 #

Initial heap size set to an invalid value

通常是因为 -Xms 或 -Xmx 超过了物理内存或操作系统限制。

频繁 Full GC #

  • 检查堆大小是否足够。
  • 使用 GET _nodes/stats/jvm 查看堆使用率。
  • 分析 GC 日志(logs/gc.log)定位原因。

压缩指针未启用 #

堆大小超过约 32 GB 时压缩指针失效。建议设为 31g 或以下。


延伸阅读 #