GitLab 升级迁移排查与修复手册

GitLab升级迁移排查与修复手册

本手册总结了在升级GitLab过程中,因历史脏数据约束冲突、数据库Advisory咨询锁阻塞,或后台批处理迁移(Batched Background Migrations,简称BBM)挂起导致db:migrate失败、容器启动循环或Web页面无法访问时的完整命令排查流程与核心注意事项。

目录

一、核心排查与修复命令流程

阶段一:清理数据库死锁与卡顿连接

阶段二:修复历史脏数据(以namespaces.state约束为例)

阶段三:处理后台批处理迁移(BBM)挂起与收尾

阶段四:恢复常规迁移与服务重构

阶段五:健康检查与系统验证

二、关键运维注意事项

1.数据库操作层面

2.后台批处理迁移(BBM)层面

3.容器与服务运维层面

 一、核心排查与修复命令流程

阶段一:清理数据库死锁与卡顿连接

当迁移抛出ActiveRecord::ConcurrentMigrationError或提示锁等待超时时,需要清理后台残留的Advisory锁。

#终止所有非当前会话的advisory锁

docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "SELECT pg_terminate_backend(pid) FROM pg_locks WHERE locktype = 'advisory' AND pid <> pg_backend_pid();"

阶段二:修复历史脏数据(以namespaces.state约束为例)

新版本添加NOT NULL约束时,老数据如果存在NULL会导致PG::CheckViolation。

# 1.检查是否存在NULL数据(注意:state字段为smallint整数类型,0代表active)

docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "SELECT count(*) FROM namespaces WHERE state IS NULL;"

# 2.批量回填默认值(0表示正常激活状态)

docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "UPDATE namespaces SET state = 0 WHERE state IS NULL;"

 阶段三:处理后台批处理迁移(BBM)挂起与收尾

某些常规迁移(如表分区收尾Finalise...)会强制检查对应的后台批处理任务是否已完成。如果后台任务处于异常状态(如状态5:execution_error),常规迁移会直接中断。

1.查询当前后台任务状态分布

docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "SELECT status, count(*) FROM batched_background_migrations GROUP BY status;"

BBM常见状态码语义:

0: paused(已暂停)

1: active(执行中)

3: finished(已完成)

4/5: failed / execution_error(失败/出错挂起)

6: finalized(已终结/完全收尾)

2.定位阻断迁移的具体任务

以定位Commit分区任务为例:

docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "SELECT id, job_class_name, table_name, column_name, status FROM batched_background_migrations WHERE job_class_name ILIKE '%Commit%';"

3.解除阻塞(二选一)

方案A(官方Rake任务在线强制收尾):

 #格式:gitlab:background_migrations:finalize[任务类名,表名,主键列名, '参数JSON']

docker exec -it gitlab gitlab-rake "gitlab:background_migrations:finalize[BackfillMergeRequestDiffCommitsToPartitioned,merge_request_diff_commits,merge_request_diff_id,'[\"merge_request_diff_commits_b5377a7a34\"]']"

方案B(数据库直接放行,适用于急需恢复系统):

 #将挂起的子任务更新为成功(3 = succeeded)

 docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "UPDATE batched_background_migration_jobs SET status = 3 WHERE batched_background_migration_id = 334;"

#将主后台任务标记为已终结(6 = finalized)

docker exec -it gitlab gitlab-psql -d gitlabhq_production -c \

  "UPDATE batched_background_migrations SET status = 6 WHERE id = 334;"

 阶段四:恢复常规迁移与服务重构

解除前置阻碍后,按顺序跑完常规迁移并拉起全套组件。

 # 1.恢复执行未完成的数据库迁移

 docker exec -it gitlab gitlab-rake db:migrate

 # 2.检查是否还有处于down状态的迁移(无输出即代表全部成功通过)

 docker exec -it gitlab gitlab-rake db:migrate:status | grep " down "

 # 3.重新配置并拉起全部服务(Puma、Sidekiq、Nginx等)

 docker exec -it gitlab gitlab-ctl reconfigure

 # 4.查看各组件运行状态

 docker exec -it gitlab gitlab-ctl status

 阶段五:健康检查与系统验证

# 1.执行官方全方位健康检查(检查项目归属、存储、Gitaly、Shell、上传文件等)

docker exec -it gitlab gitlab-rake gitlab:check

# 2.验证后台批处理迁移中是否存在异常任务(输出为空[]即为完全健康)

docker exec -it gitlab gitlab-rails runner \

  "puts Gitlab::Database::BackgroundMigration::BatchedMigration.where.not(status: [1, 3, 6]).pluck(:id, :job_class_name, :status)"

 # 3.查看容器健康状态

 docker ps | grep gitlab

二、关键运维注意事项

1.数据库操作层面

严禁随意删除或截断表(DROP / TRUNCATE / DELETE): 历史脏数据(如NULL)只能通过UPDATE回填默认值,绝对不可直接DELETE,否则会触发级联删除,导致关联的项目、分支、权限历史被破坏。

确认字段数据类型:状态枚举多为整型(如namespaces.state是smallint,用0表示active)。切勿使用字符串赋值,避免触发类型转换报错回滚。

避免强杀PostgreSQL进程: 清理死锁时只杀Advisory咨询锁会话,切勿执行宿主机kill -9,防止触发PostgreSQL崩溃恢复机制导致停机时间大幅拉长。

2.后台批处理迁移(BBM)层面

升级前必须确认BBM全部跑完: 这是绝大多数升级故障的根源。在跨版本升级前,必须确保status = 1(运行中)为0,且没有失败/挂起的任务。

不要频繁重复触发批量重试:当任务处于status = 1时代表后台Worker正在消费队列,重复触发可能导致多个Worker争抢同一批次,加剧数据库锁竞争。

注意状态码在版本间的语义:当前新版本中,主迁移表的status = 3代表finished(已完成正常状态),切勿当成失败强行调用retry_failed_jobs!。

3.容器与服务运维层面

迁移期间严禁强行中断(Ctrl+C或 重启容器): 当执行gitlab-rake db:migrate处理大表分区时,终端可能长时间无日志刷新,后台仍在扫描数据。强杀会导致任务状态落入不一致。

必须等数据库迁移完成后再执行gitlab-ctl reconfigure: 若数据库仍有大量down迁移,执行reconfigure大概率失败或产生新的配置死锁。

升级前务必备份配置与密钥:关键文件(特别是gitlab-secrets.json和gitlab.rb)必须做本地备份:

tar -czvf gitlab_config_backup_$(date +%F).tar.gz /path/to/gitlab/config