例行维护

极狐GitLab 支持自动化的执行 Git 仓库的例行维护任务来确保尽可能的高效。例行维护包括:

  • 压缩 Git 对象和修订版。
  • 删除无法访问的对象。
  • 删除诸如锁定文件之类的陈旧数据。
  • 维护提高性能的数据结构。
  • 更新对象池,以提升跨分支的对象重复数据删除效率。
caution 不要在 Git 仓库中手动执行 Git 命令来执行例行维护任务。这样做可能导致损坏的仓库和数据丢失。

例行维护策略

Gitaly 有两种方式来在 Git 仓库中执行例行维护任务:

  • 即时例行维护会独立于存储库的状态执行特定的例行维护任务。
  • 随机例行维护会依据一套启发式方法来执行清理任务。这些方法会根据存储库的状态,判断需要执行哪些清理任务。

即时(eager)例行维护

“eager” 例行维护策略会独立于仓库的存储状态来执行特定的例行维护任务。这是手动触发器和基于推送的触发器的默认策略。

eager 例行维护策略受控于极狐GitLab 应用程序。取决于引发例行维护作业运行的触发器,极狐GitLab 让 Gitaly 执行特定的例行维护任务。Gitaly 会执行这些任务,即使仓库处于优化状态。结果就是,这种策略在大型仓库中可能效率低下,因为执行例行维护任务可能很慢。

随机(heuristical)例行维护

  • 针对手动触发器和基于推送的触发器引入于极狐GitLab 14.9,使用名为 optimized_housekeeping功能标志。默认启用。
  • 极狐GitLab 15.8 中 GA。功能标志 optimized_housekeeping 被移除。

随机例行维护策略会分析仓库的状态,然后仅在其找到一个或多个需要优化的数据结构时才执行例行清理任务。计划的例行维护使用此策略。

随机例行维护使用如下信息来决定是否需要运行任务:

  • 松散对象和陈旧对象的数量。
  • 包含已经被压缩对象的包文件数量。
  • 松散引用数量。
  • 提交图的存在。

关于任何分析的数据结构是否需要被优化的决定都要基于仓库的大小:

  • 所有对象的总大小越大,对象重新打包的频率就越高。
  • 引用的总数越多,引用重新打包的频率就越低。

Gitaly这样做是为了弥补一个事实,即数据结构越大,优化它们所需的时间就越多。在大型单体仓库(这类仓库流量很大)中,避免过于频繁地对其进行优化尤为重要。

您可以更改 Gitaly 询问优化仓库的频率:

  1. 在导航栏左侧,底部,选择 管理员
  2. 选择 设置 > 仓库
  3. 展开 仓库维护
  4. 例行维护 部分,配置例行维护选项。
  5. 选择 保存更改
  • 启用自动仓库例行维护:Gitaly 运行的常规任务来优化仓库。如果您长期禁用此设置,那么您极狐GitLab 服务器上的 Git 仓库访问会变慢,并且您的仓库会使用更多磁盘空间。
  • 优化仓库周期:在进行若干次 Git 推送后,就会要求Gitaly对存储库进行优化。

运行例行维护任务

极狐GitLab 运行例行维护任务的方式有多种:

  • 项目管理员可以手动触发仓库例行维护任务。
  • 极狐GitLab 可以在一定数量的 Git 推送发生后自动定时运行例行维护任务。
  • 极狐GitLab 可以定时一个任务来为所有的仓库在可配置的时间窗口内运行例行维护任务。

手动触发

仓库的管理员可以在仓库中手动触发例行维护任务。一般来说,这并非必要操作,因为金鸡湖GitLab 会自动运行清理任务。手动触发器在以下场景中非常有用:

  • 指名需要例行维护的仓库。
  • 基于推动的自动定时例行维护任务被禁用。

要手动触发例行维护任务:

  1. 在左侧导航栏,选择 搜索或前往 并找到您的项目。
  2. 选择 设置 > 通用
  3. 展开 高级
  4. 选择 运行例行维护

这会为项目仓库启动一个异步地后端工作器。此后端工作器会要求 Gitaly 执行优化。

例行维护还会在您的仓库中每隔 200 次推送后来移除掉非引用的 LFS 文件,从而为您的仓库释放空间。

清理无法访问的对象

无法访问的对象会作为定时例行维护任务的一部分被清理掉。当然,您也可以手动触发清理任务。比如:移除包含敏感信息的提交信息。触发清理操作会删除无法访问的对象,不过会有两周的宽限期。当您手动触发无法访问对象的清理时,宽限期减少到 30 分钟。

caution 如果对象创建了并发进程(诸如 git push)但是并未为对象创建引用,如果在对象被删除后又添加了对该对象的引用,你的存储库可能会损坏。宽限期的存在就是为了避免这种情况的发生。比如,如果通过有时极为缓慢的网络连接频繁推送大量大型对象,那么删除无法访问的对象所带来的风险,要比在企业环境中高得多。在企业环境里,项目只能通过高性能的内部网络访问。使用此选项时,要考虑项目的使用情况,并选择业务低谷期。

