Gerrit 大型仓库加速与索引维护实战指南
目录
目标:在 Gerrit(裸仓库)环境中,通过对 Git pack、bitmap 索引、commit-graph 与 Gerrit/Lucene 索引的系统化维护,显著缩短 git clone / fetch 时的 “Finding sources” 与其它慢步骤,提升整体 CI/CD 与开发效率。
先决条件(环境概览)
角色 | 设备 / 软件 | 规格 / 说明 |
---|---|---|
服务端(Gerrit) | 裸金属:FusionServer 2288H V6 | 双路 Intel Xeon Gold 6330 ×2(每路 28 cores, 56 threads),内存 125GB,/data:15TB NVMe SSD;Gerrit v3.10.2 |
客户端(构建 / CI) | 深信服超融合 (SANGFOR HCI) VM → Docker 容器 | Ubuntu 22.04 LTS 容器,64 cores / 128 threads,内存 128GB,/data:15TB NVMe SSD |
网络 | 同一局域网 | 低延迟局域网(但仍可能受服务器 I/O/CPU 影响) |
问题描述(现象)
在客户端执行:
git clone "ssh://[email protected]:29418/Chery/T29-T16A/.../co_common" -b baseline-mp1
出现极慢的克隆过程:
Cloning into 'co_common'...
remote: Counting objects: 9907586, done
remote: Finding sources: 4% (361750/9907586)
观测:Finding sources 阶段非常慢(每秒仅加载 ~1500 个对象),导致整体 clone 时长大幅延长。
快速结论(概览)
- 根因:服务器端缺少或未及时更新 bitmap index 与 commit-graph,导致在协商对象集合(finding sources)时退化为对提交 DAG 的全量遍历。
- 次要影响:若仓库未做紧凑
repack
,Pack 分散/过多,服务器在生成/复用 pack 时也会耗费 CPU/IO,进一步延长Compressing objects
阶段。 - 解决方向:定期对仓库执行
git repack -adf --write-bitmap-index
与git commit-graph write --reachable --changed-paths
,并在 Gerrit 层面重建 Lucene 索引(必要时)。
详细成因分析
1. Counting objects
阶段
- 读取对象索引(pack / .idx)并统计元数据;此阶段通常较快,受磁盘 I/O 与读取索引性能影响。
2. Finding sources
阶段(核心瓶颈)
- 目的:服务器判断客户机已有对象集合与目标 refs 的差集(即要发送哪些对象)。
- 当 bitmap index 与 commit-graph 可用时,服务器使用位运算与已索引的可达性信息快速计算差集;否则会走提交 DAG 遍历(深度优先/广度优先),这是在超大仓库上非常耗时的操作。
3. Compressing objects / sending pack
阶段
- 一旦需要发送对象集合,服务器会尝试复用现有 pack 或实时打包(pack-objects)。如果仓库没有紧凑 pack,实时打包会占用大量 CPU/IO;NVMe 和大内存能缓解,但无助于前一步骤耗时。
运维与优化(逐项、可执行命令)
在裸仓库(Gerrit 的
.git
即裸仓库)中运行以下维护命令。请先在维护窗口执行,并做好短期备份。
A. 对单仓库的维护(推荐先执行在示例仓库)
# 进入裸仓库目录(示例)
cd /data/sdc/cockpit-gerrit-8082/git/Chery/T29-T16A/MediaTek_MTK8678/yocto/BITECH/mt8678-yocto/src/kernel/linux/v6.6_mt8678/co_common.git
# 备份现有 pack 目录(短期)
cp -r objects/pack ../pack_backup_$(date +%F)
# 强制 repack:合并 pack、产生新的紧凑 pack,并写入 bitmap index
git repack -adf --write-bitmap-index --threads=16
# 生成 commit-graph,记录 changed-paths(提升按路径查询效率)
git commit-graph write --reachable --changed-paths
# 验证 bitmap 与 commit-graph 文件存在
ls -lh objects/pack/*.bitmap || true
ls -lh objects/info/commit-graph* || true
说明:
-a
:将所有 loose objects 也打包。-d
:删除旧的 pack(视操作风险,可先不加以保留备份)。-f
:强制生成(覆盖可能存在的旧索引)。--write-bitmap-index
:为 pack 生成 .bitmap 文件。
B. Gerrit 层面的 Lucene 索引(用于代码搜索 / UI 查询加速)
在 Gerrit 服务器上,通过 gerrit 管理命令触发索引重建:
# 重新为所有项目重建索引(消耗资源,建议低峰期执行)
ssh -p 29418 gerrit@localhost gerrit index start --all
# 或者单项目重建
ssh -p 29418 gerrit@localhost gerrit index start --project "Chery/T29-T16A/.../co_common"
注意:Lucene 索引主要影响 Gerrit UI 的查询与搜索性能,而非 git 协议本身的 clone/fetch 逻辑;但在一些管理操作或插件中,过慢的索引会间接影响用户体验。
C. 批量 / 自动化维护脚本(示例)
定期对仓库做轮询维护:
#!/bin/bash
set -euo pipefail
GERRIT_SITE="/data/sdc/cockpit-gerrit-8082/git"
LOGFILE="/var/log/gerrit_maint_$(date +%F).log"
THREADS=12
cd "$GERRIT_SITE"
for repo in $(find . -name "*.git" -type d); do
echo "$(date +%F_%T) - Optimizing $repo" | tee -a "$LOGFILE"
cd "$repo" || continue
# 先备份 pack(可选,按需开启)
# cp -r objects/pack ../pack_backup_$(date +%F)
# repack(避免并发太多,按仓库顺序进行)
git repack -adf --write-bitmap-index --threads=${THREADS}
# commit-graph
git commit-graph write --reachable --changed-paths || true
cd "$GERRIT_SITE"
# sleep 2 # 可选,避免短时间内连续占满 I/O
done
# 可选触发 Gerrit 索引(谨慎)
# ssh -p 29418 gerrit@localhost gerrit index start --all
建议:通过 systemd
timer 或 cron
在低峰时间(如周末夜间)触发。脚本中应加入日志、错误处理与报警机制。
客户端 / 网络层优化建议
- 在客户端
.gitconfig
配置并行解压:
[pack]
threads = 8
- 若仅需某个分支或目录,使用 浅克隆 / 单分支 限制传输数据量:
# 单分支
git clone --single-branch -b baseline-mp1 <repo-url>
# 浅克隆最近 N 次提交(若不需要全部历史)
git clone --depth 1 --branch baseline-mp1 <repo-url>
-
在局域网环境下,如果仍慢,排查以下指标:
- 服务器端 CPU、iowait、磁盘队列(
top
/iostat
/iotop
) - 网络丢包、MTU 设置
- Gerrit 进程是否在同时执行重打包或 GC 操作
- 服务器端 CPU、iowait、磁盘队列(
概念速查(技术解释)
Pack / Pack Index (.pack / .idx)
- 作用:将大量 loose objects 合并并压缩以减少磁盘与网络带宽开销。
- 位置:
objects/pack/pack-<hash>.pack
与对应.idx
。 - 运维要点:保持较少且紧凑的 pack 通常高效;不宜频繁在高峰期执行
repack
。
Bitmap Index
- 作用:用位图表示从某个 ref 可达的对象集合,支持位运算快速计算差集。
- 优势:显著加速
finding sources
阶段,特别是超大仓库。 - 生成方式:在 repack 时加
--write-bitmap-index
。
Commit-Graph
- 作用:预计算 commit 的可达性与 parent 元信息,加速
git rev-list
、可达性检查与按路径历史查询(配合--changed-paths
)。 - 生成方式:
git commit-graph write --reachable --changed-paths
。
Compressing objects / sending pack
- 流程:服务器根据需要的对象集打包(可能复用已有 pack),对对象做 delta 压缩并通过网络发送。
- 瓶颈:如果没有预先紧凑的 pack 或服务器需要实时创建 pack,会占用大量 CPU/IO。
验证与故障排查清单
-
验证生成的索引:
ls objects/pack/*.bitmap
— 应存在 .bitmap 文件。ls objects/info/commit-graph*
— 应存在 commit-graph 文件。
-
在客户端复测:
- 在另一个机器上进行
git clone --single-branch -b baseline-mp1 <url>
,对比速度。
- 在另一个机器上进行
-
监控指标:
top
、htop
:查看 CPU/线程占用。iostat -x 1
、iotop
:磁盘 I/O 与延迟。- Gerrit 日志(
error_log
/gerrit.log
):观察索引/repacks 相关报错。
-
回滚策略:若 repack 后出现问题,可从
pack_backup_YYYY-MM-DD
恢复旧的 pack 目录(谨慎操作,并保证服务短暂停止或在维护窗口恢复)。
维护频率建议
-
热仓库(每日大量 push):
commit-graph
:每天或每次大批量 push 后更新。repack + bitmap
:每周或每次发布/版本切割后执行。
-
中等活跃仓库:每月一次
repack + bitmap
,commit-graph
每周或每日一次视情况。 -
小型/冷门仓库:每季度或按需。
风险与注意事项
git repack -adf --threads
与git commit-graph write
都是 CPU/内存/IO 密集型 操作,务必在低峰窗口执行。- 在运行
-d
删除旧 pack 前,保留短期备份,以便回滚。 - 若 Gerrit 自身对仓库有并发写入(push),应考虑暂停写入或协调维护时段。
附:常用命令速查表
# 重新打包并生成 bitmap
git repack -adf --write-bitmap-index --threads=16
# 生成 commit-graph(记录 changed-paths)
git commit-graph write --reachable --changed-paths
# 验证 bitmap
ls objects/pack/*.bitmap
# 触发 Gerrit 全量索引重建(谨慎)
ssh -p 29418 gerrit@localhost gerrit index start --all
后续建议(实践落地)
- 在 单个最慢仓库 上先做一次完整维护(repack + commit-graph),并记录
git clone
前后时间对比。 - 制定分批维护计划(避免同时针对所有仓库并发 repack)。
- 将维护脚本集成到
systemd
timer 或cron
,并加入邮件/Telegram 报警(若日志出现错误)。 - 按需优化 Gerrit 的 JVM / Lucene 配置,确保索引重建时有足够内存。