This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. As with all projects, the items mentioned on this page are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.
StatusAuthorsCoachDRIsOwning StageCreated
proposed @jcai-gitlab @toon devops systems 2023-05-19

データをより安価なストレージにオフロード

要約

Gitデータのストレージ・コストの管理は、私たちのビジネスにとって重要な部分です。Gitデータをより安価なストレージにオフロードすることで、ストレージコストを削減することができます。

動機

GitLabでは、データへのアクセスを高速に保つために、ほとんどのGitデータをSSDに保存しています。これは、頻繁にアクセスする必要があるデータについては理にかなっています。しかし、ストレージのコストはデータの増加に応じてスケールすることを考えると、私たちはどのようなデータをSSDに保存し、どのようなデータをより安価なストレージにオフロードするかについて、もっと賢くなることができます。

例えば、大きなファイル(Gitの用語では “blob”)は、通常はテキスト以外のファイル(画像、動画、バイナリなど)なので、頻繁に変更されることはありません。このような大きな blob を含むリポジトリでは、Git LFSを使うことで大きなファイルを Git サーバーにプッシュする手間を省くことができます。しかし、これはクライアント側の設定に依存します。

あるいは、プロジェクトが「古い」もので、長い間アクセスされていないのであれば、そのプロジェクトのために高速ストレージにお金を払い続ける必要はありません。

代わりに、その古いプロジェクトのすべてのブロブをより安価なストレージに置くこともできます。こうすることで、アプリケーションはコミット履歴やツリーにアクセスできるため、プロジェクト閲覧のエクスペリエンスに影響はありませんが、めったにアクセスされないため、すべてのファイルはより低速なストレージに置かれます。

Git のデータをさまざまなカテゴリーに分ける方法があれば、特定のデータをより安価なセカンダリ・ロケーションにオフロードすることができます。例えば、あまり頻繁にアクセスされないような大きなファイルを他のGitデータから分離して、SDDマウントではなくHDDに保存することができます。

要件

どのような特定の解決策に対しても、与えなければならない一連の要件と不変条件があります。

保管コストの節約

究極的には、このソリューションはストレージコストを節約する必要があります。特定のGitデータを分離することで、より安価なストレージを確保することができます。

データをより安価なストレージにオフロードすることで節約できるプロジェクトに対して、このソリューションが追加するコストを評価する必要があります。以下は、検討すべき基準です:

  • X以上の大きなブロブをすべてHDDに保存した場合、どれだけのコストを削減できますか?
  • すべての古いプロジェクトのブロブをHDDに保存した場合、どれだけのコスト削減になりますか?
  • オフローディング・メカニズムを実行するためのオペレーション・オーバーヘッドは、CPU/メモリの追加コストとしてどのくらいになりますか?
  • 例えば、大きなブロブを取得するために、ネットワークを経由して別のノードへの余分なラウンドトリップが発生しますか。
  • アクセスコスト、例えばブロブがオブジェクトストアに格納される場合。

Gitalyのダウンストリーム消費者には不透明。

この機能は純粋にストレージの最適化であり、潜在的なパフォーマンスの低下を除けば、Gitalyのダウンストリームコンシューマーに影響を与えるべきではありません。例えば、GitLabアプリケーションはこの機能をサポートするためにロジックを変更する必要はありません。

この機能は、Gitalyの呼び出し元からは完全に見えないようにすべきです。Railsやどのコンシューマも、この機能について知る必要も、管理する必要もないはずです。

オペレーションがシンプル

Gitのデータを扱うときは、リポジトリが壊れるリスクを最小限にするために、できるだけシンプルにしたいものです。オペレーションをシンプルにし、Git自身の外で動かす部分を最小限に抑えましょう。リポジトリのデータを変更するようなロジックは、Git自体のアップストリームに置くようにしましょう。

提案

Git alternates メカニズムで接続されたリポジトリごとに、別のオブジェクトデータベースをメンテナーします。このセカンダリオブジェクトデータベース(ODB)に対して、特定の Git オブジェクトをフィルタリングすることができます。

Git データを、フィルターに基づいてこのセカンダリ ODB に配置します。Git には、フィルターに基づくオプションがあります。

ある制限に基づいて大きな blob をセカンダリ ODB に置くか、あるいはすべての blob をセカンダリ ODB に置くかを選択できます。

デザインおよび実施内容

Git

git-repack(1) 、さまざまな種類のブロブをさまざまなオブジェクトデータベースに分割できるようにする機能を追加する必要があります。私たちはこのイシューでこの作業を追跡しています。

Gitaly

