在CI/CD流水线的日常运维中,GitLab CI作为主流的持续集成平台,其Web界面的响应速度直接影响着开发人员的使用体验。但很多团队会发现,随着项目增多和运行时间增长,GitLab的前端加载变得越来越慢。本文记录了一次真实的GitLab CI前端性能问题排查经历,从现象分析到根因定位,再到系统性优化,希望能为遇到类似问题的读者提供参考。
一个让人烦躁的加载过程
某天上午,开发团队陆续反馈GitLab的页面打开变得非常慢。具体表现是这样的:
登录GitLab后,项目列表页面需要等待十几秒才能完整显示。进入具体的CI/CD流水线页面,构建日志区域一直显示加载中,要等很久才能看到内容。点击各个标签页切换时,浏览器有明显的卡顿感。刷新页面后,情况并没有改善,依然很慢。
运维人员登录服务器查看系统状态,发现CPU和内存使用率都在正常范围内,磁盘IO也没有异常。进程都正常运行,没有出现僵尸进程或资源泄漏的迹象。
问题出在哪里呢。
排查过程
第一步:观察浏览器端的情况
打开浏览器的开发者工具,切换到网络标签,清空缓存后刷新GitLab页面。观察所有请求的加载情况,发现了一些异常。
有很多JavaScript文件加载时间很长,有的甚至超过十秒。这些文件大小不大,但就是卡在那里不动。还有一个特殊的请求引起了注意。
这个请求是/assets/application-xxx.css,状态码是200,但等待时间很长。进一步查看这个请求的详细信息,发现响应头里的Last-Modified时间是一周前的,而Cache-Control设置的是max-age=0,也就是说浏览器每次都要重新请求这个文件。
第二步:查看服务器的响应情况
在GitLab服务器上查看生产日志,找到了线索。
tail -f /var/log/gitlab/gitlab-rails/production.log日志里出现了一堆警告信息。大概意思是资产预编译步骤耗时过长,超过了设定的阈值。还有不少请求在等待数据库连接池的释放。
这说明问题不在网络层面,而在GitLab应用内部的处理上。
第三步:检查资产编译状态
GitLab的前端资源需要通过资产预编译来生成。如果预编译过程出问题,前端加载就会受影响。
# 查看资产编译状态 sudo gitlab-rails runner "puts Rails.application.config.assets.compile" # 输出为 true这个输出说明GitLab被配置为在运行时动态编译资产,而不是使用预编译好的静态文件。这是导致页面加载慢的根本原因。
当config.assets.compile为true时,每次用户访问页面,Rails都会检查资产文件是否需要重新编译。如果有多个用户同时访问,服务器就要处理多次编译请求,CPU和内存消耗大幅增加,响应时间自然就上去了。
第四步:深入分析资产预编译过程
继续查看更详细的日志,发现了具体的瓶颈。
sudo gitlab-rails runner "Assets.precompile"执行这个命令后,编译过程持续了好几分钟,中间输出了一大堆警告。很多JavaScript文件在编译时出现了依赖缺失的提示,还有些CSS文件的引用路径找不到对应的资源。
这些问题导致编译过程异常缓慢,而且编译出来的文件也可能不完整。
问题的根源
通过上述排查,问题的根源逐渐清晰。
资产预编译配置不当是主因。GitLab默认配置下,config.assets.compile为false,会使用预编译好的静态文件。但这个环境中该配置被改成了true,导致每次请求都要动态编译。
依赖缺失加剧了问题。部分JavaScript库和CSS框架在编译时找不到依赖,导致编译过程反复重试,进一步拖慢了速度。
并发请求放大了影响。多个用户同时访问时,每个请求都可能触发编译,服务器资源被大量占用,形成恶性循环。
解决方案
紧急修复:切换到预编译模式
最简单的修复办法是把动态编译关掉,改用预编译的静态文件。
编辑GitLab的配置文件。
sudo vi /etc/gitlab/gitlab.rb找到下面这一行,取消注释并把值改为false。
gitlab_rails['assets_compile'] = false保存文件后,重新配置GitLab。
sudo gitlab-ctl reconfigure这个操作会触发一次完整的资产预编译,生成所有需要的静态文件。整个过程可能需要几分钟,取决于服务器性能和资产数量。
重新配置完成后,刷新GitLab页面,加载速度明显改善。原来十几秒的页面现在三五秒就能打开,构建日志的加载也快了很多。
根本修复:重新编译完整的资产
紧急修复解决了燃眉之急,但那些依赖缺失的问题依然存在,可能会在其他地方引发问题。需要完整地重新编译一次资产。
# 清理旧的编译产物 sudo rm -rf /var/opt/gitlab/gitlab-rails/public/assets/* # 强制重新编译所有资产 sudo gitlab-rails assets:clobber sudo gitlab-rails assets:precompile编译完成后,重启GitLab服务。
sudo gitlab-ctl restart长期优化:建立系统性的性能保障机制
解决了当前问题后,还需要从长远角度优化GitLab的性能。
系统性的优化方案
一、合理的资源缓存策略
通过配置合适的缓存策略,减少不必要的重复请求。
在GitLab的Nginx配置中,为静态资源设置较长的缓存时间。
location ~ ^/assets/ { expires 1y; add_header Cache-Control "public, immutable"; }这样设置后,浏览器会缓存这些资源一年,除非用户主动清除缓存,否则不会再向服务器请求这些文件。
二、定期清理无用的构建产物
GitLab的CI/CD流水线会产生大量的构建日志和产物,这些文件长期堆积会拖慢数据库查询和页面渲染。
设置自动清理策略。
# 在gitlab.rb中配置 gitlab_rails['artifacts_enabled'] = true gitlab_rails['artifacts_days_to_keep'] = 30这个配置会让GitLab自动删除超过30天的构建产物。对于需要长期保留的重要产物,可以单独标记为永久保留。
三、优化数据库查询性能
GitLab的前端很多页面都需要查询数据库。如果数据库查询慢,前端加载自然就慢。
启用慢查询日志,找出那些执行时间过长的SQL语句。
sudo gitlab-ctl tail postgresql观察日志中执行时间超过100毫秒的查询,分析它们的执行计划,看看是否需要添加索引。
四、配置合适的Puma工作进程数
Puma是GitLab使用的应用服务器,它的工作进程数配置直接影响并发处理能力。
ruby
# 在gitlab.rb中配置 puma['worker_processes'] = 2 puma['min_threads'] = 1 puma['max_threads'] = 16工作进程数不是越多越好,通常设置为CPU核心数的一半到一倍之间。线程数可以根据应用的内存和响应时间来调整。
五、使用Redis缓存会话和页面片段
GitLab大量使用Redis来缓存会话信息、页面片段和Sidekiq任务队列。确保Redis配置合理,内存充足。
# 查看Redis内存使用情况 sudo gitlab-redis-cli info memory如果Redis内存占用过高,可以考虑增加Redis的最大内存限制,或者配置内存淘汰策略。
日常运维建议
定期检查日志
每天抽出几分钟查看GitLab的错误日志和慢查询日志,及时发现潜在问题。
sudo gitlab-ctl tail gitlab-rails/production.log | grep "Completed 500" sudo gitlab-ctl tail postgresql | grep "duration"监控关键指标
关注几个核心的系统和应用指标。
CPU和内存使用率,特别是GitLab相关进程的消耗。数据库连接池的使用情况,避免连接数达到上限。磁盘空间,尤其是存放构建产物和Git仓库的目录。Redis的内存占用和命中率。
版本升级时的注意事项
GitLab升级时,资产预编译是容易出问题的环节。
升级前先备份整个GitLab实例,包括配置文件、数据库和仓库数据。升级过程中留意编译日志,如果有依赖缺失的警告,提前安装相应的系统包。升级完成后验证所有核心功能是否正常,特别是文件上传、CI/CD执行、Web界面加载这些关键路径。
故障应急流程
当GitLab前端再次出现慢加载问题时,按照这个顺序排查。
先用浏览器开发者工具确认慢的是哪个请求,是CSS、JS还是API接口。
如果发现是静态资源慢,检查资产预编译配置是否正确,查看是否有大量的动态编译日志。
如果是API接口慢,查看Rails日志中对应请求的耗时分布,看看慢在数据库查询、视图渲染还是外部调用。
如果原因不明确,执行一次完整的资产预编译,重新生成静态文件。
在最坏的情况下,可以临时切换到一个干净的环境,逐步恢复配置,隔离问题。
总结
GitLab CI前端加载慢的问题,往往不是单一因素导致的。资产预编译配置不当可能是导火索,但背后的深层原因可能包括依赖缺失、数据库性能下降、缓存策略不合理等多个方面。
解决这类问题需要系统性的思维。从浏览器端观察到服务器端分析,从紧急修复到长期优化,每个环节都不能忽视。
最好的运维不是出了问题能快速修复,而是让问题不容易发生。建立完善的监控体系,定期检查关键指标,提前发现性能劣化的趋势,这才是运维工作的核心价值。
每次故障都是一次学习的机会。记录排查过程,总结根因,形成文档,这些积累比任何技术都更有价值。当类似问题再次出现时,你就能快速定位,从容应对。