Help us learn about your current experience with the documentation. Take the survey.

解决 Geo 同步和验证错误

  • Tier: Premium, Ultimate
  • Offering: GitLab Self-Managed

如果您在 管理 > Geo > 站点同步状态 Rake 任务 中发现复制或验证失败,可以尝试通过以下通用步骤解决这些问题:

  1. Geo 会自动重试失败。如果失败是新出现的且数量较少,或者您怀疑根本原因已经解决,可以等待观察失败是否消失。
  2. 如果失败持续了很长时间,已经进行了多次重试,并且自动重试的间隔时间已根据失败类型增加到最多 4 小时。如果您怀疑根本原因已经解决,可以手动重试复制或验证以避免等待。
  3. 如果失败仍然存在,请使用以下部分尝试解决。

手动重试复制或验证

次要 Geo 站点的 Rails 控制台 中,您可以:

重新同步和重新验证单个组件

在次要站点,访问管理 > Geo > 复制,强制重新同步或重新验证单个项目。

但是,如果这不起作用,您可以使用 Rails 控制台执行相同的操作。以下部分描述如何使用 Rails 控制台 中的内部应用程序命令来同步或验证单个记录的复制或验证。

获取 Replicator 实例

如果未在正确条件下运行,更改数据的命令可能会造成损坏。始终先在测试环境中运行命令,并准备好备份实例以进行恢复。

在执行任何同步或验证操作之前,您需要获取一个 Replicator 实例。

首先,根据您想要执行的操作,在次要站点启动 Rails 控制台会话

站点:

  • 您可以校验资源的校验和

次要站点:

  • 您可以同步资源
  • 您可以校验资源的校验和,并将其与主站点的校验和进行比较

接下来,运行以下代码片段之一来获取 Replicator 实例。

给定模型记录的 ID
model_record = Packages::PackageFile.find_by(id: 123)
replicator = model_record.replicator
给定注册表记录的 ID
  • 432 替换为实际 ID。注册表记录可能与它跟踪的模型记录具有相同的 ID 值,也可能不同。
  • Geo::PackageFileRegistry 替换为任何 Geo 注册表类

在次要 Geo 站点中:

registry_record = Geo::PackageFileRegistry.find_by(id: 432)
replicator = registry_record.replicator
给定注册表记录 last_sync_failure 中的错误消息
  • Geo::PackageFileRegistry 替换为任何 Geo 注册表类
  • error message here 替换为实际错误消息。
registry = Geo::PackageFileRegistry.find_by("last_sync_failure LIKE '%error message here%'")
replicator = registry.replicator
给定注册表记录 verification_failure 中的错误消息
  • Geo::PackageFileRegistry 替换为任何 Geo 注册表类
  • error message here 替换为实际错误消息。
registry = Geo::PackageFileRegistry.find_by("verification_failure LIKE '%error message here%'")
replicator = registry.replicator

使用 Replicator 实例执行操作

当您将 Replicator 实例存储在 replicator 变量中后,您可以执行许多操作:

在控制台中同步

此代码片段仅在次要站点中有效。

这会在控制台中同步执行同步代码,因此您可以观察同步资源需要多长时间,或查看完整的错误回溯。

replicator.sync

或者,使控制台的日志级别比配置的日志级别更详细,然后执行同步:

Rails.logger.level = :debug
在控制台中校验或验证

此代码片段在任何次要站点中都有效。

站点中,它会校验资源并将结果存储在主 GitLab 数据库中。在次要站点中,它会校验资源,将其与主 GitLab 数据库(由站点生成)中的校验和进行比较,并将结果存储在 Geo 跟踪数据库中。

这会在控制台中同步执行校验和验证代码,因此您可以观察需要多长时间,或查看完整的错误回溯。

replicator.verify
在 Sidekiq 作业中同步

此代码片段仅在次要站点中有效。

它会将作业排队给 Sidekiq 以执行资源的sync

replicator.enqueue_sync
在 Sidekiq 作业中验证

此代码片段在任何次要站点中都有效。

它会将作业排队给 Sidekiq 以执行资源的校验或验证