Gitalyのハウスキーピングでは、以下のことが可能です:

  1. git-repack(1) を使って、メインリポジトリのオブジェクトデータベースとセカンダリオブジェクトデータベースの両方にパックファイルを書き込みます。各リポジトリは、いくつかの基準に基づいてBLOBをオフロードするために、独自のセカンダリオブジェクトデータベースを持っています。
  2. .git/objects/info/alternates ファイルが手順(1)のセカンダリオブジェクトデータベースを指していることを確認します。

基準

オブジェクトを別のオブジェクト データベースにオフロードするかどうかは、以下の基準の 1 つまたは複数に基づいて決定できます。

階層別

無料プロジェクトでは多くのブロブが安価なストレージにオフロードされ、Ultimateプロジェクトではすべてのオブジェクトが最も高速なストレージに配置されます。

履歴

あるblobがかなり前に追加され、最近のコミットで参照されていない場合、そのblobはオフロードされ、新しいblobはメインのODBに残ります。

サイズ別

大きなブロブは、高価なストレージのサイズを小さくする手っ取り早い方法なので、安価なストレージに優先的に移動するかもしれません。

アクセス頻度

頻繁に使用されるプロジェクトは、高速ストレージに完全に残っているかもしれませんが、非アクティブなプロジェクトは、ブロブをオフロードされるかもしれません。

オープンな質問

オブジェクトはどのように削除するのですか?

到達不可能なオブジェクトを削除したい場合、リパックは両方のODBを認識し、オブジェクトがメインODBにあるかセカンダリODBにあるかに関係なく、到達不可能なオブジェクトを退避させる必要があります。メインODBにオブジェクト・プールODBもある場合、プールODBからオブジェクトを削除することはないため、この図は複雑になります。

解決策オルタネートからオブジェクトを削除するようにGitを修正します。

代替 ODB にある到達不能なオブジェクトを削除できるようにするには、repack を修正する必要があります。repack configsrepack.alternates.* を追加して、代替ディレクトリでの振る舞いを指定します。例えば、repack.alternates.explodeUnreachableは、リンクされている代替ODBで-A のように動作するようrepackに指示します。

これはオブジェクトプールでどのように機能するのでしょうか?

オルタネートを使用する場合、オブジェクトプールとの関係はどうなりますか?オブジェクトプールもセカンダリストレージにデータをオフロードしますか?オブジェクトプールはメンバーですか?最も複雑なケースでは、1つのリポジトリに4つの異なるオブジェクトデータベースがあることになり、複雑さが増す可能性があります。

keep-packオプションと–honor-pack-keepオプションを使って、いくつかのパックファイルを “keep “としてマークできるかもしれません。

可能性のある解決策オブジェクトプールにblobのオフロードを許可しない

複雑さをあまり増やさないために、オブジェクトプールがブロブをオフロードしないようにすることもできます。その代わりに、オブジェクトプールで重複排除する前にリポジトリからブロブをオフロードするようにハウスキーピングを設計することができます。理論的には、これはオフロードされたblobがオブジェクトプールに行き着かないことを意味します。

これはRaft + WALでどのように機能するのでしょうか?

この機構はRaftやwrite-ahead logとどのように相互作用するのでしょうか?

WALは遅いコピーオペレーションを避けるため、ハードリンクとコピーフリーのムーブを使用します。しかし、これは異なるファイルシステム間では機能しません。ある時点で、リパックなどもログを経由することになるでしょう。ファイルシステム間のデータ転送は、トランザクション処理の遅延につながります。

理想的には、代替の使用をノード内部で維持し、この複雑さをクラスターの他の部分に漏らす必要はありません。これは、配置を決定する際に利用可能なスペースを考慮しなければならないことを考えると、難しいことです。2つのストレージのうち容量の小さい方だけを表示することで内部を維持することは可能ですが、ストレージの使用効率が悪くなる可能性があります。

設計の問題点

複雑さ

オブジェクト・プールをもう1つ追加するということは、システムに複雑さをもたらします。特にリポジトリ・レプリケーションでは、データを複製する場所がまた1つ増えることになります。

時間の経過によるコストの変化の可能性

異なるストレージ・タイプのコストは、時間とともに変化する可能性があります。このような事態を想定し、そのような変化に対応しやすいものでなければなりません。

より多くの障害点

いくつかのBlobを別のストレージデバイスに置くことで、大きなBlobをホストするデバイスが故障する可能性があるという故障シナリオが1つ増えます。

代替ソリューション

プロジェクト全体を安価なストレージに配置

Gitデータをより安価なストレージに置く代わりに、Railsアプリケーションはプロジェクト全体をマウントされたHDDドライブに移動させることができます。

可能な最適化

安価なストレージを搭載したこれらのマシンに追加のRAMを与えることで、ページキャッシュの使用による読み取り/書き込み速度の低下に対処できるかもしれません。しかし、これが全体的に安くなるかどうかはわかりません。