内存和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 只使用了分配 RAM 的一小部分,JVM 也将始终使用那分配的 2 GB 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 Memory Analyzer Tool。
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 版本的文档。