文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

GitHub Enterprise 2.0 版本带来不只是新特性以及主持在亚马逊 AWS 上的部署的功能外,同时该版本重写了我们的虚拟机架构,提升了性能和可靠性。 我们使用了简单直接的方法对这些变化进行了基准测试。 通过测试的数据以及一些我们常用的 Unix 工具, 我们可以发掘,调试, 并最终为我们的企业客户解决了一些有趣的性能问题。

编写基准测试

我们考虑了一些基准测试解决方案用来测试重要功能的性能表现,例如 git clone 操作。最后,我们选择了一个简单而有效的解决方案:同时在运行企业版的服务器上运行一系列的脚本 git clone 命令。

第 1 段(可获 2 积分)

这种方法给了我们一个很好的起点,看看Enterprise 在非常大的使用情况下的表现。

基准性能

我们首先使用GitHub.com运行我们的脚本,以获取一些初始数字与Enterprise虚拟机进行比较。

基准测试脚本通过HTTPS或SSH从github/gitignore存储库克隆数据。 我们选择这个存储库,因为它很小,但仍然有一些现实的活动。 在基准测试中,我们提高了并发克隆的数量,以便了解VM如何处理越来越重的负载。 这也是一种确定基准脚本自身可以从单个客户端生成的负载量的方法。

第 2 段(可获 2 积分)

在每次克隆之后,我们的脚本将输出具有开始时间,操作持续时间和克隆的退出状态的时间戳。 然后用matplotlib绘图,生成如下图:

git clone over HTTPS against github.comgit clone over SSH against github.com

左侧是以毫秒为单位的克隆时间,以对数刻度绘制。 绿色框图和绿色标记显示所收集的克隆时间样本。 绿色框内的线表示中值。 框的顶部表示第75个百分位数,而框的底线表示第25个。 “须”表示四分位数范围。 单独绘制该范围之外的测量值。

第 3 段(可获 2 积分)

在右边它显示每秒处理的git操作数。 此数字由图中的蓝色线标识。 基准化运行中的任何错误在图表中表示为红色的X。

Enterprise 11.10.x

对GitHub.com的基准测试提供了一个基线,以确定我们的客户可以产生多少负载。 现在是时候针对现有的Enterprise 11.10.x 虚拟机收集数据了。 我们认为这是我们在任何升级中需要保持的最低基准性能(尽管我们的意图是对11.10.虚拟机的重大改进)。

第 4 段(可获 2 积分)

对于这个简单的基准测试,我们为每个企业版本设置了两台相同的机器。 这里是对 Enterprise 11 进行的 HTTPS 和 SSH 克隆测试数据。10 x:

git clone over HTTPS against Enterprise 1git clone over SSH against Enterprise 1

Enterprise 2

现在开始对 Enterprise 2 进行第一次基准测试(重复, 先是 HTTPS 再进行 SSH)。

git clone over HTTPS against Enterprise 2git clone over SSH against Enterprise 2

结果不太好!错误率非常高而且性能很差。

我们估计性能差的原因跟这些错误有关系, 同时我们发现很多的请求在一分钟后超时,没有完成请求过程。 现在需要深入挖掘一下这些问题的原因了。

第 5 段(可获 2 积分)

初始性能改进

我们登录到Enterprise 2测试实例,启动strace,立即发现每次克隆,许多Ruby进程作为我们 post-receive hooks的一部分被加载。 @simonsj 承认在GitHub.com我们已经使用了更快的hook设置,所以我们移植到Enterprise 2。虽然这种变化有助于消除很多性能开销,我们仍然看到大量的错误。 更多挖掘的时间。

错误日志

我们通过日志文件查找此克隆路径中涉及的组件。 在GitHub.com上,现在在Enterprise 2上(但不在Enterprise 11.10.x上),我们运行一个名为babeld的内部C守护进程来路由并通过不同的协议提供所有的Git流量。 所以我们认为babeld和HAProxy(位于babeld前面)的日志是一个很好的起点:

第 6 段(可获 2 积分)
Thu Sep 18 00:50:59 2014 pid=6712 tid=18817 version=e594222 proto=http http_url=/ghe-admin/gitignore.git/git-upload-pack ip=172.16.9.25 user=ghe-admin repo=ghe-admin/gitignore cmd=git-upload-pack duration_ms=15819.033771 fs_bytes_sent=0 fs_bytes_received=0 bytes_from_client=708 bytes_to_client=0 log_level=ERROR msg="http op done: (-1) localhost" code=-1
Thu Sep 18 00:52:16 2014 pid=6712 tid=27175 version=e594222 proto=http http_url=/ghe-admin/gitignore.git/info/refs?service=git-upload-pack ip=172.16.9.25 user=ghe-admin repo=ghe-admin/gitignore duration_ms=15803.741230 fs_bytes_sent=0 fs_bytes_received=0 bytes_from_client=434 bytes_to_client=0 log_level=ERROR msg="http op done: (-1) localhost" code=-1
Thu Sep 18 00:52:18 2014 pid=6712 tid=27699 version=e594222 proto=http http_url=/ghe-admin/gitignore.git/info/refs?service=git-upload-pack ip=172.16.9.25 user=ghe-admin repo=ghe-admin/gitignore duration_ms=15801.913778 fs_bytes_sent=0 fs_bytes_received=0 bytes_from_client=434 bytes_to_client=0 log_level=ERROR msg="http op done: (-1) localhost" code=-1
第 7 段(可获 2 积分)

这些日志行中的log_level属性指示问题的类型。 ERROR表示有问题,msg属性显示实际错误。 通常它显示返回的HTTP状态,但状态为-1表示它甚至不能从上游接收响应。 这里的HTTP调用命中了一个名为gitauth的服务(它确定用户对Git操作的访问级别)。 也许我们的基准是以耗尽gitauth这样的方式,以至于它不能快速回复我们的身份验证请求。

