使用WebSockets超级加速GitLab CI状态更新

本文详细介绍如何通过WebSockets和GraphQL订阅将GitLab CI作业状态更新的API调用从每日4500万次减少到340万次,实现实时状态更新,显著提升用户体验和系统性能。

使用WebSockets超级加速GitLab CI状态更新

我们刚刚将GitLab CI作业状态更新的API调用减少了92.56%——从每日4500万次降至340万次。用户现在可以即时看到作业状态变化,而无需等待长达半分钟。以下是我们的实现方法。

问题:2025年的轮询机制

在2025年,WebSockets已经成为主流,而轮询则已过时。轮询更像是获取软件"实时"更新的传统方法。它是时间驱动的,意味着客户端按固定间隔(通常为5到30秒)向服务器发起网络调用。即使数据没有变化,这些网络请求也会被执行,以尝试向客户端提供最准确的数据。

WebSockets是事件驱动的,因此只有在数据实际发生变化时(例如,数据库列中的状态从pending变为running)才向服务器发起网络请求。与客户端重复向服务器请求更新的传统HTTP请求(轮询)不同,WebSockets在客户端和服务器之间建立了持久的双向连接。这意味着服务器可以在发生变化时立即将更新推送到客户端,从而消除不必要的网络流量并减少延迟。对于监控作业状态或实时数据,这比让客户端每隔几秒轮询服务器以检查是否有变化要高效得多。

转型过程

之前,作业日志视图中的作业标头使用轮询来获取单个作业的最新状态。该组件无论情况如何,每30秒就会发起一次网络请求,以尝试获取作业的真实状态。

我们的指标显示:

  • 每15分钟发生547,145次网络调用
  • 每24小时发生45,729,530次网络调用

用户在查看状态更新时经历了令人沮丧的延迟,而且我们正在严重冲击数据库。

引入GraphQL订阅

于是我们引入了基于WebSockets的GraphQL订阅。GraphQL订阅是一项功能,它将GraphQL从简单的请求-响应查询和变更扩展到允许客户端与服务器保持实时连接。虽然常规的GraphQL查询会一次性获取数据并返回,但订阅让您能够说"每当这个特定数据发生变化时通知我"。在底层,GraphQL订阅通常使用WebSockets来维持这种持久连接。以下是我们所做的:

首先,我们重构了作业标头组件,使用GraphQL获取其数据 然后我们实现了GraphQL订阅,通过ActionCable(Rails的WebSocket框架)提供实时更新

成果

实施后,我们的用户现在能够获得真正实时的准确作业状态——当作业状态改变时,更新会立即显示。性能提升显著:

  • 该组件的API调用减少了92.56%
  • 现在平均每15分钟39,670次网络调用(从547,145次下降)
  • 每24小时仅3,403,395次网络调用(从45,729,530次下降)

我们还监控了过去一周的CPU利用率和每个命令的操作速率,没有发现服务有任何显著增加。这对软件和团队来说是双赢。

下一步计划

这仅仅是个开始。我们正在努力使GitLab产品中的每个CI状态都实现实时更新。目前,GitLab用户界面的许多部分仍然依赖轮询来检查更新。我们的目标是系统地用GraphQL订阅替换这些轮询机制,在整个CI/CD工作流程中为用户提供即时反馈。

想亲眼看看这个功能吗?查看任何作业日志视图,观察那些状态更新的飞速变化。还不是GitLab用户?免费试用30天的GitLab Ultimate与GitLab Duo Enterprise。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计