Git receive/upload-pack 推送时占用所有 RAM
Git receive/upload-pack takes all RAM on push
我有一个带有 Git 的 Redmine 服务器。它有 2GB 的内存。
当有人尝试推送数据大于 2GB 的存储库时,我收到以下错误:
Counting objects: 957, done.
Delta compression using up to 12 threads.
Compressing objects: 100% (577/577), done.
Writing objects: 100% (957/957), 2.18 GiB | 29.66 MiB/s, done.
Total 957 (delta 255), reused 862 (delta 229)
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly
Everything up-to-date
在第一个 fatal: ...
之前,ruby 开始占用服务器上的所有 RAM。
当内存使用量达到 ~2GB 时,会出现 fatal: ...
错误。服务器错误:
App 9339 stderr: Errno::ENOMEM: Cannot allocate memory - git
所以我的猜测是 Git 或 Redmine 试图将那些 2.18 GB 放入 RAM,这显然是行不通的。
错误后:
- 服务器上的存储库仍然是空的;
- 在我重新启动 Redmine 之前,RAM 使用率仍然是 95+%。
我怎样才能让它发挥作用?是 Redmine 还是 Git 占用了所有 RAM?
推送数据 "part by part" (like here) 可以解决吗?
我已经尝试 (git config http.postBuffer 524288000
) 但没有成功。
编辑 (2017-06-01):
一些规格:
- Ubuntu LTS 12.04.05
- Redmine v2.6.9
- Git v1.7.9.5
Redmine 部署在带有 passenger 模块的 Apache 服务器 (v2.2.22) 后面。它使用 Grack (last revision) for its Git integration with the Redmine SCM 插件来创建存储库。
重新查看日志后,罪魁祸首似乎是 Grack。
App 9339 stderr: Errno::ENOMEM: Cannot allocate memory - git
App 29461 stderr: /opt/grack/lib/git_adapter.rb:24:in ``'
App 29461 stderr: /opt/grack/lib/git_adapter.rb:24:in `command'
App 29461 stderr: /opt/grack/lib/git_adapter.rb:34:in `upload_pack'
App 29461 stderr: /opt/grack/lib/grack.rb:84:in `get_info_refs'
App 29461 stderr: /opt/grack/lib/grack.rb:55:in `call'
App 29461 stderr: /opt/grack/lib/grack.rb:55:in `call'
换句话说,错误发生在 Grack 启动 git upload-pack
命令时。
编辑 (2017-06-01) (2):
本地存储库确实有 2+GB 的包。我用以下内容重新包装它:
git repack -a -d --window-memory=512m --max-pack-size=512m
将那个大包分成多个更小的包。我还配置了以下客户端和服务器端:
git config pack.windowMemory 512m
git config pack.packSizeLimit 512m
但问题依旧
App 30005 stderr: [ 2017-06-01 09:15:04.4393 30122/0x000000019264a8(Worker 1) utils.rb:72 ]: *** Exception Errno::ENOMEM in Rack body object #each method (Cannot allocate memory - git) (process 30122, thread 0x000000019264a8(Worker 1)):
App 30005 stderr: from /opt/grack/lib/git_adapter.rb:19:in `popen'
App 30005 stderr: from /opt/grack/lib/git_adapter.rb:19:in `command'
App 30005 stderr: from /opt/grack/lib/git_adapter.rb:43:in `receive_pack'
App 30005 stderr: from /opt/grack/lib/grack.rb:70:in `block in service_rpc'
编辑 (2017-06-01) (3):
在 Grack 上添加了一些日志记录以查看它究竟启动了什么:
git receive-pack --advertise-refs --stateless-rpc /var/git/mygit.git
由于它没有从 Git 存储库目录启动命令,我尝试了以下操作:
git config --global pack.windowMemory 512m
git config --global pack.packSizeLimit 512m
遗憾的是仍然无法正常工作。
编辑 (2017-06-01) (4):
再次尝试,但使用 64m
而不是 512m
,仍然没有效果。
看来Git还需要把所有对象都放到RAM上才能开始打包。在客户端,git repack
命令确实需要 2+GB 来执行,即使结果输出是多个 512 MB 的文件。
由于这个问题深入人心,这里是我用作答案的解决方法。
看起来 receive/upload-pack 需要将所有内容加载到 RAM 上。也许我错了,但我没有发现任何东西可以将 RAM 使用量减少到小数据包中。所以我所做的是创建一个临时交换文件。
# create a file of 4GB
sudo dd if=/dev/zero of=/swap bs=1024 count=4194303
# make it a swap file
sudo mkswap /swap
# enable the swap on this swap file
sudo swapon /swap
2GB 不够:推送大约需要 3.5GB,因此需要 4GB 的交换文件。
推送花了很长时间(没有 Sh*t Sherlock)但至少它成功了。
我留下了新的交换文件以备将来出现类似问题,但如果你想在推送后删除它,你可以执行以下操作:
# disable the swap (will automatically move used memory into RAM or another swap)
sudo swapoff /swap
# delete the file
sudo rm /swap
我有一个带有 Git 的 Redmine 服务器。它有 2GB 的内存。
当有人尝试推送数据大于 2GB 的存储库时,我收到以下错误:
Counting objects: 957, done.
Delta compression using up to 12 threads.
Compressing objects: 100% (577/577), done.
Writing objects: 100% (957/957), 2.18 GiB | 29.66 MiB/s, done.
Total 957 (delta 255), reused 862 (delta 229)
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly
Everything up-to-date
在第一个 fatal: ...
之前,ruby 开始占用服务器上的所有 RAM。
当内存使用量达到 ~2GB 时,会出现 fatal: ...
错误。服务器错误:
App 9339 stderr: Errno::ENOMEM: Cannot allocate memory - git
所以我的猜测是 Git 或 Redmine 试图将那些 2.18 GB 放入 RAM,这显然是行不通的。
错误后:
- 服务器上的存储库仍然是空的;
- 在我重新启动 Redmine 之前,RAM 使用率仍然是 95+%。
我怎样才能让它发挥作用?是 Redmine 还是 Git 占用了所有 RAM?
推送数据 "part by part" (like here) 可以解决吗?
我已经尝试 (git config http.postBuffer 524288000
) 但没有成功。
编辑 (2017-06-01):
一些规格:
- Ubuntu LTS 12.04.05
- Redmine v2.6.9
- Git v1.7.9.5
Redmine 部署在带有 passenger 模块的 Apache 服务器 (v2.2.22) 后面。它使用 Grack (last revision) for its Git integration with the Redmine SCM 插件来创建存储库。
重新查看日志后,罪魁祸首似乎是 Grack。
App 9339 stderr: Errno::ENOMEM: Cannot allocate memory - git
App 29461 stderr: /opt/grack/lib/git_adapter.rb:24:in ``'
App 29461 stderr: /opt/grack/lib/git_adapter.rb:24:in `command'
App 29461 stderr: /opt/grack/lib/git_adapter.rb:34:in `upload_pack'
App 29461 stderr: /opt/grack/lib/grack.rb:84:in `get_info_refs'
App 29461 stderr: /opt/grack/lib/grack.rb:55:in `call'
App 29461 stderr: /opt/grack/lib/grack.rb:55:in `call'
换句话说,错误发生在 Grack 启动 git upload-pack
命令时。
编辑 (2017-06-01) (2):
本地存储库确实有 2+GB 的包。我用以下内容重新包装它:
git repack -a -d --window-memory=512m --max-pack-size=512m
将那个大包分成多个更小的包。我还配置了以下客户端和服务器端:
git config pack.windowMemory 512m
git config pack.packSizeLimit 512m
但问题依旧
App 30005 stderr: [ 2017-06-01 09:15:04.4393 30122/0x000000019264a8(Worker 1) utils.rb:72 ]: *** Exception Errno::ENOMEM in Rack body object #each method (Cannot allocate memory - git) (process 30122, thread 0x000000019264a8(Worker 1)):
App 30005 stderr: from /opt/grack/lib/git_adapter.rb:19:in `popen'
App 30005 stderr: from /opt/grack/lib/git_adapter.rb:19:in `command'
App 30005 stderr: from /opt/grack/lib/git_adapter.rb:43:in `receive_pack'
App 30005 stderr: from /opt/grack/lib/grack.rb:70:in `block in service_rpc'
编辑 (2017-06-01) (3):
在 Grack 上添加了一些日志记录以查看它究竟启动了什么:
git receive-pack --advertise-refs --stateless-rpc /var/git/mygit.git
由于它没有从 Git 存储库目录启动命令,我尝试了以下操作:
git config --global pack.windowMemory 512m
git config --global pack.packSizeLimit 512m
遗憾的是仍然无法正常工作。
编辑 (2017-06-01) (4):
再次尝试,但使用 64m
而不是 512m
,仍然没有效果。
看来Git还需要把所有对象都放到RAM上才能开始打包。在客户端,git repack
命令确实需要 2+GB 来执行,即使结果输出是多个 512 MB 的文件。
由于这个问题深入人心,这里是我用作答案的解决方法。
看起来 receive/upload-pack 需要将所有内容加载到 RAM 上。也许我错了,但我没有发现任何东西可以将 RAM 使用量减少到小数据包中。所以我所做的是创建一个临时交换文件。
# create a file of 4GB
sudo dd if=/dev/zero of=/swap bs=1024 count=4194303
# make it a swap file
sudo mkswap /swap
# enable the swap on this swap file
sudo swapon /swap
2GB 不够:推送大约需要 3.5GB,因此需要 4GB 的交换文件。
推送花了很长时间(没有 Sh*t Sherlock)但至少它成功了。
我留下了新的交换文件以备将来出现类似问题,但如果你想在推送后删除它,你可以执行以下操作:
# disable the swap (will automatically move used memory into RAM or another swap)
sudo swapoff /swap
# delete the file
sudo rm /swap