JVM 设置

编辑

jvm.options 设置文件 中配置 JVM 设置。JVM 设置也可以通过 LS_JAVA_OPTS 环境变量设置。

此文件包含一个使用特殊语法的 JVM 参数的行分隔列表

  • 仅包含空格的行将被忽略
  • # 开头的行被视为注释并被忽略

    # this is a comment
  • - 开头的行被视为 JVM 选项,独立于 JVM 版本应用

    -Xmx2g
  • 以数字后跟 : 再后跟 - 开头的行被视为 JVM 选项,仅当 JVM 版本与数字匹配时才应用

    8:-Xmx2g
  • 以数字后跟 - 再后跟 : 开头的行被视为 JVM 选项,仅当 JVM 版本大于或等于该数字时才应用

    8-:-Xmx2g
  • 以数字后跟 - 再后跟数字再后跟 : 开头的行被视为 JVM 选项,仅当 JVM 版本落在这两个数字的包含范围内时才应用

    8-9:-Xmx2g
  • 所有其他行都将被拒绝

设置内存大小

编辑

执行 Logstash 的 JVM 内存可以分为两个区域:堆内存和堆外内存。堆内存指的是 Java 堆,其中包含 Logstash 在其运行过程中创建的所有 Java 对象,有关如何调整其大小的说明,请参见 设置 JVM 堆大小。堆外内存是指堆内存之外的内存,它包含 Logstash 可以使用和控制的内存,通常是线程栈、直接内存和内存映射页面,请查看 设置堆外内存大小 以获取全面说明。在堆外空间中,有一些空间由 JVM 使用,其中包含虚拟机执行所需的所有数据结构。Logstash 无法控制此内存,并且很少自定义其设置。

设置 JVM 堆大小

编辑

以下是一些调整 JVM 堆大小的提示

  • 对于典型的摄取场景,建议的堆大小不应小于 4GB,也不应大于 8GB。
  • 如果堆大小太小,CPU 利用率可能会不必要地增加,导致 JVM 不断进行垃圾回收。您可以通过将堆大小加倍来检查此问题,看看性能是否得到改善。
  • 不要将堆大小增加到超过物理内存的数量。必须保留一些内存来运行操作系统和其他进程。对于大多数安装,一般准则是不超过物理内存的 50-75%。内存越多,可以使用百分比越高。
  • 将最小 (Xms) 和最大 (Xmx) 堆分配大小设置为相同的值,以防止堆在运行时调整大小,这是一个非常昂贵的过程。
  • 您可以使用 Java 附带的 jmap 命令行实用程序或使用 VisualVM 来更准确地测量 JVM 堆。更多信息,请参见 分析堆

设置堆外内存大小

编辑

操作系统、持久队列 mmap 页面、直接内存和其他进程除了分配给堆大小的内存外还需要内存。

内部 JVM 数据结构、线程栈、内存映射文件和用于输入/输出 (IO) 操作的直接内存都是堆外 JVM 内存的一部分。内存映射文件不是 Logstash 进程堆外内存的一部分,但在从磁盘分页文件时会消耗 RAM。这些映射文件加快了对持久队列页面的访问速度,这是一个性能改进——或权衡——以减少昂贵的磁盘操作,例如读取、写入和搜索。某些网络 I/O 操作也采用进程内直接内存使用,例如避免在网络套接字之间复制缓冲区。Elastic Agent、Beats、TCP 和 HTTP 输入等输入插件使用直接内存。线程栈区域包含 JVM 创建的每个 Java 线程的栈帧列表;每个帧都保留在方法调用期间传递的局部参数。如果需要根据处理需求调整大小,请阅读 设置 JVM 堆栈大小

插件根据其类型(输入、过滤器和输出)具有不同的线程模型。每个输入插件都在其自己的线程中运行,并可能产生其他线程。例如,每个 JDBC 输入插件都会启动一个调度程序线程。基于 Netty 的插件(如 TCP、Beats 或 HTTP 输入)会生成一个具有 2 * core_数量 线程的线程池。输出插件也可能会启动辅助线程,例如每个 Elasticsearch 输出实例的连接管理线程。每个管道也都有自己的线程负责管理管道生命周期。

总而言之,我们有 3 类内存使用情况,其中 2 类可以由 JVM 限制,而另一类则依赖于可用的空闲内存

内存类型 使用配置 由…使用

JVM 堆

-Xmx

任何正常的对象分配

JVM 直接内存

-XX:MaxDirectMemorySize