replicator.verify_async
获取模型记录

此代码片段在任何次要站点中都有效。

replicator.model_record
获取注册表记录

此代码片段仅在次要站点中有效,因为注册表表存储在 Geo 跟踪数据库中。

replicator.registry

Geo 数据类型模型类

Geo 数据类型是特定类别的数据,由一个或多个 GitLab 功能需要存储相关数据,并由 Geo 复制到次要站点。

  • Blob 类型
    • Ci::JobArtifact
    • Ci::PipelineArtifact
    • Ci::SecureFile
    • LfsObject
    • MergeRequestDiff
    • Packages::PackageFile
    • PagesDeployment
    • Terraform::StateVersion
    • Upload
    • DependencyProxy::Manifest
    • DependencyProxy::Blob
  • Git 仓库类型
    • DesignManagement::Repository
    • ProjectRepository
    • ProjectWikiRepository
    • SnippetRepository
    • GroupWikiRepository
  • 其他类型
    • ContainerRepository

主要的类类型是注册表(Registry)、模型(Model)和复制器(Replicator)。如果您拥有其中任何一个类的实例,就可以获取其他类。注册表和模型主要管理 PostgreSQL 数据库状态。复制器知道如何复制或验证非 PostgreSQL 数据(文件/Git 仓库/容器仓库)。

Geo 注册表类

在 GitLab Geo 的上下文中,注册表记录指的是 Geo 跟踪数据库中的注册表表。每条记录跟踪主 GitLab 数据库中的单个可复制对象,例如 LFS 文件或项目 Git 仓库。与可查询的 Geo 注册表表对应的 Rails 模型有:

  • Blob 类型
    • Geo::CiSecureFileRegistry
    • Geo::DependencyProxyBlobRegistry
    • Geo::DependencyProxyManifestRegistry
    • Geo::JobArtifactRegistry
    • Geo::LfsObjectRegistry
    • Geo::MergeRequestDiffRegistry
    • Geo::PackageFileRegistry
    • Geo::PagesDeploymentRegistry
    • Geo::PipelineArtifactRegistry
    • Geo::ProjectWikiRepositoryRegistry
    • Geo::SnippetRepositoryRegistry
    • Geo::TerraformStateVersionRegistry
    • Geo::UploadRegistry
  • Git 仓库类型
    • Geo::DesignManagementRepositoryRegistry
    • Geo::ProjectRepositoryRegistry
    • Geo::ProjectWikiRepositoryRegistry
    • Geo::SnippetRepositoryRegistry
    • Geo::GroupWikiRepositoryRegistry
  • 其他类型
    • Geo::ContainerRepositoryRegistry

重新同步和重新验证多个组件

如果未在正确条件下运行,更改数据的命令可能会造成损坏。始终先在测试环境中运行命令,并准备好备份实例以进行恢复。

以下部分描述如何使用 Rails 控制台 中的内部应用程序命令来执行批量复制或验证。

重新同步一个组件的所有资源

您可以从 UI 安排一个组件的所有资源的完整重新同步:

  1. 在左侧边栏底部,选择管理
  2. 选择Geo > 站点
  3. 复制详情下,选择所需的组件。
  4. 选择重新同步所有

或者,在次要 Geo 站点上启动 Rails 控制台会话以收集更多信息,或使用下面的代码片段手动执行这些操作。

如果未在正确条件下运行,更改数据的命令可能会造成损坏。始终先在测试环境中运行命令,并准备好备份实例以进行恢复。

同步一个组件中所有同步失败的资源

以下脚本:

  • 遍历所有失败的仓库。
  • 显示 Geo 同步和验证元数据,包括上次失败的原因。
  • 尝试重新同步仓库。
  • 报告是否发生失败以及原因。
  • 可能需要一些时间才能完成。每个仓库检查必须完成才能报告结果。如果您的会话超时,请采取措施使进程继续运行,例如启动 screen 会话,或使用 Rails runnernohup 运行它。
