【问题标题】:git pull over SSH performance issue with Atlassian Stash (stuck for 7 seconds on git-upload-pack)git 使用 Atlassian Stash 解决 SSH 性能问题(在 git-upload-pack 上卡住 7 秒)
【发布时间】:2015-11-16 17:41:33
【问题描述】:

我有一个使用 Atlassian Stash 的小型 Git 存储库。该 repo 有大约 250 个文件,历史不多,而且文件都很小 - 总 repo 大小约为 10MB。

在许多情况下,Git pull(仅返回“已经是最新的”)超过 8 秒。

设置 GIT_TRACE 后,显示如下:

23:35:25.109710 git.c:555               trace: exec: 'git-pull'
23:35:25.109745 run-command.c:351       trace: run_command: 'git-pull'
23:35:25.122176 git.c:346               trace: built-in: git 'rev-parse' '--git-dir'
23:35:25.131460 git.c:346               trace: built-in: git 'rev-parse' '--is-bare-repository'
23:35:25.132926 git.c:346               trace: built-in: git 'rev-parse' '--show-toplevel'
23:35:25.134679 git.c:346               trace: built-in: git 'ls-files' '-u'
23:35:25.136349 git.c:346               trace: built-in: git 'symbolic-ref' '-q' 'HEAD'
23:35:25.139419 git.c:346               trace: built-in: git 'config' 'branch.master.rebase'
23:35:25.142520 git.c:346               trace: built-in: git 'config' 'pull.rebase'
23:35:25.144089 git.c:346               trace: built-in: git 'config' 'pull.ff'
23:35:25.145995 git.c:346               trace: built-in: git 'rev-parse' '-q' '--verify' 'HEAD'
23:35:25.147660 git.c:346               trace: built-in: git 'fetch' '--update-head-ok'
23:35:25.148347 run-command.c:351       trace: run_command: 'ssh' '-p' '7999' 'git@smsvcs' 'git-upload-pack '\''/srm/srm.git'\'''
23:35:31.758436 run-command.c:351       trace: run_command: 'rev-list' '--objects' '--stdin' '--not' '--all' '--quiet'
23:35:31.761165 run-command.c:351       trace: run_command: 'rev-list' '--objects' '--stdin' '--not' '--all'
23:35:31.761307 exec_cmd.c:129          trace: exec: 'git' 'rev-list' '--objects' '--stdin' '--not' '--all'
23:35:31.762459 git.c:346               trace: built-in: git 'rev-list' '--objects' '--stdin' '--not' '--all'
23:35:33.806938 run-command.c:351       trace: run_command: 'gc' '--auto'
23:35:33.807048 exec_cmd.c:129          trace: exec: 'git' 'gc' '--auto'
23:35:33.808245 git.c:346               trace: built-in: git 'gc' '--auto'
23:35:33.809709 git.c:346               trace: built-in: git 'rev-parse' '-q' '--verify' 'HEAD'
23:35:33.813711 git.c:346               trace: built-in: git 'fmt-merge-msg'
23:35:33.818468 git.c:346               trace: built-in: git 'merge' 'Merge branch '\''master'\'' of ssh://smsvcs:7999/srm/srm' 'HEAD' 'f77e569b202ef7674dc30d219e71b2587e87f708'
Already up-to-date.

最大的延迟似乎发生在 23:35:25.148347,同时它正在通过 SSH 运行 git-upload-pack(它需要超过 6.5 秒)。

SSH 连接非常快:

=->time ssh xyz@smsvcs 'echo test'
test

real    0m0.136s
user    0m0.009s
sys     0m0.001s

第二大延迟是在 23:35:33.806938,它是 2 秒 - 运行 rev-list。

这是在 Red Hat Enterprise Linux Server 版本 5.11 (Tikanga) 上, git 版本 2.3.2

任何想法可能导致这些性能问题,或者如何进一步排除故障?

【问题讨论】:

  • 您使用的是什么 Git 版本和操作系统?您的本地克隆是存储在本地磁盘上还是网络路径上?
  • @VonC:本地克隆存储在本地磁盘上
  • 好的。您使用的是什么 Git 版本和操作系统?
  • 谁否决了我的问题,请提供原因。我遇到了 Atlassian Stash/git 性能问题,我正在尝试解决它,但我被卡住了。为什么投反对票?
  • 我没有投反对票,为了记录。但我仍然想知道您使用的是什么 Git 版本和操作系统。

标签: git git-pull bitbucket-server


【解决方案1】:

我增加了 Stash 服务器内存并将其退回(仅通过重启肯定无法解决该问题 - 我之前尝试过重启)。 git-upload-pack 的 8 秒延迟消失了。

更改是在 bin/setenv.sh 中完成的:

-JVM_MINIMUM_MEMORY="256m"
-JVM_MAXIMUM_MEMORY="512m"
+JVM_MINIMUM_MEMORY="1G"
+JVM_MAXIMUM_MEMORY="2G"

【讨论】:

  • 不错的收获。这可以帮助其他人。 +1。有关如何增加 Stash Server 内存的详细信息?
【解决方案2】:

正如我在其他答案中提到的(关于 protocol v2pack files),添加 Git Wire Protocol, Version 2 改变了 Git 传输协议的工作方式。
它是default one since Git 2.26

特别是,git fetch 会更快,因为最近发生了变化:

在 Git 2.33(2021 年第三季度)中,“git fetch(man) 在协议 v2 完成讲话后,它的套接字一侧保持打开状态,这不必要地浪费了另一边。

