如何在生产环境中运行 Metabase
如果您正在自托管 Metabase,这里有一些基准和最佳实践。
本文描述了 Metabase 生产就绪的设置,包括服务器大小、最佳实践和要避免的陷阱。本文适用于对自托管 Metabase 感兴趣的人。如果您希望我们为您运行 Metabase,只需注册免费试用。
Metabase JAR 中有什么
就上下文而言,Metabase 是一个 Web 应用程序。其后端用 Clojure 编写,前端用 JavaScript、TypeScript 和 ClojureScript 结合 React 框架编写。
默认情况下,整个应用程序是自包含的:后端和提供前端的 Web 服务器打包在同一个捆绑包中。该捆绑包是一个 JAR 文件,可以在任何安装了 Java 运行时环境的地方运行。
Metabase 还提供了一个容器镜像,其中打包了 JRE 和 Metabase JAR(您也可以使用 Podman 运行)。
您只需要一个 JAR 文件和一个数据库
要在生产环境中运行 Metabase,您需要两样东西:
- 一个 Metabase JAR 文件或容器镜像。
- 一个专用的 PostgreSQL 数据库来存储 Metabase 的应用程序数据库。
您也可以使用 MySQL/MariaDB 来存储 Metabase 的应用程序数据库,但我们强烈推荐使用 Postgres。
为什么您需要使用单独的应用程序数据库
Metabase 将其所有实体(仪表板、问题、帐户、配置)保存在其应用程序数据库中。
如果您坚持使用默认的基于文件的应用程序数据库,您的数据库最终将不可逆转地损坏,您将不得不从头开始(在丢失所有工作之后:所有问题、仪表板等)。
因此,您要避免的一件事是使用 Metabase JAR 附带的默认应用程序数据库。该嵌入式数据库仅用于本地使用。我们包含该嵌入式数据库作为一种奖励,供那些只想在自己的机器上试用 Metabase 的人使用。该嵌入式 H2 数据库还包含一些可供人们使用的数据示例。它不适用于生产环境。
同样,如果您在容器中运行 Metabase,每当您的容器被新版本替换时,您所有的数据都将丢失。容器旨在是短暂的,因此不要将您的数据保存在其中。
您可以通过使用专用的 PostgreSQL 应用程序数据库来避免所有这些问题。
如果您已经开始使用默认的 H2 数据库
没关系。但您应该尽快迁移到生产数据库。
Metabase 应用程序和数据库服务器及其大小调整
我们建议您至少运行两个实例(最好在同一个网络上)
- 一个或多个 Metabase 应用程序实例.
- 一个用于 Postgres 或 MySQL Metabase 应用程序数据库的数据库实例,Metabase 将在此处存储其应用程序数据。我们建议该数据库实例仅用于 Metabase 应用程序数据库,不用于任何其他目的。
您希望在同一网络上运行这些实例的原因是为了减少 Metabase(应用程序)从存储其应用程序数据的数据库获取响应所需的时间。绝大多数 Metabase 操作都需要调用 Metabase 的 API,该 API 使用应用程序数据库来检索有关问题、仪表板、表元数据等信息。
Metabase 应用程序服务器大小
Metabase 至少需要 1 个核心和 1GB RAM 作为基线。除此之外,每有 20 个并发用户使用您的 Metabase,Metabase 将需要 1 个 CPU 和 2GB RAM。这些系统建议适用于您运行 Metabase 作为 JAR 或容器镜像。例如,如果您有 40 个并发用户,您将总共需要 3 个 CPU 核心和 5GB RAM。
注意:在 v52 之前,我们建议每 20 个并发用户只需要 1GB 内存,但为了安全起见,我们在新版本中提高了此要求。
Metabase 应用程序数据库服务器大小
应用程序数据库可能是整个架构中最重要的组件:它是单点故障,应用程序数据库返回 Metabase 应用程序服务器查询的速度越快越好。作为起点,为运行应用程序数据库的服务器分配 1 个 CPU 核心和 2GB RAM。一般而言,每有 40 个并发用户使用您的 Metabase,PostgreSQL 应用程序数据库将需要 1 个 CPU 核心和 1 GB RAM。
每个 Metabase 环境都必须有自己的专用应用程序数据库
我们所说的环境是指一个或多个 Metabase jar(或容器镜像)以及一个应用程序数据库。如果您运行多个环境,您可以在同一个应用程序数据库服务器上运行多个应用程序数据库,每个环境一个,但每个环境都必须有自己的专用应用程序数据库。
维护
保持顺利运行。
Metabase 服务器维护
您无需执行任何操作。它应该可以正常工作。
Metabase 应用程序数据库维护
所有数据库都需要维护以获得最佳性能,PostgreSQL 和 MySQL 也不例外。请遵循 PostgreSQL 的维护最佳实践(https://postgresql.ac.cn/docs/current/maintenance.html)(特别是备份)。
此应用程序数据库应:
- 每天备份。
- 每周进行 VACUUM 和 ANALYZE。
此外,不再需要的卡片和仪表板应定期归档和删除。
数据仓库服务器维护
数据仓库的维护取决于您使用的数据仓库。请参阅数据库的文档以获取指导。
示例负载测试
在此简单负载测试中,Metabase API 在 K6 上记录了以下指标。
- 红色:性能差
- 绿色:性能良好
指标/系统 | 2 核 / 2GB RAM | 3 核 / 3GB RAM | 4 核 / 4GB RAM | 8 核 / 8GB RAM | 16 核 / 16GB RAM |
---|---|---|---|---|---|
处理的总请求数 成功处理的 Web 请求总数 |
278,303 | 303,420 | 311,740 | 311,350 | 313,625 |
每秒请求数 系统每秒可以处理多少请求(越高越好) |
121.3 请求/秒 | 132.0 请求/秒 | 136.2 请求/秒 | 135.8 请求/秒 | 136.1 请求/秒 |
平均响应时间 获得响应平均需要多长时间(越低越好) |
78.59ms | 38.89ms | 26.82ms | 27.45ms | 24.46ms |
最慢的 10% (p90) 最慢的 10% 请求至少需要这么长时间 |
204.97ms | 88.58ms | 66.00ms | 66.73ms | 65.78ms |
最慢的 5% (p95) 最慢的 5% 请求比这更长 |
389.85ms | 118.88ms | 81.79ms | 83.01ms | 76.72ms |
接收数据时间 发送请求后接收数据的时间 |
6.16ms | 2.54ms | 1.56ms | 1.52ms | 1.62ms |
发送数据时间 发送请求到服务器所花费的时间(通常非常快) |
16.74µs | 17.46µs | 15.07µs | 16.04µs | 17.79µs |
等待响应时间 发送请求和接收响应之间的延迟 |
72.41ms | 36.32ms | 25.24ms | 25.90ms | 22.82ms |
每次迭代测试持续时间 一次测试迭代完成的总时间 |
30.92秒 | 28.36秒 | 27.57秒 | 27.62秒 | 27.42秒 |
总迭代次数 测试完全完成的次数 |
4,273 | 4,666 | 4,796 | 4,790 | 4,825 |
接收数据总量 测试期间下载的数据量 |
16GB | 17GB | 17GB | 17GB | 17GB |
发送数据总量 测试期间上传的数据量 |
103MB | 112MB | 115MB | 115MB | 116MB |
负载测试的一些背景信息
- 此负载测试在具有 (Ryzen 7840HS) 的笔记本电脑上使用 Metabase v53.5 运行,更改了分配给 Metabase 容器的 CPU 核心和 RAM,并设置了最高电源配置文件。
- 为了给非堆内存留出一些空间,我们使用环境变量
JAVA_TOOL_OPTIONS: -Xmx<80% of total RAM>m
配置了 Metabase。 - 应用程序数据库是 Postgres 17 版,配备 2 核和 8GB RAM。
- 无 HTTPS。
- 我们执行此特定负载测试时使用的资源少于我们建议的资源(对于 100 个并发用户,我们建议使用 6 个核心和 11GB RAM)。我们故意使用较少的资源,以表明当应用程序有足够的内核和内存可用时,即使流量激增,应用程序也能承受,而不会显著降低性能。
- 尽管此负载测试检查了多个 API 端点,但它**没有**测试 CPU/内存密集型操作,例如 X-Rays,或异步操作,例如订阅、警报、数据库同步或数据库扫描/指纹识别。
然而,负载测试无法模拟真实使用情况。人们在 Metabase 中的活动将生成不同的 API 调用模式。您还将有异步进程在后台运行。如果 Metabase 缺少足够的 CPU 资源,它将对操作进行排队并开始消耗更多内存。如果队列溢出,Metabase 可能会在尝试处理所有请求时崩溃。在这种情况下,您将需要分配更多的核心和更多的内存。
异步进程
Metabase 会定期运行异步进程,这些进程会根据表的数量和表中的列数使用 CPU 和 RAM。
这些过程是:
- 同步
- 扫描
- 指纹识别
- 字段值
- 模型缓存
- 问题元数据
如果您发现 Metabase 在某个时间段内使用了大量 CPU,请检查日志以查看 Metabase 是否正在运行这些进程。如果是,您可以安排这些任务在人们不使用 Metabase 时运行。
Metabase 将为每个任务分配一个核心。如果您的服务器有四个核心,Metabase 将运行的最大异步进程数为三个,因为一个核心应该可用于处理人们的请求(一个核心应该能够同时处理大约 10 个人使用 Metabase 的请求)。
可观察性和一些要监控的指标
Metabase 公开了一个可由 Prometheus 抓取的指标端点。理想情况下,您应该设置一些警报,以便在任何这些数字超过阈值时采取行动。
Metabase 应用程序
- API 响应时间
- CPU:最大 80%-90%
- RAM:最大 80%
Metabase 应用程序数据库
- CPU:最大 90%
- RAM:最大 80%
- 磁盘使用量:最大 80%。
- 磁盘 IOPS:检查您的磁盘的 IOPS 支持。如果您用于运行应用程序数据库的磁盘超过了其声称支持的 IOPS,那么您的磁盘将对操作进行排队,这将影响性能。
何时增加连接池大小
默认情况下,Metabase 的连接池大小限制为 15 个连接。Metabase 将为每个连接的数据库管理一个池,包括一个应用程序数据库池,每个池限制为 15 个连接。
为了处理更多并发使用您 Metabase 的用户,您可以使用 MB_APPLICATION_DB_MAX_CONNECTION_POOL_SIZE
环境变量覆盖应用程序数据库的连接限制。如果您增加此限制,您可能需要为应用程序数据库提供更多 RAM,因此您应该监控应用程序数据库的 RAM 使用情况。如果数据库缺乏可用 RAM,数据库将对连接进行排队,这意味着一些用户在等待 RAM 释放时会发现 Metabase 无响应。
Metabase 只使用它在任何给定时间所需的连接。但有些请求可能会占用许多这些连接。例如,如果有人加载了一个包含 20 张卡片的仪表板,Metabase 将使用其 15 个可用连接来检索结果,并在连接可用时加载其余的五张卡片。
使用负载均衡器
一个好的架构实践是在 Metabase 之上使用负载均衡器,即使您只有一个服务器在运行,并且没有进行任何横向扩展。稍后部署负载均衡器可能更难实现,并且负载均衡器还可以执行 TLS 终止(也称为加密和解密 HTTP 流量)、WAF(Web 应用程序防火墙)、重定向和其他常见任务。
请参阅简单的负载均衡。
日志
Metabase 会生成您应该保留的应用程序日志。这些日志对于调试和审计非常有用。请查看我们关于日志配置的文档。
如果您还在 Metabase 之上部署了负载均衡器或反向代理,我们建议您将这些日志保存到日志聚合器。这些日志将帮助您识别模式并在需要时进行调查。
通过 HTTPS 运行 Metabase
您可以在不使用负载均衡器或反向代理的情况下通过 HTTPS 提供 Metabase。
请注意,如果您使用同一台服务器运行 Metabase 和 TLS 终止(即 HTTPS),Metabase 将损失用于加密/解密流量的宝贵 CPU 资源。因此,您可能希望使用负载均衡器。
避免的陷阱
从他人的经验中学习。
我们建议您避免那些声称能够自动扩展的服务
根据我们的经验,许多声称能够自动扩展的服务,嗯,并不神奇。我们反而建议您部署一些可观测性指标,监控它们,并根据这些观测结果进行必要的扩展更改,因为您的 Metabase 使用量将随着您公司的发展而增长。
避免在不使用服务器时关闭服务器的服务
如果您必须使用自动扩缩服务,请避免任何在服务器不使用时定期关闭服务器的服务。
原因有二:
- 异步进程。Metabase 运行一些异步进程,例如获取表的元数据,或刷新模型,或获取筛选值。如果这些进程无法运行,人们将无法看到 Metabase 提供的许多功能。
- 启动时间。第二天首次登录您应用程序的人员将遭受巨大的性能损失,因为服务器将不得不从完全冷启动开始。
在其他云提供商上运行的问题
只需注意一点:许多云服务提供商会把您托管在共享基础设施上。在这种情况下,租户共享对 CPU 的访问。多租户服务器租金可能更便宜,并且可以提供不错的性能,前提是您的 CPU 使用率保持在 100% 以下。如果您的 Metabase 服务器在一段时间内使用 100% 的 CPU,提供商可能会限制您分配的 CPU 性能,您的性能将显著下降。共享基础设施中的磁盘 IOPS 也会发生相同的限制。
升级到 Metabase 的新主版本
通常,我们不会在次要版本之间(例如,从 1.51.1 到 1.51.2)对应用程序数据库的架构进行任何更改,因此您可以在次要版本之间进行升级和降级而不会出现问题。
升级到主要版本(例如,从 1.50.9 到 1.51.3)时,您应该预计会有一些停机时间,因为 Metabase 可能需要处理应用程序数据库的架构更改。架构更改所需的时间取决于您的应用程序数据库的大小。