Firebase的云函数因超出内存限制而被终止。

60

当我转换一张相对较小的图片(2mb)时,Firebase云函数经常会出现间歇性错误。成功时,该函数只需要大约2000毫秒或更短的时间就能完成,并且根据Image Magick文档,我不应该看到任何问题。

我尝试增加命令的缓冲区大小,但Firebase不允许这样做,我还尝试寻找替代.spawn()的方法,因为它可能会被垃圾卡住而使速度变慢。但是没有一个方案奏效。


1
所有信息都在这里:管理函数 - GeneRator
更具体地说,在这里:#set_timeout_and_memory_allocation - Blundering Philosopher
1
增加内存的简易指南 - https://dev59.com/Na_la4cB1Zd3GeqPyMmx#69653948 - danday74
10个回答

73
你可以在 Firebase 的 Cloud Function 文件中进行设置。
const runtimeOpts = {
  timeoutSeconds: 300,
  memory: '1GB'
}

exports.myStorageFunction = functions
  .runWith(runtimeOpts)
  .storage
  .object()
  .onFinalize((object) = > {
    // do some complicated things that take a lot of memory and time
  });

从这里的文档中提取: https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation

别忘了从终端运行firebase deploy


4
为了保持一致性,这个回答应该被接受。有些人回答使用命令行,如果你在一个团队项目中或者项目发生变化时,这并不好。 - Oliver Dixon
7
import { VALID_MEMORY_OPTIONS } from 'firebase-functions'; 这行代码是用于导入 Firebase Functions 中的 VALID_MEMORY_OPTIONS 常量。接下来,VALID_MEMORY_OPTIONS['1GB'] 返回的是一个 TypeScript 类型,表示内存选项中可用的最大值为 1GB。 - Ruben
1
这应该是最好的答案,这是最简单的,具有未来性,不需要维护,一劳永逸的方法。 - Acid Coder
除非我也按照@p3sn给出的答案,否则对我没有用。 - danday74

66

我在用户界面中迷失了方向,找不到更改内存的选项,但最终找到了:

  1. 进入Google Cloud平台控制台(非Firebase控制台)
  2. 在菜单中选择Cloud Functions
  3. 如果正确,现在您会在这里看到您的Firebase函数。否则,请检查您是否选择了正确的项目。
  4. 忽略所有复选框、按钮和菜单项,只需点击函数名称
  5. 单击编辑(顶部菜单),仅更改分配的内存并单击保存。

1
哪个“顶部菜单”?我只看到“创建函数”,“刷新”,“删除”和“复制”。也许需要付费账户才能看到? - CodyBugstein
1
你真是个救星!谷歌云平台上的那个函数控制台太棒了! - Kushagra Gour
请注意,每次部署函数时这些设置都将被重置。请使用 functions.runWith({})。https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation - Yair Levi
3
然后它强制我点击“下一步”,然后我必须指定一个“源代码”。这对我来说没有意义。我已经上传了这个函数的源代码。为什么我还要指定另一个,哪一个可以让它只使用最初的源代码? - pete

23

[更新] 正如一位评论者所建议的那样,这不再是一个问题,因为Firebase函数现在可以在重新部署时保留它们的设置。谢谢Firebase!

事实证明,这并不明显或者有记录可循,你可以在Google Functions控制台中增加函数的内存分配。你也可以增加长时间运行函数的超时时间。这解决了内存超载的问题,现在一切正常工作。

编辑:请注意,Firebase会在部署时重置默认值,所以您应该立即登录到控制台并更新它们。我仍在寻找一种通过CLI更新这些设置的方法,找到后将进行更新。


我找不到增加函数内存分配的地方。在函数控制台中应该去哪里?谢谢! - Walucas
1
@Walucas 云函数 > {您的函数名称} > 点击“编辑” > 然后编辑“内存分配”中的数字。 - Kirill
我的函数设置又被重置了。 - El Yobo
10
增加内存对价格的影响是怎样的? - Pier
2
您还可以通过编程方式设置超时和内存分配(https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation)。 - opyate