babeld有一个内部队列长度,它设置发送到gitauth未完成的请求数。 这个限制设置为16,基于我们在GitHub.com上运行了多少gitauth工作。 然而,在Enterprise 2上,我们只有两到四个这样的工作,所以16的挂起队列能够使后台过载。 @simonsj打开了一个pull请求,允许我们根据需要配置gitauth设置。

第 8 段(可获 2 积分)

我们在认证阶段解决了这个问题,但是我们仍然看到Git客户端挂起。 这意味着我们不得不看看babeld连接到git-daemon以运行实际Git命令的过程中的下一步。 我们注意到连接到git守护进程超时,表明守护进程不接受连接。 这个问题体现在我们的测试中Git客户端无限期地挂起。 所以继续调试。

防火墙配置

接下来,我们在测试机上查看dmesg。 我们在防火墙触发的日志中看到了这样的条目:

第 9 段(可获 2 积分)
[Fri Sep 12 17:37:24 2014] [UFW BLOCK] IN=eth0 OUT=
MAC=00:0c:29:f8:e4:b8:00:1c:73:4a:03:21:08:00 SRC=172.16.9.25
DST=172.16.20.244 LEN=40 TOS=0x00 PREC=0x00 TTL=60 ID=10484 DF PROTO=TCP
`SPT=59066 DPT=443 WINDOW=0 RES=0x00 RST URGP=0
[Fri Sep 12 17:37:24 2014] [UFW BLOCK] IN=eth0 OUT=
MAC=00:0c:29:f8:e4:b8:00:1c:73:4a:03:21:08:00 SRC=172.16.9.25
DST=172.16.20.244 LEN=40 TOS=0x00 PREC=0x00 TTL=60 ID=10485 DF PROTO=TCP
SPT=59066 DPT=443 WINDOW=0 RES=0x00 RST URGP=0

这些似乎是阻塞端口重置被发送回客户端,这可能合理的解释了他们挂起的原因。 所以我们修复了防火墙问题,但是仍然没有解决所有的客户端挂起。

第 10 段(可获 2 积分)

Tcpdump调试

接下来是tcpdump,一个经典的Unix工具,我们经常在GitHub使用来调试网络问题。

tcpdump of a git client session

来自Wireshark的屏幕截图显示,虽然我们发送一个HTTP / 1.1请求并且响应 200 OK,但实际上我们从来没有发送任何数据包,Git客户端因为没有不能正确反序列化的数据而挂起。

SYN数据包和侦听积压

我们意识到我们错过了一个重要的线索在dmesg输出后。 我们会不时看到这个条目:

[ 1200.354738] TCP: Possible SYN flooding on port 9000. Sending cookies.
Check SNMP counters.
第 11 段(可获 2 积分)

git-daemon运行在端口9000,这与我们猜测git-daemon是一个影响因素相吻合。 更多的Unix工具是为了让我们查看netstat -s的输出,看看是否可以收集更多的信息。 netstat确实向我们显示了两个非常有用的消息:

    10421 times the listen queue of a socket overflowed
    10421 SYNs to LISTEN sockets dropped

啊哈! 这表明我们可能实际上没有接收git-daemon的连接,这将导致这些奇怪的错误,并一直挂起客户端。

在这一点上,@scottjg 想起了几个月前,他为git-daemon行为更改的一个pull请求。 这个问题似乎是类似的,babeld不能与git守护进程对话。 这从来没有被证明是生产环境中的一个真正的问题,但绝对似乎与我们在这里看到的有关。

第 12 段(可获 2 积分)

为了确认这个问题,我们来看看strace来观察git-daemon正在做的listen调用。 我们的假设是,我们配置错误,导致一个非常小的连接积压。 下面的输出显示了git-daemon设置其套接字以侦听传入客户端的部分。

sudo strace -tt -f git daemon --init-timeout=1
--base-path=/data/repositories --max-connections=0 --port=9000
--listen=127.0.0.1 --reuseaddr --verbose --sys
...
[pid 18762] 19:09:00.706086 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) =
3
[pid 18762] 19:09:00.706121 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1],
4) = 0
[pid 18762] 19:09:00.706152 bind(3, {sa_family=AF_INET,
sin_port=htons(9000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
[pid 18762] 19:09:00.706189 listen(3, 5) = 0
[pid 18762] 19:09:00.706219 fcntl(3, F_GETFD) = 0
[pid 18762] 19:09:00.706244 fcntl(3, F_SETFD, FD_CLOEXEC) = 0
...
第 13 段(可获 2 积分)

事实上,listen(3,5)系统调用意味着我们监听数值为3的文件描述符,但是我们只允许5个连接的积压。 因为这么小的积压设置,如果git-daemon稍微过载,我们就会丢弃传入的连接,这将导致我们观察到的丢弃SYN数据包现象。

集成所有修正

在所有的调试和所有这些修复 - 包括防火墙改进,挂钩性能改进,当然,还有改变git-daemon积压设置之后- 我们最终得到了一些新的基准数字。

git clone over HTTPS against improved Enterprise 2git clone over SSH against improved Enterprise 2

结果好多了。 我们将HTTPS的吞吐量提高了近一倍,而SSH提高了三倍。 我们还在基准测试的并发级别擦除了错误。

第 14 段(可获 2 积分)

经验教训

我们对这些基准测试的结果非常满意,当然,我们能够成功调试我们看到的问题,我们感到非常高兴。 最重要的是,我们的客户看到了很好的结果。 Spotify在AWS上升级到Enterprise2后向我们发送了聚合系统负载的图表:

Spotify performance improvements

第 15 段(可获 2 积分)

文章评论