内存和 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 将使用这些分配的 JVM RAM 中的一部分或全部,具体取决于 Metabase 的活动。但从机器的角度来看,即使 Metabase 只使用分配的 RAM 的一小部分,JVM 也会始终使用已分配的 2GB 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 的文档。