Geo::ProjectRepositoryRegistry.failed.find_each do |registry|
   begin
     puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Last Sync Failure: '#{registry.last_sync_failure}'"
     registry.replicator.sync
     puts "Sync initiated for registry ID: #{registry.id}"
   rescue => e
     puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Failed: '#{e}'", e.backtrace.join("\n")
   end
end; nil

在所有站点上重新验证一个组件

如果站点的校验和有问题,您需要让站点重新计算校验和。这样就实现了"完全重新验证",因为在站点上重新计算每个校验和后,会生成事件传播到所有次要站点,导致它们重新计算校验和并比较值。任何不匹配都会将注册表标记为 sync failed,从而安排同步重试。

UI 不提供按钮来进行完全重新验证。您可以通过在管理 > Geo > 节点 > 编辑中将站点的 重新验证间隔 设置为 1(天)来模拟此操作。然后,站点将重新计算任何超过 1 天前校验过的资源的校验和。

或者,您可以手动执行此操作:

  1. SSH 到站点上的 GitLab Rails 节点。

  2. 打开 Rails 控制台

  3. Upload 替换为任何 Geo 数据类型模型类,将所有资源标记为 等待验证

    Upload.verification_state_table_class.each_batch do |relation|
      relation.update_all(verification_state: 0)
    end
在主站点上重新验证所有校验失败的资源

系统会自动重新验证在主站点上校验失败的所有资源,但它使用渐进式退避方案来避免失败数量过多。

或者,例如,如果您已完成尝试干预,可以手动触发重新验证:

  1. SSH 到站点上的 GitLab Rails 节点。

  2. 打开 Rails 控制台

  3. Upload 替换为任何 Geo 数据类型模型类,将所有资源标记为 等待验证

    Upload.verification_state_table_class.where(verification_state: 3).each_batch do |relation|
      relation.update_all(verification_state: 0)
    end

在一个次要站点上重新验证一个组件

如果您认为站点的校验和是正确的,可以从 UI 安排在一个次要站点上重新验证一个组件:

  1. 在左侧边栏底部,选择管理
  2. 选择Geo > 站点
  3. 复制详情下,选择所需的组件。
  4. 选择重新验证所有

错误

消息:主站点上的文件丢失

在首次设置次要 Geo 站点时,同步失败主站点上的文件丢失很常见,这是由主站点上的数据不一致引起的。

在操作 GitLab 时,由于系统或人为错误,可能会发生数据不一致和文件丢失。例如,实例管理员手动删除本地文件系统上的多个工件。此类更改未正确传播到数据库,导致不一致。这些不一致仍然存在并可能造成摩擦。Geo 次要站点可能会继续尝试复制那些文件,因为它们仍然在数据库中被引用,但已不再存在。

如果是最近从本地存储迁移到对象存储,请参阅专门的对象存储故障排除部分

识别不一致

当存在缺失文件或不一致时,您可能会在 geo.log 中遇到如下条目。请注意 "primary_missing_file" : true 字段:

{
   "bytes_downloaded" : 0,
   "class" : "Geo::BlobDownloadService",
   "correlation_id" : "01JT69C1ECRBEMZHA60E5SAX8E",
   "download_success" : false,
   "download_time_s" : 0.196,
   "gitlab_host" : "gitlab.example.com",
   "mark_as_synced" : false,
   "message" : "Blob download",
   "model_record_id" : 55,
   "primary_missing_file" : true,
   "reason" : "Not Found",
   "replicable_name" : "upload",
   "severity" : "WARN",
   "status_code" : 404,
   "time" : "2025-05-01T16:02:44.836Z",
   "url" : "http://gitlab.example.com/api/v4/geo/retrieve/upload/55"
}

相同的错误也会反映在 UI 中,在管理 > Geo > 站点下查看特定可复制对象的同步状态时。在此场景中,特定的上传文件缺失:

显示所有失败错误的 Geo 上传可复制对象仪表板。

显示缺失文件错误的 Geo 上传可复制对象仪表板。

清理不一致

在发出任何删除命令之前,请确保手头有最新且可用的备份。

