Gitは通常、ファイルシステムの問題として扱われます:`.git`ディレクトリはフォルダのように見えるため、クラウドでGitをホストする自然な方法は、ファイルシステムを用意し、そのファイルシステムをオブジェクトストレージの上に載せることです。ある開発者は実際にその方法を試しましたが、実際のリポジトリでは成り立たないことがわかりました。その結果がobjgitです。これはオープンソースのGitサーバーで、Gitのオブジェクトを直接オブジェクトストレージ(具体的にはTigris)に保存し、Git自身のpackfileメカニズムを、リモート・バイトア dress可能なストレージ用に設計されたカスタム形式に置き換えます。

なぜそれが必要かを理解するには、Gitが実際に何を保存しているかから始めるのが便利です。リポジトリは、本質的に二つのもので構成されます:オブジェクトの海と、その中の個々のオブジェクトを指名する名前付き参照です。各コミット、ツリー、ファイルブロックはそれぞれ独立した内容ア dress可能で圧縮されたオブジェクトであり、そのファイル名はバイトのハッシュです——同じ内容はどこでも常に同じオブジェクトです。小さなリポジトリではこれは目立たない:ディスク上に3つのオブジェクトがあり、それぞれが単なるzlib圧縮ファイルです。しかしLinuxカーネルのチェックアウトには約1180万个のオブジェクトが含まれ、Gitはこれらを1180万个のファイルとして保持しません。これらをpackfilesに詰め込みます——複数のオブジェクトを1つのファイルに格納する圧縮アーカイブです。これは、ルーズファイルとして保存するとファイルシステムのinode制限に直面するためです。

Expanding brain meme contrasting naive and correct ideas of how Git stores file versions
Git does not store every version of every file as a separate full copy; it stores content-addressed objects, bundled into packfiles.www.tigrisdata.com

The article explains that a repository is, at root, a sea of content-addressed objects plus named references pointing into them, and that Git bundles these into packfiles rather than keeping millions of loose files. The meme captures the counterintuitive part of that: the small-brain assumption that Git keeps whole files for every version is wrong, which is exactly why the packfile format matters for object storage.

packfileが、オブジェクトストレージへの変換が破綻する点です。Gitはローカルストレージを前提に設計されています。packfileを常にディスクに書き込み、直後に読み返し、メモリマップすることで、オペレーティングシステムのページキャッシュがRAMのようにホットデータを提供するようにしています。その世界では、ファイルシステムの読み出しは約10ナノ秒です。オブジェクトストレージへのネットワークラウンドトリップは、最低でも約10ミリ秒かかります。著者は、これは最低でも100万倍遅いと指摘しています。Gitはまた、ファイルを書き込み直後に読み返してハッシュを計算するUnixイディオムにも依存していますが、これはオブジェクトストレージでは不可能です。書き込みが完了しないオブジェクトを取得できないためです。

より深い障害はpackfileのインデックスです。各packfileには、パック内の各オブジェクトの場所を伝える`.idx`ファイルが付随します。インデックスは、各オブジェクトについて、そのオフセットと展開後のサイズを記録しますが、圧縮後のサイズは記録しません。この違いはオブジェクトストレージ来说は致命的です。オブジェクトストレージはHTTP range リクエストでア dressされます:128メガバイトのパックから1つのオブジェクトを取得するには、クライアントはそのオブジェクトの開始バイト位置と長さを知り、バケットにそのExactな範囲をリクエストする必要があります。インデックスが圧縮後の長さを省略するため、その範囲をインデックスのみから計算することはできず、他の方法で安価に発見することもできません。これは、著者が主張する、以前のオブジェクトストレージにGitを保存しようとした試みが苦戦した根本理由です——range リクエストが利用できないからではなく、Gitのインデックス形式がそれを使用するための情報を提供していないからです。

著者の解決策は、物理的なメディアからアイデアを借用しています。CDのcueシートは、大きなWAVファイル内のトラックと、それらが開始するオフセットをリストアップしたプレーンテキストファイルで、プレイヤーはディスク全体をスキャンせずに任意のトラックに直接ジャンプできます。Objgitの置き換え形式は、Gitオブジェクトに対して同じことをしますが、バイナリの固定幅レイアウトで。小さな`objects.cue`ファイルは、16バイトのヘッダー(マジックナンバー、バージョン、レコードサイズ、レコード数)を含み、その後に各58バイトのレコードが並び、したがって record N はバイトオフセット`16 + N * 58`に位置します。各レコードは、オブジェクトのハッシュ、種類、圧縮方式、サイズ、および1つの大きな`objects.bin`ファイル内のバイトのオフセットと長さを携带します。したがって、任意のオブジェクトの取得は、cueファイルへの1つのシーキング、1つのルックアップ、バイナリブロックへの1つのHTTP range リクエストで完了し——全体のパックではなく、ワイヤー上では366バイトになります。

報酬は、クライアント側を一切変更せずにプロダクションスケールで動作することです。著者は、このアプローチが現実的なサイズのリポジトリで良好な性能を発挥すると報告しており、この設計はGitオブジェクトをオブジェクトストレージオブジェクトのように感じさせる最小限の邪魔のない方法として説明されています。基盤ストレージ層は、FoundationDB(分散キーバリューストア)内のオブジェクトの海の中の点に対する名前付き参照を保持し、著公司将将其を一種の再帰と呼んでいます:オブジェクトを保持するオブジェクトストレージが、そのオブジェクトへの参照を、もう一つのオブジェクトのようなシステムに保存しています。

ログポストの裏にあるプロジェクト、objgitは、この取り組みが製品として什么样的存在になるかのより完全な姿を示しています。tigrisdata/objgitにホストされており、これは既存の forge のプロキシではなく、SSH、HTTP、Gitプロトコルをサポートし、ユーザー空間のサンドボックス内でpost-receiveフックを実行し、 presigned転送によるGit LFSをサポートし、大ファイルはサーバーを経由せずにクライアントとTigrisの間を直接移動できるようにしています。また、各ツリーに対してEROFSスナップショットを取得し、基本的なPrometheusメトリクスを公開し、Kustomize経由でKubernetesデプロイを提供します。現時点では認証がなく、著公司将将其を、プロジェクトが有益であることが証明された場合に埋めるべき既知の欠点としてリストアップしています。

これは伴うべき2つの注意点です。第一に、性能に関する主張——ファイルシステムシムが現実のリポジトリ来说遅すぎたこと、および新しい形式がプロダクションサイズで良好に動作すること——は、プロジェクト自身の著者とそのブログに由来し、独立したベンチマークではありません。提供されたリポジトリページはプロジェクトの機能集合を裏付けても、測定値を検証してはいません。第二に、著者が指摘するエコシステムの差は現実です。GitLab、Forgejo、Giteaなどの主流のGitサーバーは、依然としてリポジトリ用にローカルファイルシステムを期待しているため、objgitは現時点では自己ホストの初期段階の代替手段であり、即時置き換え可能な代替品ではありません。cueシートのアイデアが、他で採用されるほど一般的であるかは、現時点では未解決の問題です。

この作業が示しているのは、Gitをクラウドに移動できるというより(それ以前に試みられたことである)、むしろ、特定のボトルネックがネットワークやプロトコルではなかったが、Gitがディスク中心の時代に継承したインデックス形式にあったというものです。その1つの部品を、Gitをファイルシステム層でラップするのではなく、置き換えることが、オブジェクトストレージをGitのバックエンドとして現実的にします。