长读。
从我的角度来看,这是一个非常大的问题。解决方案不仅需要代码开发,还需要大量的设计思考和决策(包括一些妥协)。
根据我的个人经验(我开发了两次这样的解决方案,在生产中维护它等),可以将云功能与一组 GCP 资源一起使用 - 秘密管理器、pubsub 主题、firestore 集合、服务帐户和 IAM等等...根据您的要求(我不知道详细信息)和上下文 - 您可能需要创建一个由一些(假设在两个到五个之间)不同的云功能组成的功能组件。二、如果您的文件较小(每个最多100M),每天的文件数量不大(几千或几万个文件),并且您有权在下载后从SFTP服务器上删除原始文件。
如果您没有这样的权限 - 应该有一些其他进程可以清理“旧”或“已下载”文件。否则,最终解决方案将无法工作(当仅下载文件列表,而不是文件,而只是文件列表时,需要超过 540 秒)。
SFTP 是一个“被动”组件 - 如果有新文件到达,它不会通知我们,因此我们这边应该有一些“主动”组件来发起与 SFTP 服务器的连接。这是一种“拉动”交互,并且有规律性(即每 10 分钟、15 分钟或 20 分钟)连接到 SFTP 服务器并检查是否有任何新内容可供下载。
下一个。云函数是幂等的,不可能仅在云函数中存储/保留文件下载的状态。应该有一些外部(相对于云功能)服务来维护每个文件下载过程的状态机。我使用了 Firestore。它非常方便并且延迟非常小。 firestore 集合中的每个文档都代表“文件下载过程”的反映 - 一个状态机以及大量元数据、状态转换历史记录等。
Cloud Functions 有 2 个重要限制:
- 540 秒超时。
- 2GB 内存。
这意味着下载过程(以及任何其他活动)不应超过 540 秒。如果要将任何数据存储在(云功能的)内存中,则数据块应小于 2Gb。
超时限制会影响进程吗? - 是的,它可以。整个过程的瓶颈是SFTP服务器和GCP存在点之间的“带宽”。文件越大 - 下载所需的时间越长,尤其是在并行下载许多文件时。
因此,很快该算法将按以下方式工作:
1/ 第一个云函数每隔 15 分钟触发一次(云调度程序 => PubSub 主题 => 云函数)。云功能读取所有 SFTP 连接和所有数据管道的配置(即来自 GCS 存储桶的 json 文件)(因为该组件可能与许多 SFTP 服务器一起使用,并且对于每个 SFTP 服务器可能有许多数据管道),然后从Secret Manager(对于每个 SFTP 服务器),然后连接到 SFTP 服务器,并下载每个连接/管道的可用文件列表。因此,对于我们知道的每个文件 - 连接(SFTP 服务器)、管道(即源目录)、文件名、文件大小、文件修改时间戳。我对 SFTP 服务器不再抱有任何期望。对于每个连接和数据管道,我们都会编写一个文件列表(取决于配置,并且应该是灵活的),最多可包含 5、8 或 10,000 个文件。该列表作为 json 结构被作为消息推送到 PubSub 主题(如果需要,还可以包含一些附加元数据)。因此,如果我们有 2 个 SFTP 服务器,每个服务器中有 3 个管道,则至少会有 6 条消息。如果 SFTP 服务器中的目录包含超过 5K、8K 或 10K 文件,则可能会更多。此时,我们不知道这些文件是否已下载,或者下载过程正在进行中,或者已经失败,或者这是一个新文件。
部署此函数时 - “最大实例数”参数的值为 1。
2/ 第二个云功能由包含文件列表的 PubSub 消息触发(对于某些 SFTP 服务器和某些管道)。对于传入列表中的每个文件,云功能应该决定要做什么:
- 这是一个新文件,应该下载它。
- 下载正在进行中,我们需要等待更多 - 什么也不做。
- 这是一个已经下载的文件,我们什么也不做。
- 这是正在下载,但时间太长 - 可能下载崩溃了,应该重新下载。
- 这是……可能还有更多的情况需要处理……
现在需要 firestore 集合。集合中的每个文档 - 反映该文件发生的情况;所有内容都记录在那里 - 下载过程何时开始、何时(或是否)完成等等。文档 ID 是基于可用元数据计算的哈希值 - 连接(SFTP 服务器)、管道(即源目录)、源文件名、源文件大小、源文件修改时间戳。所有这些都来自于消息。
例如,我们计算哈希并检查集合中是否存在此类文档。如果不存在 - 创建一个新文档,因为这是一个可供下载的全新文件。然后编写一条 json 消息并将其推送到第二个 PubSub 主题中 - 下一个云函数将对其进行处理。如果它存在 - 有必要决定我们将如何处理它 - 不执行任何操作(因为它已经下载,或者因为下载可能仍在进行中)或再次触发其下载 - 编写一条 json 消息并推送它进入第二个 PubSub 主题...
部署此函数时,“最大实例数”参数的值介于 4 到 12 之间(根据我的经验)。
3/ 第三个云功能由 PubSub 消息触发,其中包含要下载的文件的详细信息。需要完成以下步骤:
- 检查该文件没有被其他云功能下载
- 更新 firestore 文档 - 我们开始下载过程
- 获取配置详细信息(来自 GCS 中的 json 文件)
- 获取连接详细信息(来自 Secret Manager)
- 连接和下载
- 将下载的文件保存到目标GCS存储桶中
- 更新 firestore 文档 - 我们完成了下载过程
部署此函数时,“最大实例数”参数的值介于 10 到 30 之间(根据我的经验)。
这是一个非常简短的描述,基于最简单的假设(即您没有大于 100Mb 的文件或/并且连接良好)。
一些额外的事情要记住。
1/ 准确的记录。具有一致字段的Json结构将被定期记录。我建议创建一个接收器,以便可以在 BigQuery 表中分析日志。
2/ 服务帐户和 IAM。所有这些都应该在仅用于给定组件的自定义服务帐户下运行。将提供相关的 IAM 角色。
3/ 云 NAT。 SFTP(根据我的经验)仅适用于特定的静态 IP 地址(它们不允许来自任何地址的连接)。因此,网络、子网、IP 地址、路由器、NAT——所有这些都需要创建和配置。 IP 地址将提供给 SFTP 服务器所有者,以允许访问。要使用“vpc 连接器”参数部署的云函数。
4/ 进度和监控 - 3 个信息源 - firestore 收集、Stackdriver 日志、BigQuery 表。
再说一遍,这是我内心深处的一个非常简单的描述。如果您有具体问题或想讨论,请告诉我。