beats、tcp 和 http 输入

本地内存

N/A

持久队列页面、线程栈

在计算理想的内存分配时,请记住这些内存需求。

即将对缓冲区分配和故障排除内存不足错误进行的更改

编辑

Elastic Agent、Beats、TCP 和 HTTP 输入等插件当前默认使用直接内存,因为它往往可以提供更好的性能,尤其是在与网络堆栈交互时。在高负载下,即大量连接和大型消息的情况下,直接内存空间可能会耗尽,并导致堆外空间中的内存不足 (OOM) 错误。

堆外 OOM 很难调试,因此 Logstash 在 logstash.yml 中提供了一个 pipeline.buffer.type 设置,允许您控制为使用它们的插件分配内存缓冲区的位置。目前它默认设置为 direct,但您可以将其更改为 heap 以改为使用 Java 堆空间,这将在未来成为默认设置。当设置为 heap 时,插件使用的缓冲区分配将配置为优先 使用 Java 堆而不是直接内存,因为根据插件的不同,仍然可能需要直接内存分配。

设置为“heap”后,如果出现内存不足的情况,Logstash 将生成堆转储以方便调试。

重要的是要注意,由于以前驻留在直接内存中的分配将改为使用堆,因此 Java 堆的大小需求将受到此更改的影响。

从性能方面来看,不应该有明显的差异,因为虽然直接内存 IO 更快,但这些插件生成的 Logstash 事件对象最终都分配在 Java 堆上,无论设置如何,都会产生从直接内存到堆内存的复制成本。

  • 当您将 pipeline.buffer.type 设置为 heap 时,请考虑根据为直接空间保留的内存量增加 Java 堆。

内存大小

编辑

必须估算总 JVM 内存分配,并使用 Java 堆和直接内存设置间接控制。默认情况下,JVM 的堆外直接内存限制与堆大小相同。查看 beats 输入内存使用情况。考虑将 -XX:MaxDirectMemorySize 设置为堆大小的一半或任何可以适应您期望这些插件处理的负载的值。

在进行容量计算时,请记住 JVM 无法使用主机可用的全部内存,因为操作系统和其他进程也需要内存。

对于在多个管道上启用了持久队列 (PQ) 的 Logstash 实例,我们可以使用以下方法估算内存消耗

pipelines number * (pipeline threads * stack size + 2 * PQ page size) + direct memory + Java heap

每个持久队列都需要至少头部和尾部页面存在并可访问内存。默认页面大小为 64 MB,因此每个 PQ 需要至少 128 MB 的堆内存,这可能是每个管道内存消耗的重要来源。请注意,内存映射文件的大小无法用上限限制。

堆栈大小是一个取决于所用 JVM 的设置,但可以使用 -Xss 设置进行自定义。

默认情况下,直接内存空间与 Java 堆一样大,但可以使用 -XX:MaxDirectMemorySize 设置进行自定义。

示例

考虑一个运行 10 个管道的 Logstash 实例,使用简单的输入和输出插件,不会启动其他线程,它有 1 个管道线程、1 个输入插件线程和 12 个工作线程,总共 14 个线程。请记住,默认情况下,JVM 分配的直接内存等于分配给 Java 堆的内存。

计算结果为

  • 本地内存:1.4Gb [源自 10 * (14 * 1Mb + 128Mb)]
  • 直接内存:4Gb
  • Java 堆:4Gb

设置 JVM 堆栈大小

编辑

大型配置可能需要额外的 JVM 堆栈内存。如果您看到堆栈溢出错误,请尝试增加 JVM 堆栈大小。在 jvm.options 设置文件 中添加类似于此的条目

-Xss4M

请注意,默认堆栈大小因平台和操作系统版本而异。您可以通过运行以下命令来查找默认值:

java -XX:+PrintFlagsFinal -version | grep ThreadStackSize

根据默认堆栈大小,开始时乘以 4 倍,然后是 8 倍,然后是 16 倍,直到溢出错误解决。

使用 LS_JAVA_OPTS

编辑

LS_JAVA_OPTS 环境变量也可以用来覆盖 jvm.options 文件 设置文件 中的 JVM 设置。此变量的内容是对 jvm.options 文件中配置的选项的补充,并将覆盖同时存在于这两个位置中的任何设置。

例如,要设置不同的区域设置以启动 Logstash 实例

LS_JAVA_OPTS="-Duser.country=DE -Duser.language=de" bin/logstash -e 'input { stdin { codec => json } }'