上传是极狐GitLab 许多功能不可或缺的一部分。为了帮助理解极狐GitLab 如何处理上传,本页面概述了将文件传输到存储目标的关键机制。
极狐GitLab 上传是按功能配置的。所有涉及上传的功能都提供相同的配置选项,但它们可以彼此独立配置。例如,Git LFS 上传可以独立于 CI/CD 构建产物上传进行配置,但它们都提供相同的设置键集。这些设置决定了上传的处理方式,这可能会对性能和可扩展性产生重大影响。
本页面总结了在决定如何处理此类文件时很重要的上传设置。接下来的章节将更详细地描述每种机制。
上传设置如何驱动上传流程#
在更详细地研究各个上传策略之前,我们先从高层次看一下哪些上传设置映射到这些策略。
上传设置本身在上传管理中有文档说明。这里,我们关注这些设置如何驱动极狐GitLab 上传逻辑的内部机制。在顶层,我们区分上传文件的两种 目的地:
本地存储 - 文件存储在 Web 服务器节点挂载的卷上。
对象存储 - 文件存储在远程对象存储桶中。
在这个表格中,x.y.z 指定了通过 gitlab.yml 的路径:
设置值行为
使用对象存储时,管理员可以控制这些文件如何移入相应的存储桶。这种移动可以通过以下方式之一进行:
Rails 控制器上传。
直接上传。
各个 Sidekiq 工作器也可能将文件存储在对象存储中,这不是此处讨论的范围。
最后,Workhorse 使用上传缓冲机制来协助大多数用户发起的上传,以将慢速工作从 Rails 控制器中移出。此机制在 Workhorse 辅助上传 中进行了说明,因为它与之前讨论的内容很大程度上是正交的。
现在我们更详细地讨论每种情况。
本地存储#
本地存储是上传可以采用的最简单路径。这是极狐GitLab 早期处理上传的方式。它假设 Rails 应用程序可以在 storage_path 访问到一个存储卷(如磁盘或网络附加存储)。此文件路径相对于 Rails 根目录,并且像任何上传设置一样,可以按功能配置。
当客户端发送文件上传请求时,Workhorse 首先将文件缓冲到磁盘,该机制在 Workhorse 辅助上传 中有更详细的说明。当请求到达 Rails 应用程序时,文件已经存在于本地存储中,因此 Rails 只需将其移动到指定目录即可完成事务。
本地存储不能用于云原生极狐GitLab (CNG) 安装。因此,它也不用于 JihuLab.com。
对象存储#
为了提供水平可扩展的存储,你必须使用对象存储提供商,例如:
Amazon AWS。
Google Cloud Storage (GCS)。
Azure Cloud Storage。
使用对象存储有两个主要好处:
轻松增加更多存储容量:云提供商自动为你完成此操作。
启用极狐GitLab 安装的水平扩展:当数据存储在对象存储中时,多个极狐GitLab 应用服务器可以访问相同的数据。
包括 JihuLab.com 在内的 CNG 安装始终使用对象存储(在 JihuLab.com 的情况下使用 GCS)。
上传到远程对象存储的一个挑战是,它包括从极狐GitLab 到对象存储提供商的一个传出 HTTP 请求。如上所述,发送此 HTTP 请求有三种不同的策略可供选择。
Rails 控制器上传。
直接上传。
Workhorse 辅助上传。
Rails 控制器上传#
当直接上传不可用时,Rails 将文件作为控制器 create 操作的一部分上传到对象存储。哪个控制器负责取决于上传的文件类型。
Rails 控制器上传与上传到本地存储非常相似。主要区别在于:Rails 必须向对象存储发送一个 HTTP 请求。这通过 CarrierWave Fog 上传器完成。
与本地存储一样,此策略受益于 Workhorse 的辅助,以将一些耗时的 I/O 工作移出 Ruby 和 Rails。直接上传在这方面做得更好,因为它还将到对象存储的 HTTP PUT 请求保持在 Puma 之外。
此策略仅适用于小文件上传,因为它受 Puma 的 60 秒请求超时限制。
直接上传#
在像 JihuLab.com 这样的 CNG 安装中,直接上传是将大文件移入对象存储的推荐方式。
启用直接上传后,Workhorse 会:
向 Rails 授权请求。
与对象存储本身建立连接,将文件传输到临时位置。
传输完成后,Workhorse 向 Rails 完成请求。
通过删除对象存储中的临时文件完成上传。
此策略是 Workhorse 辅助 的另一种形式。它不依赖于 Workhorse 和 Puma 都可访问的共享存储。
在所有现有的上传策略中,直接上传最适合处理大(千兆字节)上传。
磁盘缓冲上传#
当 direct_upload 在对象存储设置中被禁用时,直接上传回退到 磁盘缓冲上传。/authorize 调用的响应只包含一个文件系统路径。
Rendering chart...
Workhorse 辅助上传#
所有接受文件内容的 REST 和 GraphQL API 都必须使用 Workhorse 辅助上传。
Workhorse 可以以多种方式提供帮助:
通常,Workhorse 将上传缓冲到临时文件。Workhorse 向请求添加元数据,以告诉 Puma 临时文件的名称和位置。这需要 Workhorse 和 Puma 之间的共享临时存储。所有极狐GitLab 安装(包括 CNG)都有此共享临时存储。
Workhorse 有时会预处理文件。例如,对于 CI 产物上传,Workhorse 会创建 ZIP 文件内容的单独索引。通过在 Workhorse 中执行此操作,我们绕过了 Puma 请求超时。与 Sidekiq 后台处理相比,这样做的优点是用户不会看到 GitLab 已接受文件但尚未处理的中间状态。
通过直接上传,Workhorse 既可以预处理文件,也可以将其上传到对象存储。将大文件上传到对象存储需要时间;通过在 Workhorse 中执行此操作,我们避免了 Puma 请求超时。
要实现 Workhorse 辅助上传,你必须:
在 workhorse/internal/upstream/routes.go 中使用 mimeMultipartUploader 或 requestBodyUploader 添加路由。
在你的 API 类中创建一个 /authorize 端点。该端点必须:
调用 require_gitlab_workhorse!
返回状态 200,内容类型为 Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
在上传器类上调用 workhorse_authorize
创建接收文件的上传端点。该端点必须:
调用 require_gitlab_workhorse!
对文件使用参数类型 ::API::Validations::Types::WorkhorseFile
声明可选的文件元数据参数(路径、名称、类型、大小、校验和)
使用包含 ObjectStorage::Concern 的适当上传器类。
完整实现示例请参见 lib/api/project_import.rb。
有关上传的更多信息,请参见 Workhorse 处理器。