要为无法访问的对象触发手动清理:

  1. 在导航栏左侧,选择 搜索或前往 并找到您的项目。
  2. 选择 设置 > 通用
  3. 展开 高级
  4. 选择 运行例行维护
  5. 等待 30 分钟以让操作完成。
  6. 返回您选择 例行维护 的页面,然后选择 清理无法访问的对象

定时的例行维护

当极狐GitLab 基于推送数量自动执行例行维护任务时,它不会维护那些一点儿也不接受任何推送的仓库。结果就是,那些不活跃的仓库或仅获取读请求的仓库无法从仓库例行维护策略的改进中获益。

管理员可以启用一个后台任务来以可定义的时间周期为所有仓库执行例行维护任务,这就能很好的修复上述提到的问题。此后台作业会以随机顺序处理由某个 Gitaly 节点托管的所有存储库,并立即对它们执行清理任务。如果处理时间超过配置的时间间隔,该 Gitaly 节点将停止处理存储库。

配置定时的例行维护

Git 仓库的后台维护在 Gitaly 中配置。默认情况下,Gitaly 会在每天中午 12:00 执行后台仓库维护任务,每次持续 10 分钟。

您可以在 Gitaly 配置中修改此默认值。

对于 Gitaly 集群来说,预定的清理任务启动时间可在各个 Gitaly 节点间错开,这样就不会在多个节点上同时运行预定的清理任务。

如果定时的例行计划任务运行超过了指定的 duration,则运行任务会被平滑取消。在后续预定的清理任务运行时,Gitaly 会随机打乱要处理的存储库列表顺序。

以下代码片段可启用每日后台仓库维护,从23:00开始,针对 default 存储持续1小时。 :

::Tabs

:::TabTitle Self-compiled (source)

[daily_maintenance]
start_hour = 23
start_minute = 00
duration = 1h
storages = ["default"]

使用如下代码片段来完全禁用后台仓库维护:

[daily_maintenance]
disabled = true

:::TabTitle Linux package (Omnibus)

gitaly['configuration'] = {
  daily_maintenance: {
    disabled: false,
    start_hour: 23,
    start_minute: 00,
    duration: '1h',
    storages: ['default'],
  },
}

使用如下代码片段来完全禁用后台仓库维护:

gitaly['configuration'] = {
  daily_maintenance: {
    disabled: true,
  },
}

::EndTabs

当定时例行维护任务执行时,您可以在您的 Gitaly 日志中看到如下条目:

# When the scheduled housekeeping starts
{"level":"info","msg":"maintenance: daily scheduled","pid":197260,"scheduled":"2023-09-27T13:10:00+13:00","time":"2023-09-27T00:08:31.624Z"}

# When the scheduled housekeeping completes
{"actual_duration":321181874818,"error":null,"level":"info","max_duration":"1h0m0s","msg":"maintenance: daily completed","pid":197260,"time":"2023-09-27T00:15:21.182Z"}

actual_duration(以纳秒计算)显示了定时维护花费的执行时长。在上面的例子中,定时的例行维护仅在 5 分钟内就已完成。

对象池仓库

GitLab 使用对象池存储库,在同一存储库的不同 fork 间去重对象。 当首次创建 fork 时,我们可以:

  1. 创建一个包含对象池仓库,其中包含即将被 fork 的仓库的所有对象。
  2. 通过使用 Git 的交替机制将仓库链接到这个新的对象池。
  3. 重新打包仓库以便它使用此存储池。然后,它可以丢弃自己的对象副本。

此仓库的任何 fork 现在都可以链接到这个对象池,因此只需要保留那些与主仓库不同的对象即可。

极狐GitLab 需要在对象池中执行特殊的例行维护操作:

  • Gitaly 永远不能从对象池中删除无法访问的对象,因为它们可能会被与其相连的任何 fork 所使用。
  • 由于相同的原因,Gitaly 必需保持所有的对象不可访问。因此,对象池会保留对不可访问的“悬空”对象的引用,以便它们永远不会被删除。
  • 极狐GitLab 必须定期更新对象池,以引入主存储库中添加的新对象。否则,对象池在对象去重方面的效率会越来越低。

这些清理操作由专门的 FetchIntoObjectPool RPC 执行,它处理所有这些特殊任务,同时也会执行我们为标准 Git 存储库执行的常规清理任务。

每当主成员进行垃圾回收时,对象池会自动得到优化。因此,可以使用该项目中相同的 Git GC 周期来配置优化的频率。

如果您需要从 Rails 控制台手动引入 RPC,则您可以调用 project.pool_repository.object_pool.fetch。这是一个可能很长的任务,但是 Gitaly 会在大约 8 小时后超时。