要删除这些错误,首先确定哪些特定资源受到影响。然后,运行适当的 destroy 命令以确保删除传播到所有 Geo 站点及其数据库。基于前面的场景,一个上传导致这些错误,下面以此为例。

  1. 将识别的不一致映射到相应的 Geo 模型类名称。下一步需要类名。在此场景中,对于上传对应 Upload

  2. Geo 主站点上启动 Rails 控制台

  3. 根据上一步的 Geo 模型类,查询所有因文件丢失而验证失败的资源。调整或删除 limit(20) 以显示更多结果。观察列出的资源是否与 UI 中显示的失败资源匹配:

    Upload.verification_failed.where("verification_failure like '%File is not checksummable%'").limit(20)
    
    => #<Upload:0x00007b362bb6c4e8
     id: 55,
     size: 13346,
     path: "503d99159e2aa8a3ac23602058cfdf58/openbao.png",
     checksum: "db29d233de49b25d2085dcd8610bac787070e721baa8dcedba528a292b6e816b",
     model_id: 1,
     model_type: "Project",
     uploader: "FileUploader",
     created_at: Thu, 01 May 2025 15:54:10.549178000 UTC +00:00,
     store: 1,
     mount_point: nil,
     secret: "[FILTERED]",
     version: 2,
     uploaded_by_user_id: 1,
     organization_id: nil,
     namespace_id: nil,
     project_id: 1,
     verification_checksum: nil>
  4. 可选地,使用受影响资源的 id 确定它们是否仍然需要:

    Upload.find(55)
    
    => #<Upload:0x00007b362bb6c4e8
     id: 55,
     size: 13346,
     path: "503d99159e2aa8a3ac23602058cfdf58/openbao.png",
     checksum: "db29d233de49b25d2085dcd8610bac787070e721baa8dcedba528a292b6e816b",
     model_id: 1,
     model_type: "Project",
     uploader: "FileUploader",
     created_at: Thu, 01 May 2025 15:54:10.549178000 UTC +00:00,
     store: 1,
     mount_point: nil,
     secret: "[FILTERED]",
     version: 2,
     uploaded_by_user_id: 1,
     organization_id: nil,
     namespace_id: nil,
     project_id: 1,
     verification_checksum: nil>
    • 如果您确定需要恢复受影响的资源,则可以探索以下选项(非详尽)来恢复它们:
      • 检查次要站点是否有该对象,并手动复制到主站点。
      • 查看旧备份并手动将对象复制回主站点。
      • 抽查一些,以确定删除记录可能没问题,例如,如果它们都是非常旧的工件,那么它们可能不是关键数据。
  5. 使用已识别资源的 id 通过 destroy 单独或批量删除它们。确保使用适当的 Geo 模型类名称。

    • 删除单个资源:

      Upload.find(55).destroy
    • 删除所有受影响的资源:

      def destroy_uploads_not_checksummable
        uploads = Upload.verification_failed.where("verification_failure like '%File is not checksummable%'");1
        puts "Found #{uploads.count} resources that failed verification with 'File is not checksummable'."
        puts "Enter 'y' to continue: "
        prompt = STDIN.gets.chomp
        if prompt != 'y'
          puts "Exiting without action..."
          return
        end
      
        puts "Destroying all..."
        uploads.destroy_all
      end
      
      destroy_uploads_not_checksummable

对所有受影响的资源和 Geo 数据类型重复这些步骤。

消息:"验证期间出错","error":"文件不可校验"

错误 "验证期间出错","error":"文件不可校验" 是由主站点上的不一致引起的。请按照主站点上的文件丢失中的说明操作。

主 Geo 站点上上传验证失败

如果某些上传在主 Geo 站点上的验证失败,verification_checksum = nilverification_failure 包含 验证期间出错:未定义的方法 'underscore' for NilClass:Class拥有此上传的模型缺失。,这是由于孤立的上传引起的。拥有上传的父记录(上传的"模型")以某种方式被删除,但上传记录仍然存在。这通常是由于应用程序中的错误引起的,在实现批量删除"模型"时忘记批量删除其关联的上传记录。因此,这些验证失败不是验证失败,而是 PostgreSQL 中错误数据的结果。

