9

少し前に、大きなバイナリファイルがたくさんあるために遅いリポジトリを修正する計画についてフィードバックを求める質問を投稿しました。その質問(これは必読ではありません):大きなバイナリファイルのために遅くなるgitリポジトリを修正する

私は自分の計画を実行し、予期しない副次的な結果を経験しました。

私たちのリポジトリの新しいクローンは、もともと2〜3時間かかりました。サーバーがスワッピングを開始し、git config pack.windowMemory 100m && git config pack.packSizeLimit 200mを実行した後、クローン時間が約15分に短縮されたことがわかりました。

残りの計画はまだ実行すると思ったので、使用しているバイナリタイプのデルタ圧縮を無効にし、リポジトリでgit repack -a-d-Fを実行しました。

この後、リポジトリの新しいクローンは約20分かかるため、実際には悪化しました。しかし、本当の問題は、リポジトリのクローンを作成した人がコミットをプッシュしようとするたびに、「最適なパフォーマンスを得るためにリポジトリを自動パックする」ということです。

何がうまくいかなかったのか、そしてそれをどのように修正できる/すべきかについてのアイデアはありますか?

4

3 に答える 3

4

おそらく、レポのサイズとの値が低いためpack.packSizeLimit、パックの数は常にを上回っていgc.autopacklimitます。したがって、それらのいずれかを増やして、gcが各コミットを実行しないようにします。

packSizeLimitどのように記憶に影響を与えるかはわかりませんが、それが大きな影響を与えるとは思いません。あなたの実験がそうでないことを示したら私を訂正してください。pack.windowMemoryメモリ使用量に直接影響するパラメータはとpack.deltaCacheSizeです。

于 2013-11-10T19:20:02.970 に答える
2

git repack同じことを、今回はGit 2.32(2021年第2四半期、ほぼ8年後)とその新しい--geometric=<n>オプションで再試行することをお勧めします。

" git repack" これまでのところ、太陽の下ですべてを1つのパックに再梱包する(またはサイズで分割する)ことしかできませんでした。

リポジトリの再パックのコストを削減するための賢い戦略が導入されました。

Taylor Blau()によるcommit 14e7b83(2021年3月19日)、commit 2a15964commit 13d746acommit dab3247commit f25e33c(05 Mar 2021)、commit 0fabafdcommit 339bce2commit c9fff00commit f62312e(22 Feb 2021)を参照してください。Junio C Hamano()によるcommit ccae01c(2021年3月5日) を参照してください。ジェフ・キング( 2021年2月22日)によるコミット20b031fコミット6325da1コミットfbf20aeコミット60bb5f2(2021年2月22日) を参照してください。ttaylorr
gitster
peff
濱野純雄によって合併gitster---コミット2744383、 20213月24日)


初め:find_kept_pack_entry()

packfile:紹介' find_kept_pack_entry()'

共著:Jeff King
署名者:Jeff King
署名者:Taylor Blau
レビュー者:Jeff King

将来の呼び出し元は、関数がpack_entry特定のオブジェクトIDの「構造体」を埋める必要がありますが、保持されているパック内のその位置からのみです。

特に、結果のパックがオブジェクト数によって等比数列を形成することを保証する新しい' git repack' manモードは、再パックしたくないパックを「コア内に保持」としてマークし、到達可能性トラバーサルを停止する必要があります保持されているパックのいずれかでオブジェクトにアクセスするとすぐに。
ただし、キープされていないパック、または.keepパックでトラバーサルを停止することは望ましくありません。

明らかな代替手段は' find_pack_entry()'ですが、最初に見つかったパックのみが返されるため、これでは十分ではありません。保持される場合と保持されない場合があります(mruキャッシュにより、オプションがある場合にどちらを取得するかが予測できなくなります)。 。

それがなければ、すべてのパックを歩き回ってそれぞれのオブジェクトを探すことができますが、パックの数に応じてスケーリングされるため、法外な場合があります。

find_kept_pack_entry()' 'に似た関数find_pack_entry()ですが、保持されているパック内のオブジェクトのみを入力する''を導入します。


それで:git pack-objects --stdin-packs

builtin/pack-objects.c:'--stdin-packs'オプションを追加

提案者:Jeff King
承認者:Taylor Blau
レビュー者:Jeff King

今後のコミットでは、' git repack' man)は、他のいくつかのパック(除外されたパック)のオブジェクトを除いて、いくつかのパック(含まれているパック)のすべてのオブジェクトで構成されるパックを作成する必要があります。

