4

我正在使用 Cloud Run 创建数据提取管道。每次通过 Pub Sub 将文件放入 GCS 存储桶时,都会调用我的 Cloud Run api。我需要加载一些元数据,其中包含我正在摄取的数据的文本。此元数据很少更改。我显然不想在每次执行时将它重新加载到内存中。我最好的选择是什么?到目前为止,我能够研究的是:

选项1

如果在每个服务请求上重新创建对象的成本很高,您也可以将对象缓存在内存中。将其从请求逻辑转移到全局范围会带来更好的性能。 https://cloud.google.com/run/docs/tips#run_tips_global_scope-java

在此链接给出的示例中,是否仅在冷启动时调用了一次重计算函数?如果我需要在元数据更新时偶尔重新触发此功能怎么办。我还发现以下信息令人不安,因为它似乎说不能保证其他实例会重用该对象。

在 Cloud Run 中,您不能假设在请求之间保留服务状态。但是,Cloud Run 确实会重用单个容器实例来服务持续的流量,因此您可以在全局范围内声明一个变量,以允许在后续调用中重用其值。无法提前知道任何单个请求是否会从这种重用中受益。

选项 2

使用 Redis 或 Cloud Memory Store 之类的东西,只要有更改,就会由云功能更新。并且所有的云运行 api 实例都从 Redis 中拉取元数据信息。这会比选项 1 性能更低还是更高?这还有其他不利方面吗?

如果还有其他更好的方法可以做到这一点,我会非常感兴趣。

更新 1:我想了更多,因为我的元数据对于每个租户都是不同的,而且我的云运行代码的每次调用都会为一个租户摄取一个文件,加载所有租户是个坏主意每次执行时的元数据,即使它被缓存。不过,我可能会在每个租户的项目中运行单独的云运行。

4

2 回答 2

2

关于第一个选项(选项 1):

此处heavyComputation()函数只会在冷启动时调用,每次创建新的Cloud Run 容器实例时(当超过可以并行发送到给定容器实例的最大请求数并因此创建新实例时)。

为了解决第二个选项(选项 2):

截至目前,Cloud Run(全托管)不支持无服务器 VPC 访问,因此无法连接到 Cloud Memorystore。监控以下功能请求以从 Cloud Run 产品团队获取所有相关信息和更新,以检查此功能何时可用。

您可以在这篇文章和已经提到的功能请求中找到一些解决方法。它们基本上包括:

  1. 将 Google Kubernetes Engine 集群与 Cloud Run 结合使用
  2. 在 Compute Engine 上设置 Redis 实例。
于 2019-12-24T11:52:39.270 回答
1

我们从您的初始前提开始,即“我显然不想在每次执行时将其重新加载到内存中”。对我来说,这并不总是正确的说法。如果我实现了一种缓存技术,那么作为一名程序员,我会花时间把它做好,并引入错误和维护的机会。如果我每次执行节省了 100 毫秒,那么与增加执行时间所节省的成本相比,需要多少数千次执行才能实现收支平衡?我通常会预先采取最简单的方法,并准备好监控未来的运营,并仅在必要时进行改进。

综上所述,让我们假设您已经确定每秒将发出无数个新文件创建请求并希望进行优化。了解如何最好地使用 Cloud Run 的关键在于它运行一个可以处理并发请求的整个容器。我相信默认是 80。这意味着如果创建了 80 个并发文件,则只会创建一个容器实例并处理 80 个并行事件。如果您使用 Java 进行编码,这意味着 80 个并发线程都在同一个 JVM 中。每个线程将对公共全局变量具有并发寻址能力。只有当第 81 个请求到达并且之前的 80 个请求都没有完成时,才会生成新的 Cloud Run 容器。

这告诉我的是,我的第一个“改进”是在第一次使用时在我的 JVM 中填充缓存数据,并将其保留以供后续重用。您何时填充缓存数据?这将是您的设计选择。您可以在容器首次启动时预先填充所有内容......如果您知道数据将用于每个请求,这将是明智的。或者,如果您有多个可缓存的值,请考虑创建一个包含您的名称/值对的映射,并具有一个返回缓存值(如果存在)或从慢速存储、缓存和返回值(如果最初不存在)的访问器)。

于 2019-12-23T21:32:21.050 回答