您可以在主 Geo 站点的 geo.log 文件中找到这些错误。

要确认模型记录是否缺失,可以在主 Geo 站点上运行 Rake 任务:

sudo gitlab-rake gitlab:uploads:check

您可以通过在主 Geo 站点上运行以下脚本来删除这些上传记录以消除这些失败:

def delete_orphaned_uploads(dry_run: true)
  if dry_run
    p "This is a dry run. Upload rows will only be printed."
  else
    p "This is NOT A DRY RUN! Upload rows will be deleted from the DB!"
  end

  subquery = Geo::UploadState.where("(verification_failure LIKE 'Error during verification: The model which owns this Upload is missing.%' OR verification_failure = 'Error during verification: undefined method `underscore'' for NilClass:Class') AND verification_checksum IS NULL")
  uploads = Upload.where(upload_state: subquery)
  p "Found #{uploads.count} uploads with a model that does not exist"

  uploads_deleted = 0
  begin
    uploads.each do |upload|

      if dry_run
        p upload
      else
        uploads_deleted=uploads_deleted + 1
        p upload.destroy!
      end
    rescue => e
      puts "checking upload #{upload.id} failed with #{e.message}"
    end
  end

  p "#{uploads_deleted} remote objects were destroyed." unless dry_run
end

前面的脚本定义了一个名为 delete_orphaned_uploads 的方法,您可以这样调用它进行试运行:

delete_orphaned_uploads(dry_run: true)

而实际删除孤立的上传行:

delete_orphaned_uploads(dry_run: false)

错误:同步仓库错误:13:fatal: 无法读取用户名

last_sync_failure 错误 同步仓库错误:13:fatal: 无法读取 'https://gitlab.example.com' 的用户名:终端提示已禁用 表示在 Geo 克隆或获取请求期间 JWT 身份验证失败。

首先,检查系统时钟是否同步。运行健康检查 Rake 任务,或手动检查次要站点上的所有 Sidekiq 节点和主站点上的所有 Puma 节点上的 date 是否相同。

如果系统时钟已同步,则 JWT 令牌可能在 Git fetch 在其两个单独的 HTTP 请求之间执行计算时过期。请参阅问题 464101,该问题存在于所有 GitLab 版本中,直到在 GitLab 17.1.0、17.0.5 和 16.11.7 中修复。

要验证您是否遇到此问题:

  1. 在次要站点上的 Rails 控制台 中修补代码,将令牌的有效期从 1 分钟增加到 10 分钟。在次要站点上的 Rails 控制台中运行:

    module Gitlab; module Geo; class BaseRequest
      private
      def geo_auth_token(message)
        signed_data = Gitlab::Geo::SignedData.new(geo_node: requesting_node, validity_period: 10.minutes).sign_and_encode_data(message)
    
        "#{GITLAB_GEO_AUTH_TOKEN_TYPE} #{signed_data}"
      end
    end;end;end
  2. 在同一个 Rails 控制台中,重新同步受影响的项目:

    Project.find_by_full_path('<mygroup/mysubgroup/myproject>').replicator.resync
  3. 查看同步状态:

    Project.find_by_full_path('<mygroup/mysubgroup/myproject>').replicator.registry
  4. 如果 last_sync_failure 不再包含错误 fatal: could not read Username,那么您遇到了此问题。状态现在应该是 2,这意味着已同步。如果是这样,您应该升级到包含修复的 GitLab 版本。您可能还希望对问题 466681进行投票或评论,这将降低此问题的严重性。

要解决此问题,您必须在次要站点的所有 Sidekiq 节点上热修补以延长 JWT 过期时间:

  1. 编辑 /opt/gitlab/embedded/service/gitlab-rails/ee/lib/gitlab/geo/signed_data.rb

  2. 找到 Gitlab::Geo::SignedData.new(geo_node: requesting_node) 并添加 , validity_period: 10.minutes

    - Gitlab::Geo::SignedData.new(geo_node: requesting_node)
    + Gitlab::Geo::SignedData.new(geo_node: requesting_node, validity_period: 10.minutes)
    
  3. 重启 Sidekiq:

    sudo gitlab-ctl restart sidekiq
  4. 除非您升级到包含修复的版本,否则每次 GitLab 升级后都必须重复此解决方法。