この呼び出し元は、それらのパックを自分で繰り返し、検出したオブジェクトをstdinの直接の' git pack-objects' manにフィードできますが、このアプローチにはいくつかの欠点があります。

  • この方法で''を駆動したいすべての呼び出し元は、git pack-objectsパックの反復を自分で実装する必要があります。
    これにより、呼び出し元は、パックオブジェクトにフィードされる順序オブジェクトなどの詳細について考える必要がありますが、呼び出し元はそうしない可能性があります。
  • 含まれているパック内のオブジェクトのセットが大きい場合、パイプを介して大量のデータを送信する必要があり、非効率的です。
  • 呼び出し元は、除外されたオブジェクトも追跡する必要があり、含まれているパックと除外されているパックの両方に表示されるオブジェクトを送信しないようにします。

しかし、最大の欠点は、到達可能性のトラバーサルがないことです。
呼び出し元はオブジェクトのリストを直接渡すため、それらのオブジェクトにはネームハッシュが割り当てられません。これは、デルタ選択プロセスに悪影響を及ぼし、' git pack-objects'が存在する場合でも適切なデルタを見つけることができない原因となる可能性があります。

呼び出し元は到達可能性トラバーサルを自分で作成できますが、git pack-objectsこの方法で''を駆動する唯一の方法は、完全なトラバーサルを実行し、トラバーサルが完了した後に除外されたパック内のオブジェクトを削除することです。
これは、特に多くのオブジェクトを含むリポジトリで、パフォーマンスを気にする呼び出し元にとって有害になる可能性があります。

これらの4つの懸念を解決する' git pack-objects --stdin-packs' を紹介します。

' git pack-objects --stdin-packs'はstdinのパック名のリストを期待します。ここで、' pack-xyz.pack'はそのパックが含まれていることを示し、' ^pack-xyz.pack'はそれが除外されていることを示します。
結果のパックには、少なくとも1つの含まれるパックに存在し、除外されるパックには存在しないすべてのオブジェクトが含まれます。

git pack-objects現在、そのマニュアルページに含まれています:

--stdin-packs

pack-1234abcd.packオブジェクト名やリビジョン引数の代わりに、標準入力からパックファイルのベース名(たとえば)を読み取ります。

結果のパックには、含まれているパック(で始まらない)にリストされているすべてのオブジェクトが含まれます^。ただし、除外されているパック(で始まる^)にリストされているオブジェクトは含まれません。

と互換性がない、または互換性のあるを除いて、--revsを意味するオプション--revs(など ) 。--all--unpacked


ついに:git repack --geometric=<n>

builtin/repack.c:「-geometric」オプションを追加

提案者:Derrick Stolee承認者
:Taylor Blau
レビュー者:Jeff King

多くの場合、次の両方に役立ちます。

  • リポジトリ内のパックファイルが比較的少なく、
  • リポジトリ内のパックファイルが少なすぎて、コンテンツ全体を定期的に再パックすることは避けてください

git repackこのパッチは、' ' manに'--geometric='オプションを実装します。
これにより、呼び出し元は、各パックを前の最大パックの少なくとも1倍の大きさにすることを指定できます(オブジェクト数による)。

具体的には、リポジトリにP1、P2、...、Pnまでのラベルが付いた「n」個のパックファイルがあるとします。
各パックファイルには、''に等しいオブジェクト数がありますobjects(Pn)
幾何学的係数が' r'の場合、次のようになります。

objects(Pi) > r*objects(P(i-1))

[1, n]パックが並べ替えられているすべてのiについて

objects(P1) <= objects(P2) <= ... <= objects(Pn).

真の最適な再梱包を見つけることはNP困難であるため、2つの方向に沿って近似します。

  1. 再パックを開始する前にパックのカットオフがあり、そのカットオフの右側のすべてがすでに等比数列を形成していると想定します(または、カットオフが存在せず、すべてを再パックする必要があります)。

  2. カットオフカウントよりも小さいものはすべて再梱包する必要があると想定しています。
    これは基本的な仮定を形成しますが、たとえば、次の数のオブジェクトを含む6つのパックがある場合、「重い」パックでさえ再パックされる可能性もあります。

    1、1、1、2、4、32

次に、カットオフを「1、1」と「1、2、4、32」の間に配置し、最初の2つのパックを2つのオブジェクトを含むパックにロールアップします。
それは私たちの進歩を壊し、私たちを残します:

2, 1, 2, 4, 32
  ^