参见Jeff King (peff)commit ae1a7ee(2021 年 5 月 19 日)。
(由 Junio C Hamano -- gitster -- 合并于 commit 4dd75a1,2021 年 6 月 14 日)

fetch-pack: 向 v2 服务器发出信号,我们已完成请求

报告人:Greg Pflaum
签字人:Jeff King

当使用 v0 协议通过 ssh(或带有管道的本地上传包)获取时,服务器在完成发送包后立即关闭连接。
因此,即使客户端可能仍在通过索引包对数据进行操作(例如,解析增量、检查连接性等),服务器已释放所有资源。

但是,对于 v2 协议,服务器仅将 ssh 会话视为一种传输方式,各个请求通过它。
发送包后,它返回主循环,等待来自客户端的另一个请求。
因此,ssh 会话会一直挂起,直到客户端进程结束,这可能要晚得多(因为解析 deltas 等可能会消耗大量 CPU)。

这很糟糕有两个原因:

  • 它正在消耗服务器上的资源以保持打开的连接不会再被使用
  • 如果在此期间 ssh 连接发生了不好的事情(例如,它因为空闲而被网络杀死,就像在真实世界的报告中发生的那样),那么 ssh 将退出非零值,我们将传播堆栈中的错误。

这里的服务器是正确的,服务包后不要挂断。
v2 协议的设计旨在允许这样的多个请求,对于计划发出更多请求的假设客户端来说,挂断是错误的(尽管在实践中,git.git 客户端永远不会,我怀疑任何其他实现也可以)。

正确的做法是让客户端向服务器发出信号,表明它对发出更多请求不感兴趣。
我们可以通过关闭用于写入 ssh 的管道描述符来做到这一点。
当它尝试读取下一个请求时,这将作为 EOF 传播到服务器上传包(然后它将关闭它的一半,整个连接将消失)。

进行这种“半双工”关闭很重要,因为我们必须在真正收到数据包之前这样做。
这是 fetch-pack 和 index-pack(或 unpack-objects)交互方式的产物。
我们将连接交给 index-pack(实际上是一个为其提供数据的边带解复用器),然后等待它返回。
直到它解决了包中的所有增量,它才会这样做,即使它很久以前就从服务器读取过。

所以在 index-pack 返回后完全关闭连接为时已晚;我们会将它打开的时间比必要的时间长得多。
并且教 index-pack 关闭连接很尴尬。
它甚至没有看到整个对话(边带解复用器是,但它实际上并不知道数据包中的内容,也不知道何时结束)。

请注意,此 close() 发生在传输代码的深处。
调用者可能希望在收到包后通过同一个 ssh 传输执行其他操作。
但就目前的代码而言,没有一个调用者这样做,也没有讨论过任何改变这一点的计划。
如果我们稍后需要支持它,我们可能可以通过传递一个标志来实现“你是传输中的最后一个请求;可以关闭”,而不是假设这是真的代码。

上面的描述都讨论了 v2 ssh,所以值得思考一下它是如何与其他协议交互的:

  • 在 v0 协议中,我们可以执行相同的半双工关闭(它只是进入 v0 do_fetch_pack())。
    这确实有效,但由于它一开始就没有相同的持久性问题,所以现在没有理由改变它。
  • 在同一台机器上针对git-upload-pack进行本地提取(man)的行为与 ssh 相同(它们通过两个管道进行通信,并在其输入管道上查看 EOF)
  • 针对git-daemon进行提取(man)将运行相同的代码,并关闭其中一个描述符。
    实际上,这不会做任何事情,因为我们的两个描述符是彼此的副本,而不是半双工对的一部分。
    正确的做法可能是致电shutdown(SHUT_WR)
    我没有在这里打扰。
    它不会面临同样的错误代码问题(因为它只是一个 TCP 连接),所以它实际上只是一个优化问题。
    并且 git:// 现在并没有那么广泛使用,并且对服务器资源的影响比 ssh 终止要小。
  • v2 http 首先没有遇到这个问题,因为我们的管道终止于本地 git-remote-https,它通过 curl 将数据作为单独的请求传递。
    可能 curl 为更多请求保持 TCP/TLS 连接打开,我们也许可以手动告诉它“嘿,我们现在已经完成了请求”。
    但我认为这不那么重要。
    它再次不受错误代码问题的影响,并且 HTTP keepalive 很好理解(重要的是,可以将超时设置为低,因为 curl 等客户端知道如何在必要时重新连接后续请求)。
    所以可能不值得弄清楚如何告诉 curl 我们已经完成(尽管如果我们这样做了,这个补丁可能无论如何都是第一步;fetch-pack 关闭管道回到 remote-https,这将是它的信号应该告诉 curl 我们完成了)。

代码非常简单。
我们在适当的时候关闭管道,并将其设置为 -1 以将其标记为无效。
我修改了后面的清理代码以避免调用 close(-1)。
这不是绝对必要的,因为 close(-1) 是一个 noop,但希望对读者来说更明显。

我怀疑在 close() 之后尝试调用更多传输函数(例如,再次调用 transport_fetch_refs())会失败,因为它不够聪明,无法意识到我们需要重新打开 ssh 连接。
但在使用 v0 时,情况已经如此。
目前没有任何调用者愿意这样做(同样,解决方案可能是传输代码中的一个标志,以保持打开状态,以后可以添加)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-30
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 2020-09-15
    • 2011-04-26
    • 2013-02-25
    相关资源
    最近更新 更多