错误:同步仓库错误:13:创建仓库:克隆仓库:退出状态 128

您可能会看到此错误用于未成功同步的项目。

仓库创建期间的退出代码 128 表示 Git 在克隆时遇到致命错误。这可能是由于仓库损坏、网络问题、身份验证问题、资源限制或项目没有关联的 Git 仓库引起的。有关此类失败具体原因的更多详细信息可以在 Gitaly 日志中找到。

当不确定从哪里开始时,通过在命令行上手动执行 git fsck 命令在主站点上对源仓库进行完整性检查。

错误:在恰好 3 小时处出现 fetch remote: signal: terminated: context deadline exceeded

如果 Git fetch 在同步 Git 仓库时恰好三小时失败:

  1. 编辑 /etc/gitlab/gitlab.rb 以将 Git 超时时间从默认的 10800 秒增加:

    # Git 超时时间(秒)
    gitlab_rails['gitlab_shell_git_timeout'] = 21600
  2. 重新配置 GitLab:

    sudo gitlab-ctl reconfigure

在次要站点上配置注册表复制时出现 无法打开到 localhost:5000 的 TCP 连接 错误

在次要站点上配置容器注册表复制时,您可能会遇到以下错误:

无法打开到 localhost:5000 的 TCP 连接(连接被拒绝 - connect(2) 为 "localhost" 端口 5000)

如果容器注册表未在次要站点上启用,就会发生这种情况。要修复它,检查容器注册表是否在次要站点上启用。如果禁用了 Let’s Encrypt 集成,容器注册表也会被禁用,您必须手动配置

消息:同步失败 - 同步仓库错误

如果大型仓库受此问题影响, 它们的重新同步可能需要很长时间,并对您的 Geo 站点、存储和网络系统造成显著负载。

以下错误消息表示同步仓库时的一致性检查错误:

同步失败 - 同步仓库 [..] fatal: 压缩对象中 fsck 错误

几个问题可能会触发此错误。例如,电子邮件地址问题:

同步仓库错误:13:fetch remote: "error: object <SHA>: badEmail: 无效的作者/提交者行 - 错误的电子邮件
   fatal: 压缩对象中 fsck 错误
   fatal: fetch-pack: 无效的 index-pack 输出

另一个可能触发此错误的问题是 object <SHA>: hasDotgit: 包含 '.git'。检查具体错误,因为您可能在所有仓库中有多个问题。

第二个同步错误也可能由仓库检查问题引起:

同步仓库错误:13:收到错误代码为 2 的 RST_STREAM。

这些错误可以通过立即同步所有失败的仓库观察到。

删除导致一致性错误的格式错误对象涉及重写仓库历史,这通常不是选项。

要忽略这些一致性检查,在次要 Geo 站点上重新配置 Gitaly 以忽略这些 git fsck 问题。以下配置示例:

Gitaly 文档有更多详细信息 关于其他 Git 检查失败和早期 GitLab 版本。

gitaly['configuration'] = {
  git: {
    config: [
      { key: "fsck.duplicateEntries", value: "ignore" },
      { key: "fsck.badFilemode", value: "ignore" },
      { key: "fsck.missingEmail", value: "ignore" },
      { key: "fsck.badEmail", value: "ignore" },
      { key: "fsck.hasDotgit", value: "ignore" },
      { key: "fetch.fsck.duplicateEntries", value: "ignore" },
      { key: "fetch.fsck.badFilemode", value: "ignore" },
      { key: "fetch.fsck.missingEmail", value: "ignore" },
      { key: "fetch.fsck.badEmail", value: "ignore" },
      { key: "fetch.fsck.hasDotgit", value: "ignore" },
      { key: "receive.fsck.duplicateEntries", value: "ignore" },
      { key: "receive.fsck.badFilemode", value: "ignore" },
      { key: "receive.fsck.missingEmail", value: "ignore" },
      { key: "receive.fsck.badEmail", value: "ignore" },
      { key: "receive.fsck.hasDotgit", value: "ignore" },
    ],
  },
}