(ここで、' ^'は分割の位置を示します)。
等比数列を復元するには、等比数列が復元されるまで、分割を前方に(より大きなパックに向かって)移動して、各パックを新しいパックに結合します。
ここでは、次のようになります。

2, 1, 2, 4, 32  ~>  3, 2, 4, 32  ~>  5, 4, 32  ~> ... ~> 9, 32
  ^                   ^                ^                   ^

これには、パックの重い面を頻繁に再パックすることなく、一度に1つの新しいパックを作成するだけであるという利点があります。
もう1つの問題は、ルーズ、インデックス、およびreflogされたオブジェクトは重要ではないと想定し、作成する新しいパックにそれらをまとめることです。
これは、べき等でない結果につながる可能性があります。

git repack現在、そのマニュアルページに含まれています:

-g=<factor>

--geometric=<factor>

結果のパック構造を、連続する各パックに、次に大きいパックの少なくとも<factor>倍の数のオブジェクトが含まれるように配置します。

git repack等比数列を確実にするために1つに再パックする必要があるパックファイルの「カット」を決定することによってこれを保証します。大きいパックファイルの多く(そのパックに含まれるオブジェクトの数による)がそのまま残るように、パックファイルの最小セットを選択します。

他の再梱包モードとは異なり、梱包するオブジェクトのセットは、「ロールアップ」されるパックのセットによって一意に決定されます。言い換えれば、等比数列を復元するために組み合わせる必要があると判断されたパックです。

が指定されている場合--unpacked、ルーズオブジェクトは、到達可能性に関係なく、この「ロールアップ」に暗黙的に含まれます。これは将来変更される可能性があります。このオプション(大幅に異なる再パックモードを意味する)は、オプションの他のすべての組み合わせで機能することが保証されていませんgit repack)。


結果

  Test                                        HEAD^                   HEAD
  -----------------------------------------------------------------------------------------------
  5303.5: repack (1)                          57.34(54.66+10.88)      56.98(54.36+10.98) -0.6%
  5303.6: repack with kept (1)                57.38(54.83+10.49)      57.17(54.97+10.26) -0.4%
  5303.11: repack (50)                        71.70(88.99+4.74)       71.62(88.48+5.08) -0.1%
  5303.12: repack with kept (50)              72.58(89.61+4.78)       71.56(88.80+4.59) -1.4%
  5303.17: repack (1000)                      217.19(491.72+14.25)    217.31(490.82+14.53) +0.1%
  5303.18: repack with kept (1000)            246.12(520.07+14.93)    217.08(490.37+15.10) -11.8%

そして、--stdin-packsケースは少し良くスケーリングします(1,000パックでもそれほどではありませんが):

  5303.7: repack with --stdin-packs (1)       0.00(0.00+0.00)         0.00(0.00+0.00) =
  5303.13: repack with --stdin-packs (50)     3.43(11.75+0.24)        3.43(11.69+0.30) +0.0%
  5303.19: repack with --stdin-packs (1000)   130.50(307.15+7.66)     125.13(301.36+8.04) -4.1%

Taylor Blauの「Git2.33:Geometricrepacking」を参照してください。

歴史的に、git repack次の2つのいずれかを実行しました。

  • すべてのルーズオブジェクトを新しいパックに再パックし(オプションで、これらの各オブジェクトのルーズコピーを削除します)、
  • または、すべてのパックを1つの新しいパックに再パックしました(オプションで冗長パックを削除します)。

一般的に、多くの操作はリポジトリ内のパックの数に応じてスケーリングされるため、パックが少ないほどGitのパフォーマンスが向上します。
したがって、多くの場合、すべてを1つのパックにまとめることをお勧めします。>しかし、歴史的に言えば、忙しいリポジトリでは、多くの場合、すべてのコンテンツを1つの巨大なパックにまとめる必要があります。
これは、サーバー側のGitパフォーマンスの重要な最適化である到達可能性ビットマップは、単一のパック内のオブジェクトしか記述できないためです。
したがって、ビットマップを使用してリポジトリ内の多くのオブジェクトを効果的にカバーする場合は、それらのオブジェクトを同じパックに一緒に保存する必要があります。

私たちはその制限を取り除くことに取り組んでいます(私たちがそれをどのように行ったかについてもっと読むことができます)が、途中の重要なステップの1つは、比較的少数のパックを持つこととパッキングすることの間でトレードオフする新しい再パッキングスキームを実装することです最近追加されたオブジェクトを一緒に(つまり、前回の再パック以降に追加された新しいオブジェクトに近づけます)。

