【问题标题】:Cloud Run: Why does my instance need so much RAM?Cloud Run:为什么我的实例需要这么多 RAM?
【发布时间】:2020-05-05 19:41:13
【问题描述】:

我有一个在 400MB SQLite 文件上运行 SQL 查询的 Golang 进程。

我将https://github.com/mattn/go-sqlite3 与连接字符串一起使用:

file:mydb.sqlite?mode=ro&_journal=DELETE

在我的 Docker 开发机器上运行时,它只需要 20MB 的 RAM,但在 Google Run 上,任何小于 512MB 的实例都会在日志中返回 HTTP 代码 500,并带有 memory exceeded 限制。

docker diff x 表明 DB 文件没有被修改(我认为这会导致 gVisor 将整个二进制 SQLite db 文件复制到 RAM 以对其进行修改)。

docker 镜像是如何构建的

我正在将 SQLite DB 文件复制到带有源代码的图像中:

FROM golang:latest
...
COPY . /go/src/api

我的 Golang 文件中有一个全局变量:var db *sqlx.DB

这在主 fn 中设置,在 ListenAndServe 之前:

conStr := fmt.Sprintf("file:%s?mode=ro&_journal=DELETE", *fileName)
dbConn, err := sqlx.Open("sqlite3", conStr)
db = dbConn

我在 HTTP 请求中查询数据库:

err := db.Selectv(&outDataSet, "SELECT...", arg1, arg2)

为什么这一定是 Cloud Run 环境的问题

docker stats 在本地运行时永远不会超过 20MB。

docker run 限制为 20MB RAM 在我的开发机器上也可以正常运行:

docker run \
  --memory=20m \
  --memory-swap=20m \

Cloud Run“容器内存分配”指标也远低于 128M:

https://console.cloud.google.com/monitoring/metrics-explorer

谢谢。

【问题讨论】:

  • 我不确定您在本地运行时是否正确测量了容器内存。您不能仅在 20Mb 中加载 400Mb 文件!
  • 我没有将 400MB 文件加载到 RAM 中,我在其上运行 SQLite SELECT 查询,它只返回一小部分数据。 SQLite 是基于磁盘的存储,我假设它不会将数据集加载到内存中。
  • 如果您投反对票,请留下评论解释原因。
  • @zino,您能否详细说明如何构建容器并分享启动时完成的操作(您的 go 代码)。我会尽力向你解释发生了什么。 注意:我没有投票,很少有人问这个问题,其他人只是设置工作记忆。你的问题很好!
  • 这是一个建议。在打开 SQLite 数据库之前,请检查容器内的可用内存。然后打开数据库。再次检查内存。这应该给你一个线索。在容器中,文件存储在只读层中。打开文件时,会创建一个新图层。新层至少占用您正在打开的文件的大小并且在内存中。对于只读文件,这不是必需的,但我无法通过 gVisor 了解实现细节。

标签: sqlite go google-cloud-platform google-cloud-run gvisor


【解决方案1】:

根据官方文档:

Configuring Memory Limits

超出允许的内存限制的 Cloud Run 容器实例 被终止。

以下内容计入容器的可用内存 实例:

a.运行应用程序可执行文件(因为必须加载可执行文件 记忆)

b.在应用程序进程中分配内存

c.写文件 到文件系统

部署的容器镜像大小不 计入可用内存。

另外我建议考虑:

Are your container instances exceeding memory?

您的容器实例可能超出了可用内存。到 确定是否是这种情况,在 varlog/系统日志。如果实例超出可用 内存,考虑增加内存限制。

请注意,Cloud Run 容器实例在环境中运行 写入本地文件系统的文件计入 有效内存。这还包括任何不属于 写入 /var/log/* 或 /dev/log。

您的容器文件系统似乎正在使用内存。

【讨论】:

  • 我认为这不是正确的答案,它是自动选择的。 SQLite 文件是容器映像的一部分,而不是运行时文件系统。容器镜像不占用运行时 RAM。我没有将数据集加载到 RAM 中,这是通过在运行良好的本地计算机上将 RAM 限制为 20MB 来证明的。
【解决方案2】:

在 Cloud Run(全托管)环境中,磁盘存储是内存中的文件系统。 link

【讨论】:

  • 我没有在运行时将任何文件写入磁盘,只使用 SQLite SELECT 查询从容器映像中读取。
猜你喜欢
  • 2020-07-10
  • 1970-01-01
  • 2019-02-17
  • 2012-01-18
  • 2021-05-12
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多