GitLab 16.1 及更高版本包含增强功能,可能会解决其中一些问题。

Gitaly 问题 5625 建议确保 Geo 即使源仓库包含有问题的提交也复制仓库。

相关错误 似乎不是一个 git 仓库

您也可能收到错误消息 同步失败 - 同步仓库错误 以及以下日志消息。此错误表示在次要 Geo 站点文件系统上的仓库的 .git/config 文件中不存在预期的 Geo 远程:

{
  "created": "@1603481145.084348757",
  "description": "Error received from peer unix:/var/opt/gitlab/gitaly/gitaly.socket",
  
  "grpc_message": "exit status 128",
  "grpc_status": 13
}
{  
  "grpc.request.fullMethod": "/gitaly.RemoteService/FindRemoteRootRef",
  "grpc.request.glProjectPath": "<namespace>/<project>",
  
  "level": "error",
  "msg": "fatal: 'geo' 似乎不是一个 git 仓库
          fatal: 无法从远程仓库读取。……",
}

要解决此问题:

  1. 登录次要 Geo 站点的 Web 界面。

  2. 备份 .git 文件夹

  3. 可选。抽查 一些 ID 是否确实对应于已知 Geo 复制失败的项目。 使用 fatal: 'geo' 作为 grep 术语和以下 API 调用:

    curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<first_failed_geo_sync_ID>"
  4. 进入 Rails 控制台 并运行:

    failed_project_registries = Geo::ProjectRepositoryRegistry.failed
    
    if failed_project_registries.any?
      puts "Found #{failed_project_registries.count} failed project repository registry entries:"
    
      failed_project_registries.each do |registry|
        puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Last Sync Failure: '#{registry.last_sync_failure}'"
      end
    else
      puts "No failed project repository registry entries found."
    end
  5. 运行以下命令为每个项目执行新的同步:

    failed_project_registries.each do |registry|
      registry.replicator.sync
      puts "Sync initiated for registry ID: #{registry.id}, Project ID: #{registry.project_id}"
    end

回填期间的失败

回填期间,失败被安排在回填队列末尾重试,因此这些失败仅在回填完成后才会清除。

消息:读取边带数据包时意外断开连接

不稳定的网络条件可能导致 Gitaly 在尝试从主站点获取大型仓库数据时失败。这些条件可能导致此错误:

curl 18 传输关闭,仍有未读取的数据剩余 & fetch-pack:
读取边带数据包时意外断开连接

如果仓库必须在站点之间从头复制,则此错误更有可能发生。

Geo 会重试几次,但如果传输因网络故障而持续中断,可以使用 rsync 等替代方法来绕过 git 并创建任何无法通过 Geo 复制的仓库的初始副本。

我们建议单独传输每个失败的仓库,并在每次传输后检查一致性。按照单目标 rsync 说明将每个受影响的仓库从主站点传输到次要站点。

在 Geo 次要站点中查找仓库检查失败

所有仓库数据类型已在 GitLab 16.3 中迁移到 Geo 自助服务框架。有一个问题要在 Geo 自助服务框架中重新实现此功能

对于 GitLab 16.2 及更早版本:

为所有项目启用时,仓库检查也会在 Geo 次要站点上执行。元数据存储在 Geo 跟踪数据库中。

Geo 次要站点上的仓库检查失败不一定意味着复制问题。以下是解决这些失败的一般方法。

  1. 如下所述查找受影响的仓库,以及它们的记录错误
  2. 尝试诊断特定的 git fsck 错误。可能的错误范围很广,尝试将它们放入搜索引擎。
  3. 测试受影响仓库的典型功能。从次要站点拉取,查看文件。
  4. 检查主站点的仓库副本是否具有相同的 git fsck 错误。如果您计划故障转移,请考虑次要站点具有与主站点相同的信息。确保您有主站点的备份,并遵循计划故障转移指南
  5. 推送到主站点并检查更改是否复制到次要站点。
  6. 如果复制未自动工作,尝试手动同步仓库。

