内存和 JVM 问题故障排除

Metabase 在 Java 虚拟机 (JVM) 上运行,并且根据其配置方式,它可能会使用服务器的文件系统来存储一些信息。因此,JVM 或文件系统出现问题都可能阻止 Metabase 运行。

Java 版本

Metabase 应该在 Java 21 版本上运行(不支持旧版本)。

在搜索 Java 版本时,请始终使用您选择的主要版本的最新次要版本。例如,在 Java 21.0.1 和 Java 21.0.4 之间进行选择时,请选择最新版本(在本例中为 21.0.4)。

我们建议在单个服务器上仅运行一个 Java 版本,因为在单个服务器上运行多个 Java 版本可能会导致应用程序问题。如果您需要运行多个应用程序,每个应用程序都需要不同的 Java 版本,请考虑使用容器(因为容器旨在解决此问题)。否则,只需确保您可以使用单个 Java 版本运行所有应用程序。

Metabase 的内存使用量

Metabase 以 JAR 文件形式发布,该文件在 Java 虚拟机 (JVM) 上运行。

区分Metabase的内存使用量和 JVM 的内存使用量非常重要。

JVM 将消耗恒定数量的内存。默认情况下,JVM 将使用大约机器 RAM 的四分之一(尽管您可以更改您希望 JVM 使用的 RAM 量)。

JVM 应用程序(如 Metabase)将消耗和释放分配给 JVM 的 RAM。但是,JVM 不会将未使用的 RAM 释放给机器;JVM 的内存使用量将是恒定的。

因此,在具有 8 GB RAM 的机器上,默认情况下 JVM 将使用 2 GB RAM。Metabase 将使用这 2 GB JVM 分配的 RAM 中的一部分或全部,具体取决于 Metabase 的活动。但从机器的角度来看,JVM 将始终使用分配的 2GB RAM,即使 Metabase 仅使用分配的 RAM 的一小部分。

诊断内存问题

鉴于上述对 JVM 如何处理内存的解释,如果您在使用 Metabase 时遇到性能问题,并且您认为这不是由您的数据仓库引起的,您将需要检查以下警报

Metabase 因 Java 堆空间 OutOfMemoryError 而崩溃

JVM 通常可以计算出系统上有多少 RAM 可用,并自动为堆内存使用量设置合理的上限。但是,在某些共享托管环境中,这并不总是按预期工作。这种情况的常见症状是出现类似以下的错误消息

java.lang.OutOfMemoryError: Java heap space

如果您看到“内存不足” (OOM) 错误,您需要为 JVM 分配更多内存

当以折线图形式查看一段时间内的内存使用情况时,您会看到锯齿状模式

您可以使用工具查看 Metabase 如何随时间推移使用可用的内存。查看

您需要检查的特定 Prometheus 指标是 jvm_memory_bytes_used{area=”heap”}

需要注意的警报:锯齿状模式。Metabase 将快速消耗大量内存,这将触发垃圾回收,从而释放内存,而 Metabase 又会快速消耗内存。这种内存使用量的上下波动模式是频繁垃圾回收周期的标志。垃圾回收将占用 CPU 周期,这可能会降低应用程序的速度。

如果您看到这种情况,您需要增加分配给 JVM 的内存量

为 JVM 分配更多内存

您可以设置 JVM 选项以将更多内存分配给 JVM 的堆。例如,您的 Java 运行时可能使用 -X 标志来执行此操作

java -Xmx2g -jar metabase.jar

向上调整内存分配,直到 Metabase 看起来正常为止,但请确保该数字低于机器上可用的 RAM 总量,因为 Metabase 不会是唯一运行的进程。通常为机器上的其他进程保留 1 到 2 GB 的 RAM 就足够了,因此您可以在具有 2 GB RAM 的机器上将 -Xmx 设置为 1g,在具有 4 GB RAM 的机器上设置为 2g,依此类推。您可能需要试验此设置以找到一个使 Metabase 和其他所有内容都能很好地协同工作的设置(并且此实验可能需要升级到具有更多内存的机器)。

您还可以使用环境变量 JAVA_OPTS 来设置 JVM 参数,而不是直接将它们传递给 java。这在运行 Docker 镜像时尤其有用

docker run -d -p 3000:3000 -e "JAVA_OPTS=-Xmx2g" metabase/metabase

诊断导致 OutOfMemoryErrors 的内存问题

如果 Metabase 实例启动并运行了相当长的时间后才耗尽内存,则可能存在特定事件(例如大型查询)触发了 OutOfMemoryError。诊断内存使用位置的一种方法是在触发 OutOfMemoryError 时启用堆转储。要启用此功能,您需要向 java 调用添加两个标志

java -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/a/directory -jar metabase-jar

-XX:HeapDumpPath 标志指定转储的放置位置——当前目录是默认位置。当发生 OutOfMemoryError 时,JVM 会将 hprof 文件转储到指定的目录。这些 hprof 文件可能很大(-Xmx 参数的大小),因此请确保您的磁盘有足够的空间。可以使用许多不同的工具读取这些 hprof 文件,例如 jhat(JDK 中包含)或 Eclipse 内存分析器工具

Metabase 无法从文件或文件夹读取或写入(IOError)

如果您看到有关文件权限的错误,例如 Metabase 无法读取 SQLite 数据库或自定义 GeoJSON 地图文件,请查看我们的Docker 故障排除指南中的“Metabase 无法从文件或目录读取/写入”部分。

警告:不支持 sun.reflect.Reflection.getCallerClass

不用担心。

WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.

如果您看到上述错误,请忽略它。您的 Metabase 非常健康,并且运行正常。

阅读其他Metabase 版本的文档。