そのために、Gitは新しい「幾何学的」な再梱包戦略を学びました

アイデアは、残りのパックがオブジェクトのサイズに基づいて等比数列を形成するように、一緒に組み合わせることができる(小さい)パックのセットを決定することです。
つまり、最小のパックにN個のオブジェクトがある場合、次に大きいパックには少なくとも2N個のオブジェクトがあり、以下同様に、途中の各ステップで2倍(または任意の定数で増加)します。

https://github.blog/wp-content/uploads/2021/04/Scaling-monorepo-maintenance-fig-12.png?w=1958


git pack-objects --stdin-packs" " manの入力検証は、Git 2.34(Q4 2021)で修正されました。

commit 561fa03(2021年7月9日)およびÆvarArnfjörðBjarmason ( )によるcommit fb20d4b(2021年6月21日)を参照してください。( Junio C Hamanoによってマージされました---コミット5c933f0 、20218月24日)avar
gitster

pack-objects--stdin-packs:オプションのsegfaultを修正

サインオフ:ÆvarArnfjörðBjarmason

339bce2で--stdin-packs追加されたオプションのセグメンテーション違反を修正します( " builtin/pack-objects.c:add'--stdin-packs' option"、2021-02-22、Git v2.32.0-rc0 --mergeバッチ#4にリストされています)。

このread_packs_list_from_stdin()関数は、読み取っている行が有効なパックであることを確認しなかったため、QSORT()を実行するpack_mtime_cmp()と、NULL「util」フィールドが作成されます。「util」フィールドは、含まれる/除外されるパックの名前を、それらが対応する構造体
に関連付けるために使用されます。packed_git

論理エラーは、stdinで取得した行をチェックするのではなく、すべてのパックを反復処理し、取得した除外パックと包含パックに注釈を付けることができると想定した場合に発生しました。
除外されたパックのチェックがありましたが、含まれているパックは単に有効であると想定されていました。

string-list.cテストで指摘したように、最初の不良行は報告しませんが、 APIに従って最初にソートされた行はすべて報告します。
この場合は問題ないと思います。代替アプローチについてのさらなる議論
がありました。

私たちは怠惰ですが、将来このコードを変更する人は誰でもこのケースを見逃す可能性があり、テストとコメントを更新したいと思うので、テストで取得する予定の行を主張しましょう。


再パックを高速化する別の方法:--quiet、これは実際にはGit 2.35(Q1 2022)で動作します。

Derrick Stolee()によるcommit 47ca93dcommit e4d0c11(2021年12月20日)を参照してください。( Junio C Hamanoによってマージされました---コミット88a516a、2022年1月5日derrickstolee
gitster

repack:make'--quiet'は進行を無効にします

支援者:Jeff King
署名者:Derrick Stolee

git repack' ' manでいくつかのアイデアをテストしているときに、''で実行したところ--quiet、進行状況の出力がまだ表示されていることがわかりました。
具体的には、multi-pack-indexを書き込むための出力に進捗状況が示されました。

の' show_progress'変数はcmd_repack()で初期化され、' 'フラグisatty(2)によってまったく変更されません。 '--quiet'フラグは、 .quietオプションを変更します。これは、' ' man子プロセスの'--quiet'フラグに変換されます。 ただし、' 'は、子プロセスを使用しないマルチパックインデックス書き込みロジックに進行状況情報を直接送信するために使用されます。--quiet
po_argsgit pack-objects
show_progress

ここでの修正は、trueのshow_progress場合はfalseに、それ以外の場合はfalseに変更することです。 この新しい期待は、両方をチェックする後の条件を単純化します。po_opts.quietisatty(2)

ドキュメントを更新して、「-q」がすべての進行状況を無効にするだけでなく、「git pack-objects」子プロセスがフラグを受け取るようにすることを明確にします。

git repack現在、そのマニュアルページに含まれています:

--quiet

標準エラーストリームの進行状況を表示せず、-q オプションを「gitpack-objects」に渡します。を参照してくださいgit pack-objects

于 2021-03-27T14:07:07.890 に答える
0

何が詰め替えられていますか?ローカルクローン、リモート?ローカルとリモートは別々であることを忘れないでください。おそらく、アンパックされたものがローカルにパックされていることを意味します...リモートの構成をローカルに複製する必要があります(もう一度やり直してください。完全にベースから外れている可能性があります)。

于 2013-03-16T16:06:41.710 に答える