13

最新的Firebase部署命令会将内存分配覆盖为默认的256MB,并将超时时间延长至60秒。

另外,为了指定所需的内存分配和最大超时时间,我使用gcloud命令,例如:

gcloud beta functions deploy YourFunctionName --memory=2048MB --timeout=540s

其他选项,请参考:

https://cloud.google.com/sdk/gcloud/reference/beta/functions/deploy


11
你可以在这里调整你的内存:

输入图像描述


这是唯一真正有效的解决方案!UI不再允许您更改内存。它似乎可以,但然后它要求您点击“下一个”按钮而不是“保存”按钮。保存内存更改的唯一方法是上传新的函数源代码,这当然没有意义,因为函数的源代码已经存在,否则该函数就不会首先出现在表中。 - pete
这是迄今为止2020年唯一且最佳的解决方案。 - Hoon

9

1
这个不再起作用了,因为它要求重新上传源代码! - Ayyappa
为什么在改变内存使用时,它要求另一个源代码并且需要它?难道不是已经从firebase deploy上传了源代码吗?这毫无意义! - pete

5
更新:看起来他们现在可以在重新部署时保留设置,因此您可以安全地在云控制台中更改内存分配!

哦,好消息!我已经有一段时间没有重新部署了,为了避免出现任何问题。我会在一个测试项目上尝试一下。如果它再次工作正常就太好了! - Kirill
更新:对我来说,它每次都在重置它们(并且由于在部署时超过内存限制而无法部署,这会创建一个尴尬的鸡和蛋问题)。 - El Yobo
截至2020年1月,重新部署时仍会保留设置。 - omeanwell

5

您可以在Firebase函数定义中添加配置,例如:

functions.runWith({memory: '2GB', timeoutSeconds: '360'})

1
似乎Firebase云函数中默认的ImageMagick资源配置与实际分配给函数的内存不匹配。
在Firebase云函数上下文中运行identify -list resource命令会产生以下结果:
File       Area         Memory        Map       Disk   Thread  Throttle       Time
--------------------------------------------------------------------------------
 18750    4.295GB       2GiB       4GiB  unlimited        8         0   unlimited  

默认分配给FCF的内存为256MB - 默认的ImageMagick实例认为它有2GB,因此不会从磁盘分配缓冲区,并且很容易尝试过度分配内存,导致函数失败并出现“错误:超出内存限制。函数终止。”。
一种方法是根据上面的建议增加所需的内存 - 尽管仍存在IM尝试过度分配的风险,具体取决于您的用例和异常值。
更安全的方法是在图像处理过程中将正确的内存限制设置为IM,使用“-limit memory [your limit]”。您可以通过使用“-debug Cache”运行IM逻辑来确定您的近似内存使用情况 - 它将显示所有分配的缓冲区、它们的大小以及它们是否是内存还是磁盘。
如果IM达到内存限制,它将开始在磁盘上分配缓冲区(内存映射,然后是常规磁盘缓冲区)。您必须考虑特定的I/O性能与内存成本之间的平衡。您分配给FCF的每个额外字节的内存价格乘以100毫秒的使用时间 - 因此这可能会迅速增长。

0

这里的另一个选择是避免使用.spawn()

有一个非常棒的用于Node的图像处理包,名为Sharp,它使用了低内存占用库libvips。你可以在Github上查看云函数示例。

或者,还有一个ImageMagick(和GraphicsMagick)的Node封装,名为gm。它甚至支持-limit选项,以向IM报告你的资源限制。


有趣。会试试Sharp。Google Cloud的问题在于你无法在本地真正测试任何东西,需要通过云代码推送每个更改。因此,即使有更好的解决方案,切换成本也很高。 - Kirill
1
你应该查看一些刚刚添加的新本地测试功能。现在你可以在本地测试触发函数并对它们运行单元测试。https://firebase.google.com/docs/functions/local-emulator#invoke_storage_and_auth_functions - Kiana
模拟器目前还不支持存储API。 - K20GH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接