启动 Rails 控制台会话 以执行以下基本故障排除步骤。

如果未在正确条件下运行,更改数据的命令可能会造成损坏。始终先在测试环境中运行命令,并准备好备份实例以进行恢复。

获取仓库检查失败的仓库数量

Geo::ProjectRegistry.where(last_repository_check_failed: true).count

查找仓库检查失败的仓库

Geo::ProjectRegistry.where(last_repository_check_failed: true)

重置 Geo 次要站点复制

如果您让次要站点处于损坏状态并想要重置复制状态, 从头开始,有几个步骤可以帮助您:

  1. 停止 Sidekiq 和 Geo 日志光标。

    可以让 Sidekiq 优雅地停止,但让它停止获取新作业并 等待当前作业完成处理。

    您需要发送 SIGTSTP 终止信号用于第一阶段,然后发送 SIGTERM 当所有作业完成时。否则只需使用 gitlab-ctl stop 命令。

    gitlab-ctl status sidekiq
    # run: sidekiq: (pid 10180) <- 这是您将使用的 PID
    kill -TSTP 10180 # 更改为正确的 PID
    
    gitlab-ctl stop sidekiq
    gitlab-ctl stop geo-logcursor

    您可以观看 Sidekiq 日志 来了解 Sidekiq 作业处理何时完成:

    gitlab-ctl tail sidekiq
  2. 清理 Gitaly 和 Gitaly 集群(Praefect)数据。

    mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
    sudo gitlab-ctl reconfigure
    1. 可选。禁用 Praefect 内部负载均衡器。

    2. 在每个 Praefect 服务器上停止 Praefect:

      sudo gitlab-ctl stop praefect
    3. 重置 Praefect 数据库:

      sudo /opt/gitlab/embedded/bin/psql -U praefect -d template1 -h localhost -c "DROP DATABASE praefect_production WITH (FORCE);"
      sudo /opt/gitlab/embedded/bin/psql -U praefect -d template1 -h localhost -c "CREATE DATABASE praefect_production WITH OWNER=praefect ENCODING=UTF8;"
    4. 从每个 Gitaly 节点重命名/删除仓库数据:

      sudo mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
      sudo gitlab-ctl reconfigure
    5. 在您的 Praefect 部署节点上运行 reconfigure 来设置数据库:

      sudo gitlab-ctl reconfigure
    6. 在每个 Praefect 服务器上启动 Praefect:

      sudo gitlab-ctl start praefect
    7. 可选。如果您禁用了它,请重新激活 Praefect 内部负载均衡器。

    您可能希望将来删除 /var/opt/gitlab/git-data/repositories.old, 一旦您确认不再需要它,以节省磁盘空间。

  3. 可选。重命名其他数据文件夹并创建新的。

    您在次要站点上可能仍有文件已被从站点删除, 但此删除尚未反映。如果您跳过此步骤,这些文件不会从 Geo 次要站点中删除。

    任何上传的内容(如文件附件、头像或 LFS 对象)都存储在这些路径之一的子文件夹中:

    • /var/opt/gitlab/gitlab-rails/shared
    • /var/opt/gitlab/gitlab-rails/uploads

    重命名所有这些:

    gitlab-ctl stop
    
    mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
    mkdir -p /var/opt/gitlab/gitlab-rails/shared
    
    mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
    mkdir -p /var/opt/gitlab/gitlab-rails/uploads
    
    gitlab-ctl start postgresql
    gitlab-ctl start geo-postgresql

    重新配置以重新创建文件夹并确保权限和所有权 正确:

    gitlab-ctl reconfigure
  4. 重置跟踪数据库。

    如果您跳过了可选步骤 3,请确保 geo-postgresqlpostgresql 服务都在运行。

    gitlab-rake db:drop:geo DISABLE_DATABASE_ENVIRONMENT_CHECK=1   # 在次要应用节点上
    gitlab-ctl reconfigure     # 在跟踪数据库节点上
    gitlab-rake db:migrate:geo # 在次要应用节点上
  5. 重新启动之前停止的服务。

    gitlab-ctl start