Google宣布Git协议迎来重大更新,性能大幅提升

百家 作者:聊聊架构 2018-05-19 10:00:31

来自 Git 团队的 Brandon Williams 在博客上宣布正式推出 Git 协议 v2,这是对 Git 线路协议(wire protocol)的一个重大更新。此次更新移除了 Git 协议中最低效的部分,修复了一个扩展性瓶颈问题,并为未来更多的线路协议改进提供可能性。

协议 v2 的规范可以https://www.kernel.org/pub/software/scm/git/docs/technical/protocol-v2.html 找到。主要改进包括:

  • 服务器端的引用过滤。

  • 扩展新特性变得更容易,如 ref-in-want 及 symref 的拉取和推送。

  • 简化 HTTP 客户端处理。

新版本协议的主要目标是支持服务器端引用(分支和标签)过滤。在协议 v2 之前,服务器在向 fetch 命令做出响应时,会列出仓库中所有的引用。即使客户端只想更新单个分支,例如“git fetch origin master”,服务器端也会向它发送整个引用清单。

对于包含成千上万个引用的仓库(Chromium 仓库有超过 50 万个分支和标签),服务器可能会发送数十兆字节的数据,而这些数据最终将被忽略。这通常会浪费时间和带宽,特别是在更新只包含少量提交的远程分支时,或者有时候只想检查代码是否是最新的。

Git 团队最近为谷歌提供协议 v2 支持,他们发现,在包含 50 万个引用的仓库中,单个分支 fetch 操作的性能提高了 3 倍。协议 v2 还将从 googlesource.com 服务器发送出来的字节数减少到原先的八分之一。这项改进要归功于服务器端对引用进行了过滤,只返回客户端需要的引用。

克服障碍

在过去几年,Git 项目多次尝试限制初始引用,或者使用新的协议,但仍然存在两个问题:

  • 初始请求太过死板,请求消息里不包含这样的一个字段,可用于在不破坏与现有服务器兼容性的情况下请求新服务器修改响应消息。

  • 错误处理机制不够完善,无法在现有服务器不兼容新协议时安全快速地回退到旧协议。

为了迁移到新的协议版本,Git 团队需要找到一种方式,既可以让现有服务器忽略不兼容部分,又可以安全地与新服务器通信。

Git 的连线协议包含了三种主要的传输方式(Git://、ssh:// 和 https://)。HTTP 传输方式是最简单的,可以在请求中包含额外的 HTTP 消息头(如“Git-Protocol: version=2”)。SSH 传输方式稍难一些,因为它需要将一个环境变量(如“GIT_PROTOCOL=version=2”)发送到远程终端上。这更具有挑战性,因为它要求管理员在服务器端配置 sshd,这样才能接收到新的环境变量。最难的传输方式是匿名 Git 传输(Git://)。

使用匿名 Git 传输方式向服务器发出的初始请求使用了单个 packet-line 的格式,其中包含了请求的服务和仓库地址,后面再跟上一个 NUL 字节。后来又添加了虚拟化支持,并且可以附加主机名参数,并使用 NUL 字节作为结束符:“0033git-upload-pack /project.githost=myserver.com”。在理想情况下,可以添加一个新的参数来发起协议 v2 请求,就像添加主机名那样:“003dgit-upload-pack /project.githost=myserver.comversion=2”。

可惜的是,由于在 2006 年引入了一个 bug,导致不能添加主机名以外的任何参数,否则在解析这些参数时将进入一个死循环。这个 bug 在 2009 年得到了修复,添加了一个检查条件,不允许添加额外的参数,这样新客户就不会在老服务器上触发这个 bug。

幸运的是,如果在第二个 NUL 字节后面放置额外的请求参数,这个检查条件就不会注意到。请求可以变成这样:“003egit-upload-pack /project.githost=myserver.comversion=2”。通过在第二个 NUL 字节后面放置版本信息,就可以绕过死循环错误,同时又可以添加新的参数。只有新服务器知道如何找到隐藏在两个 NUL 字节后面的附加信息,而旧服务器不会发出任何警告。

现在,客户端可以发起使用协议 v2 的请求,协议 v2 服务器可以使用新的协议做出响应,而旧服务器则会忽略它们。

动手体验

要想体验一下协议 v2,需要安装 Git 的最新版本(支持协议 v2 的代码已经合并到 Git master 分支,预计作为 Git 2.18 的一部分)和启用了协议 v2 的服务器(googlesource.com 和 Cloud Source 上的仓库已经启用了协议 v2)。如果启用了追踪选项,在发送“ls-remote”命令查询单个分支时,可以看到服务器发送的引用数量要小得多。

# 使用旧协议

GIT_TRACE_PACKET=1 git -c protocol.version=0 ls-remote 
https://chromium.googlesource.com/chromium/src.git master
# 使用新协议
GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote 
https://chromium.googlesource.com/chromium/src.git master

如果,Google 早已解决不了你的问题。

如果,你还想知道 Apple、Facebook、IBM、阿里等国内外名企的核心架构设计。

来,我们在深圳准备了 ArchSummit 全球架构师峰会,想和你分享:

  • 微信百亿消息背后的万级机器是怎么做 AI 调度的

  • 滴滴三核心引擎之一的地图,如何计算路径规划和道路匹配

  • 微博如何做万亿级关系的实时协同推荐

  • 微众区块链首席架构师的两个具体案例实操

  • 罗辑思维 Go 语言微服务完整改造全过程

  • 阿里菜鸟全球跨域 RPC 架构设计

  • 前特斯拉视觉深度学习负责人带来的核心技术解析

  • 微服务楷模 Netflix 在 FaaS 上的最新实践

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接
百度热搜榜
排名 热点 搜索指数