GitalyとGitalyクラスター

GitalyはGitリポジトリへのハイレベルなRPCアクセスを提供します。GitLabでGitデータの読み書きに使われます。

GitalyはすべてのGitLabインストールに存在し、Gitリポジトリの保存と取得を調整します。Gitalyは以下のことができます:

  • 単一のインスタンスLinuxパッケージインストール上でオペレーションされるバックグラウンドサービス(GitLabのすべてが1台のマシンにある)。
  • 独自のインスタンスに分離され、スケーリングと可用性の要件に応じてフルクラスタ構成で設定されます。

Gitalyはクライアントサーバアーキテクチャを実装しています:

GitalyはGitLabのGitリポジトリへのアクセスのみを管理します。他のタイプのGitLabデータはGitalyを使ってアクセスされません。

GitLabは設定されたリポジトリストレージを通して リポジトリにアクセスします。それぞれの新しいリポジトリは、設定された重みに基づいてリポジトリストレージの1つに保存されます。各リポジトリストレージは以下のいずれかです:

  • ストレージパスを使用してリポジトリに直接アクセスするGitalyストレージで、各リポジトリは単一のGitalyノードに格納されます。すべてのリクエストはこのノードにルーティングされます。
  • Gitaly Clusterが提供する仮想ストレージで、フォールトトレランスのために各リポジトリを複数のGitalyノードに格納することができます。Gitaly Clusterでは:
    • 読み込み要求は複数のGitalyノードにディストリビューションされ、パフォーマンスを向上させることができます。
    • 書き込み要求はリポジトリレプリカにブロードキャストされます。

Gitalyクラスタをデプロイする前に

Gitaly Clusterは、フォールトトレランスの利点を提供しますが、セットアップと管理の複雑さを伴います。Gitaly Clusterをデプロイする前に、レビューしてください:

まだGitaly Clusterにマイグレーションしていない場合、2つの選択肢があります:

  • シャード化されたGitalyインスタンス。
  • Gitalyクラスタ。

ご不明な点がございましたら、カスタマーサクセスマネージャーまたはカスタマーサポートまでお問い合わせください。

既知のイシュー

以下の表は、Gitaly Clusterの使用に影響する現在の既知の問題の概要です。これらの問題の現在の状況については、参照されている問題とエピックを参照してください。

イシュー要約回避方法
クラスター + Geo - 失敗した同期を再試行するイシューGitaly ClusterがGeoのセカンダリサイトで使用されている場合、同期に失敗したリポジトリは、Geoが再同期を試みても失敗し続ける可能性があります。この状態から回復するには、サポートによる手動ステップの実行が必要です。GitLab 15.0以前の既知の解決策はありません。GitLab 15.0 から 15.2 では、Geo プライマリサイトでgitaly_praefect_generated_replica_paths 機能フラグ を有効にしてください。GitLab 15.3では、機能フラグはデフォルトで有効になっています。
アップグレード後にマイグレーションが適用されず、Praefect がデータベースにデータを挿入できません。マイグレーションが完了したデータベースが最新の状態に保たれていない場合、Praefectノードは標準オペレーションを実行できません。すべてのマイグレーションが完了した状態で、Praefectデータベースが稼動していることを確認してください(例:/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status 、適用されたすべてのマイグレーションのリストが表示されるはずです)。アップグレードアシスタンスをリクエストして、アップグレードプランをサポートにレビューしてもらうことを検討してください。
稼働中のクラスターのスナップショットからのGitalyクラスターノードのリストアGitaly Clusterは一貫性のある状態で動作しているため、遅れているノードを1つ導入すると、クラスターはそのノードのデータと他のノードのデータを照合できなくなります。バックアップ・スナップショットから単一のGitalyクラスタ・ノードをリストアしないでください。

1.GitLabをシャットダウンします。
2.すべてのGitaly Clusterノードを同時にスナップショットします。
3.Praefectデータベースのデータベース・ダンプを取ります。
KubernetesやAmazon ECSなどで実行する場合の制限事項Praefect(クラスター)はサポートされておらず、Gitalyには既知の制限があります。詳細はエピック6127をご覧ください。 リファレンス・アーキテクチャをご利用ください。

スナップショットバックアップとリカバリの制限

Gitalyクラスタはスナップショットバックアップをサポートしていません。スナップショット・バックアップは、Praefectデータベースがディスク・ストレージと同期しなくなるイシューを引き起こす可能性があります。Praefectはリストア中にGitalyディスク情報のレプリケーションメタデータを再構築するため、公式のバックアップおよびリストアRakeタスクを使用する必要があります。

インクリメンタルバックアップを使用すると、Gitalyクラスターのバックアップを高速化できます。

どちらの方法も使用できない場合は、カスタマーサポートにお問い合わせください。

Gitalyクラスタでイシューや制限が発生した場合の対処方法

カスタマーサポートにご連絡ください。

ディスク要件

GitalyとGitalyクラスタは、I/Oベースの処理が多いため、効率的に実行するには高速なローカルストレージが必要です。そのため、すべてのGitalyノードでソリッド・ステート・ドライブ(SSD)を使用することを強く推奨します。

これらのSSDは、少なくとも以下のスループットを持つ必要があります:

  • 8,000入出力オペレーション/秒(IOPS) 読み取りオペレーション。
  • 書き込みオペレーションは2,000 IOPS。

これらのIOPS値は初期の推奨値であり、環境のワークロードの規模に応じて、より大きな値またはより小さな値に調整することができます。クラウドプロバイダー上で環境を実行している場合は、IOPSを正しく設定する方法について、プロバイダーのドキュメントを参照してください。

リポジトリデータについては、パフォーマンスと一貫性の理由から、GitalyとGitalyクラスタではローカルストレージのみがサポートされています。NFSや クラウドベースのファイルシステムなどの代替手段はサポートされていません。

リポジトリへの直接アクセス

GitLabは、ディスク上に保存されたGitalyリポジトリにGitクライアントや他のツールで直接アクセスすることをお勧めしません。なぜなら、Gitalyは継続的に改良され、変更されているからです。これらの改良は、あなたの仮定を無効にし、パフォーマンスの低下、不安定性、さらにはデータの損失をもたらすかもしれません。例えば

  • Gitalyには、info/refs 広告キャッシュのような最適化があります。これは、公式のgRPCインターフェイスを使用することで、Gitalyがリポジトリへのアクセスを制御し、監視することに依存しています。
  • Gitaly Clusterには、フォールトトレランスや分散読み込みなどの最適化があり、リポジトリの状態を決定するためにgRPCインターフェイスとデータベースに依存しています。
caution
Gitリポジトリに直接アクセスすることは、自己責任で行ってください。

Gitaly

以下はGitalyに直接アクセスするようにGitLabをセットアップしたものです:

Shard example

この例では:

  • 各リポジトリは3つのGitalyストレージのうちの1つに保存されます:storage-1storage-2 またはstorage-3
  • 各ストレージはGitalyノードによってサービスされます。
  • 3つのGitalyノードは、それぞれのファイルシステムにデータを格納します。

Gitalyアーキテクチャ

Gitalyのクライアント・サーバーアーキテクチャを以下に示します:

flowchart TD subgraph Gitaly clients A[GitLab Rails] B[GitLab Workhorse] C[GitLab Shell] D[...] end subgraph Gitaly E[Git integration] end F[Local filesystem] A -- gRPC --> Gitaly B -- gRPC--> Gitaly C -- gRPC --> Gitaly D -- gRPC --> Gitaly E --> F

Gitalyの設定

Gitalyには、Linuxパッケージのインストールがあらかじめ設定されており、1000ユーザーまでの利用に適した設定となっています。これは1000ユーザまで対応可能です:

  • 2000ユーザーまでのLinuxパッケージ・インストールについては、Gitalyの具体的な設定方法をご覧ください。
  • 自己コンパイルインストールまたはカスタムGitalyインストールは、Gitalyの設定を参照してください。

毎日Gitの書き込みオペレーションを行う2000人以上のアクティブユーザーのためのGitLabインストールは、Gitalyクラスタを使用することが最適かもしれません。

リポジトリのバックアップ

GitLab以外のツールを使ってリポジトリのバックアップや同期を行う場合、リポジトリデータのコピー中は書き込みを禁止する必要があります。

Gitalyクラスター

GitストレージはGitLabのGitalyサービスを通じて提供され、GitLabのオペレーションに不可欠です。ユーザー数、リポジトリ数、アクティビティ数が増加した場合、Gitalyを適切にスケーリングすることが重要です:

  • リソースの枯渇がGit、Gitaly、GitLabアプリケーションのパフォーマンスを低下させる前に、Gitに利用可能なCPUとメモリリソースを増やします。
  • ストレージの上限に達して書き込みオペレーションが失敗する前に、利用可能なストレージを増やします。
  • 単一障害点を取り除き、耐障害性を向上させます。サービスの劣化によって本番環境へのデプロイができなくなるような場合、Gitはミッションクリティカルであると考えるべきです。

Gitalyはクラスター設定で実行することができます:

  • Gitalyサービスをスケールします。
  • 耐障害性の向上。

この設定では、すべてのGitリポジトリをクラスター内の複数のGitalyノードに保存することができます。

Gitalyクラスターを使うことで、フォールトトレランスは次のように向上します:

  • 書き込みオペレーションをウォームスタンバイGitalyノードにレプリケートします。
  • Gitalyノードの障害の検出。
  • Gitリクエストを利用可能なGitalyノードに自動的にルーティング。
note
GitalyクラスタのテクニカルサポートはGitLab PremiumとUltimateのお客様に限らせていただきます。

以下はGitalyクラスタが提供する仮想ストレージstorage-1 にアクセスするためのGitLabのセットアップです:

Cluster example

この例では:

  • リポジトリはstorage-1という仮想ストレージに保存されます。
  • 3つのGitalyノードがstorage-1gitaly-1gitaly-2gitaly-3
  • 3つのGitalyノードは、3つの別々のハッシュ化されたストレージでデータを共有します。
  • レプリケーション係数は 3です。各リポジトリには3つのコピーがメンテナーされます。

単一ノードの障害を想定したGitalyクラスターの可用性目標は以下の通りです:

  • 復旧ポイント目標(RPO): 1分未満。

    書き込みは非同期にレプリケートされます。新しく昇格させたプライマリにレプリケートされていない書き込みは失われます。

    強力な一貫性により、状況によっては損失を防ぐことができます。

  • 復旧時間目標(RTO): 10秒未満。停止は、各Praefectノードが1秒ごとに実行するヘルスチェックによって検出されます。フェイルオーバーには、各Praefectノードのヘルスチェックが10回連続して失敗する必要があります。

RPOとRTOの改善はエピック8903で提案されています。

caution
クラスターに完全な障害が発生した場合は、ディザスタリカバリ計画を実行する必要があります。これらは上述のRPOとRTOに影響を与える可能性があります。

Geoとの比較

GitalyクラスタとGeoはどちらも冗長性を提供します。しかし、冗長性は

以下の表は、Gitaly ClusterとGeoの主な違いの概要です:

ツールノード所在地遅延耐性フェイルオーバー一貫性冗長性
Gitalyクラスターマルチプルシングル1秒未満、理想的には1桁ミリ秒自動強いGitへのデータ保存
Geoマルチプルマルチプル最大1分手動最終的なGitLabインスタンス全体

詳細については

仮想ストレージ

仮想ストレージは、GitLabで単一のリポジトリストレージを持つことを可能にし、リポジトリ管理を簡素化します。

Gitaly Clusterを使った仮想ストレージは、通常、直接Gitalyストレージの設定を置き換えることができます。しかし、これは複数のGitalyノードに各リポジトリを保存するために必要な追加のストレージ容量を犠牲にすることになります。Gitaly Clusterの仮想ストレージを使用する利点は、Gitalyの直接ストレージを使用するよりも優れています:

  • 各Gitalyノードがすべてのリポジトリのコピーを持つため、耐障害性が向上します。
  • Gitalyノード間で読み込み負荷が分散されるため、シャード固有のピーク負荷に対する過剰プロビジョニングの必要性が減少し、リソース利用率が向上。
  • 読み取り負荷がGitalyノードに分散されるため、パフォーマンスのための手動リバランシングは必要ありません。
  • すべてのGitalyノードが同一であるため、管理がよりシンプルになります。

リポジトリレプリカの数は、レプリケーション係数を使用して設定できます。

すべてのリポジトリに対して同じレプリケーション係数を設定するのは不経済です。非常に大規模なGitLabインスタンスに対してより柔軟性を提供するために、変数レプリケーション係数はこのイシューで追跡されます。

標準的なGitalyストレージと同様に、仮想ストレージはシャーディングすることができます。

ストレージのレイアウト

caution
ストレージレイアウトはGitalyクラスタの内部詳細であり、リリース間の安定性を保証するものではありません。ここでの情報は、情報提供とデバッグのためのものです。リポジトリの変更をディスク上で直接行うことはサポートされておらず、破損や変更が上書きされる可能性があります。

Gitaly Clusterの仮想ストレージは、単一のストレージのように見えますが、実際には複数の物理ストレージで構成される抽象化を提供します。Gitaly Clusterは各オペレーションを各物理ストレージに複製する必要があります。オペレーションは、一部の物理ストレージでは成功しても、他のストレージでは失敗する可能性があります。

部分的に適用されたオペレーションは、他のオペレーションに問題を引き起こし、システムを回復できない状態にする可能性があります。このような問題を回避するには、各オペレーションは完全に適用されるか、まったく適用されないかのいずれかでなければなりません。このようなオペレーションの特性をアトミティと呼びます。

GitLabはリポジトリストレージのストレージレイアウトを制御します。GitLabはリポジトリを作成、削除、移動する場所をリポジトリストレージに指示します。これらのオペレーションが複数の物理的なストレージに適用されるとき、アトミック性のイシューが発生します。例えば

  • GitLabはそのレプリカの1つが利用できない間にリポジトリを削除します。
  • GitLab は後でリポジトリを再作成します。

その結果、削除時に利用できなかった古いリポジトリが競合を引き起こし、リポジトリの再作成を妨げることがあります。

このような原子性のイシューは、過去に複数の問題を引き起こしました:

  • Gitalyクラスターを使用したセカンダリサイトへのGeo同期。
  • バックアップの復元
  • リポジトリストレージ間のリポジトリの移動。

Gitaly Clusterは、部分的に適用されたオペレーションによって発生する可能性のある競合を防ぐ特別なレイアウトでディスク上のリポジトリを格納することによって、これらのオペレーションにアトミック性を提供します。

クライアントが生成するレプリカパス

リポジトリは、Gitalyクライアントによって決定された相対パスでストレージに保存されます。これらのパスは、@cluster プレフィックスで始まらないことで識別できます。相対パスはハッシュ化されたストレージスキーマに従います。

Praefectが生成するレプリカパス(GitLab 15.0以降)

Gitaly Clusterがリポジトリを作成するとき、リポジトリ_IDという_ユニークで永続的なIDを割り当てます。リポジトリIDはGitaly Cluster内部でのもので、GitLabの他のどのIDとも関係ありません。リポジトリがGitaly Clusterから削除され、後で再び移動された場合、そのリポジトリには新しいリポジトリIDが割り当てられ、Gitaly Clusterから見れば別のリポジトリとなります。リポジトリIDの順序は常に増加しますが、順序にギャップがあるかもしれません。

リポジトリIDは、クラスター上の各リポジトリの_レプリカパスと_呼ばれる一意のストレージパスを導出するために使用されます。リポジトリのレプリカはすべて、ストレージ上の同じレプリカパスに格納されます。レプリカパスは_相対パスとは_異なります:

  • 相対パスは、Gitalyクライアントがリポジトリを識別するために使用する名前であり、その仮想ストレージとともにリポジトリに固有のものです。
  • レプリカパスは、物理ストレージ内の実際の物理パスです。

Praefectは、クライアントリクエストを処理する際に、RPC内のリポジトリを仮想リポジトリ(virtual storage, relative path) 識別子から物理リポジトリ(storage, replica_path) 識別子に変換します。

のレプリカパスの形式:

  • オブジェクト・プールのレプリカ・パスの形式は@cluster/pools/<xx>/<xx>/<repository ID> です。オブジェクトプールは、他のリポジトリとは異なるディレクトリに保存されます。ハウスキーピングの一環としてそれらを刈り込まないためには、Gitalyによって識別可能でなければなりません。オブジェクトプールを削除すると、リンク先のリポジトリでデータが失われる可能性があります。
  • 他のリポジトリは@cluster/repositories/<xx>/<xx>/<repository ID>

例えば、@cluster/repositories/6f/96/54771.

レプリカパスの最後の構成要素54771 はリポジトリIDです。これはディスク上のリポジトリを識別するために使用できます。

<xx>/<xx> はリポジトリIDの文字列をSHA256ハッシュした最初の4桁の16進数です。これらの桁は、ファイルシステムによっては問題を引き起こす可能性のある過度に大きなディレクトリを避けるために、リポジトリをサブディレクトリに均等にバランスさせるために使用されます。この場合、547716f960ab01689464e768366d3315b3d3b2c28f38761a58a70110554eb04d582f7 とハッシュするので、最初の4桁は6f96となります。

ディスク上のリポジトリの識別

praefect metadata サブコマンドを使用します:

  • リポジトリの仮想ストレージと相対パスをメタデータストアから取得します。ハッシュ化されたストレージパスを取得したら、Railsコンソールを使ってプロジェクトパスを取得できます。
  • リポジトリがクラスター内のどこに保存されているかを検索するには、次のいずれかを使用します:
    • 仮想ストレージと相対パス。
    • リポジトリID。

ディスク上のリポジトリには、Git 設定ファイルのプロジェクトパスも含まれます。設定ファイルは、リポジトリのメタデータが削除されていても、プロジェクトパスを決定するために使うことができます。ハッシュストレージのドキュメントの指示に従ってください。

オペレーションの原子性

Gitaly Clusterは、リポジトリの作成、削除、移動のオペレーションがアトミックであることを保証するために、ストレージレイアウトとPostgreSQLメタデータストアを使用します。ディスクオペレーションは複数のストレージにアトミックに適用することはできません。しかし、PostgreSQLはメタデータオペレーションのアトミック性を保証します。Gitaly Clusterは、失敗したオペレーションが常にメタデータの一貫性を保つようにオペレーションをモデル化します。オペレーションが成功した後でも、ディスクは古い状態を含んでいるかもしれません。この状況は予期されることであり、残された状態は将来のオペレーションを妨げることはありませんが、クリーンアップが実行されるまで不必要にディスク領域を使用する可能性があります。

現在、ストレージに残っているリポジトリをクリーンアップするバックグラウンド・クローラーを開発中です。

リポジトリ作成

リポジトリを作成する際、Praefect:

  1. PostgreSQLからリポジトリIDを予約します。これはアトミックで、2つの作成が同じIDを受け取ることはありません。
  2. リポジトリIDに由来するレプリカパスのGitalyストレージ上にレプリカを作成します。
  3. リポジトリがディスク上に正常に作成された後、メタデータレコードを作成します。

2つのオペレーションが同時に同じリポジトリを作成しても、ストレージ上の異なるディレクトリに保存され、衝突することはありません。最初に完了したオペレーションがメタデータレコードを作成し、もう一方のオペレーションは “already exists” エラーで失敗します。作成に失敗すると、リポジトリがストレージに残ってしまいます。現在、バックグラウンド・クローラーを開発中で、ストレージに残ったリポジトリをクリーンアップしています。

リポジトリIDはPostgreSQLのrepositories_repository_id_seq 。上記の例では、失敗したオペレーションがリポジトリIDを1つ取得し、そのIDでリポジトリの作成に成功していません。リポジトリの作成に失敗すると、リポジトリIDにずれが生じることが予想されます。

リポジトリの削除

リポジトリはメタデータレコードを削除することで削除されます。メタデータレコードが削除されると同時にリポジトリは論理的に存在しなくなります。PostgreSQLは削除のアトミック性を保証しており、同時削除は「見つかりませんでした」というエラーで失敗します。メタデータレコードの削除に成功すると、Preefectはストレージからレプリカを削除しようとします。これは失敗することがあり、ストレージに残存状態が残ります。残った状態は最終的にクリーンアップされます。

リポジトリの移動

Gitaly ClusterはGitalyと異なり、ストレージ内のリポジトリを移動するのではなく、メタデータストア内のリポジトリの相対パスを更新することで仮想的にリポジトリを移動します。

コンポーネント

Gitaly Clusterは複数のコンポーネントで構成されています:

  • ロードバランサーは、リクエストをディストリビューションし、Praefectノードへのフォールトトレラントなアクセスを提供します。
  • クラスターを管理し、GitalyノードへのリクエストをルーティングするためのPraefectノード。
  • クラスタのメタデータを永続化するためのPostgreSQLデータベースとPlayfectのデータベース接続をプールするためのPgBouncer
  • リポジトリの保存とGitアクセスを提供するGitalyノード。

アーキテクチャ

PraefectはGitalyのルーターでありトランザクションマネージャーであり、Gitalyクラスタを実行するために必要なコンポーネントです。

Architecture diagram

詳細については、Gitaly High Availability(HA) Designをご覧ください。

機能

Gitalyクラスタは以下の機能を提供します:

Gitaly Cluster epicに従って読み込みの水平分散を含む改善を行ってください。

分散リード

Gitaly Clusterは、仮想ストレージ用に設定されたGitalyノード間でのリード・オペレーションの分散をサポートしています。

ACCESSOR オプションでマークされたすべての RPC は、最新かつ健全な Gitaly ノードにリダイレクトされます。例えば、GetBlob.

この文脈での_最新とは_

  • このGitalyノードでは、レプリケーションオペレーションは予定されていません。
  • 最後のレプリケーションオペレーションは_完了_状態です。

以下の場合、プライマリノードがリクエストに応答するために選択されます:

  • 最新のノードが存在しない場合。
  • ノード選択中にその他のエラーが発生しました。

大規模で変更の多いリポジトリ(数ギガバイトのモノレポなど)を使用している場合、センダリノードにレプリケートできる速度よりも早く変更が入ると、プライマリノードがほとんどまたはすべてのリクエストに対応できます。このような場合、CI/CDジョブやその他のリポジトリトラフィックがプライマリノードの容量によってボトルネックになります。

Prometheusを使用して、リードのディストリビューションを監視できます。

強力な一貫性

GitLab 14.0では、強い一貫性が主なレプリケーション方法です。

Gitaly Clusterは、すべての健全で最新のレプリカに同期的に変更を書き込むことで、強力な一貫性を提供します。トランザクション時にレプリカが古かったり不健全であったりした場合、書き込みは非同期でそのレプリカにレプリケートされます。

強力な一貫性は主要なレプリケーション方法です。一部のオペレーションでは、強力な一貫性の代わりにレプリケーション・ジョブ(最終的な一貫性)を使用します。詳細については、強い一貫性のエピックを参照してください。

強い一貫性が利用できない場合、Gitalyクラスタは偶発的一貫性を保証します。この場合Gitaly Clusterは、プライマリGitalyノードへの書き込みが発生した後に、セカンダリノードへの書き込みをすべて複製します。

強い一貫性の監視の詳細については、Gitaly ClusterPrometheusメトリクス・ドキュメントを参照してください。

レプリケーション係数

レプリケーションファクターとは、Gitalyクラスタが保持するリポジトリのコピー数のことです。レプリケーションファクターが高いほど

  • より良い冗長性と読み取りワークロードのディストリビューションを提供します。
  • ストレージコストが高くなります。

デフォルトでは、Gitaly Clusterは仮想ストレージ内のすべてのストレージにリポジトリをレプリケートします。

設定情報については、Configure replication factorを参照してください。

Gitalyクラスタの設定

Gitaly Clusterの設定については、Gitaly Clusterの設定 をご覧ください。

Gitaly Clusterのアップグレード

Gitalyクラスタをアップグレードするには、ゼロダウンタイムアップグレードのドキュメントに従ってください。

Gitaly Clusterを以前のバージョンにダウングレードします。

Gitalyクラスタを以前のバージョンにロールバックする必要がある場合、一部のPraefectデータベースマイグレーションを元に戻す必要がある場合があります。

Gitalyクラスタをダウングレードするには(複数のPraefectノードを想定):

  1. すべてのPraefectノードでPraefectサービスを停止します:

    gitlab-ctl stop praefect
    
  2. Praefectノードの1つでGitLabパッケージを古いバージョンにダウングレードします。
  3. ダウングレードしたノードで、Praefectマイグレーションの状態を確認します:

    /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status
    
  4. APPLIED 列にunknown migration が表示されているマイグレーションの数を数えます。
  5. ダウングレードされていないPraefectノードで、ロールバックのドライランを実行して、どのマイグレーションを戻すかを確認します。<CT_UNKNOWN> は、ダウングレードされたノードから報告された不明なマイグレーションの数です。

    /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate <CT_UNKNOWN>
    
  6. 結果が正しければ、-f オプションを付けて同じコマンドを実行し、マイグレーションを元に戻します:

    /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate -f <CT_UNKNOWN>
    
  7. 残りのPraefectノードでGitLabパッケージをダウングレードし、Praefectサービスを再度起動します:

    gitlab-ctl start praefect
    

Gitalyクラスタへのマイグレーション

caution
Gitaly Clusterにはいくつかの既知のイシューが存在します。続行する前に以下の情報をレビューしてください。

Gitaly Clusterにマイグレーションする前に:

Gitaly Clusterへのマイグレーション:

  1. 必要なストレージを作成します。リポジトリのストレージに関する推奨事項を参照してください。
  2. Gitalyクラスタを作成し、設定します。
  3. 既存のGitalyインスタンスがTCPを使用するように設定します。
  4. リポジトリを移動します。Gitaly Clusterにマイグレーションするには、Gitaly Clusterの外に保存されている既存のリポジトリを移動する必要があります。自動マイグレーションはありませんが、GitLab APIでスケジュールすることができます。

default リポジトリストレージを使用しない場合でも、確実に設定する必要があります。この制限についてもっと読む.

Gitalyクラスタからのマイグレーション

Gitaly Clusterの制限やトレードオフが環境に合わないと判断された場合、Gitaly Clusterからシャード化されたGitalyインスタンスにマイグレーションすることができます:

  1. 新しいGitalyサーバを作成し、設定します。
  2. リポジトリを新しく作成したストレージに移動します。複数のGitalyサーバーに分散させることができます。

GitLabのGitへの直接アクセス

Gitへの直接アクセスには、”Rugged patches “として知られるGitLabのコードを使います。

Gitalyが存在する以前は、現在のGitalyクライアントが直接Gitリポジトリにアクセスすることはできませんでした:

  • シングルマシンのLinuxパッケージインストールの場合は、ローカルディスク。
  • GitLab を水平にインストールする場合は NFS を使用。

GitLabでは、git コマンドの実行に加えて、Ruggedと呼ばれるRubyライブラリを使用していました。Ruggedはlibgit2のラッパーで、Cライブラリの形式でGitをスタンドアロンで実装したものです。

時間が経つにつれて、Ruggedは、特にUnicornとの組み合わせが非常に効率的であることが明らかになりました。libgit2 はライブラリであり、内部プロセスではないため、その間のオーバーヘッドはほとんどありませんでした:

  • Gitリポジトリ内のデータを検索しようとするGitLabアプリケーションコード。
  • Git の実装そのもの。

RuggedとUnicornの組み合わせはとても効率的だったため、GitLabアプリケーションのコードには重複したGitオブジェクトのルックアップがたくさんありました。例えば、デフォルトのブランチのコミットを一回のリクエストで何十回も検索するようなことです。パフォーマンスが低下することなく、非効率的なコードを書くことができました。

これらのGitルックアップをGitalyコールにマイグレーションしたところ、Gitルックアップあたりの固定コストが急に高くなりました。Gitalyがすでに実行されているgit (たとえば、コミットを検索するため)のプロセスを再利用できる場合でも、まだあります:

  • Gitalyへのネットワーク往復のコスト。
  • Gitaly内部では、Gitalyとgit プロセスを接続するUnixパイプへの書き込み/読み取りラウンドトリップ。

GitLab.comを使って測定し、Ruggedを失ったことによる効率の低下を感じなくなるまで、リクエストごとのGitaly呼び出しの回数を減らしました。また、Gitaly自体をNFSマウントではなく、Gitファイルサーバー上で直接実行したことも役立ちました。これによって、Ruggedを使わなくなったことによるマイナス効果を打ち消すほどのスピードの向上が得られました。

残念なことに、GitLabの他のデプロイメントでは、私たちがGitLab.comで行ったようにNFSを削除することができず、両方の悪い面が出てしまいました:

  • NFSの遅さです。
  • Gitaly固有のオーバーヘッドの増加。

Gitalyマイグレーションプロジェクト中にGitLabから削除されたコードは、これらのデプロイに影響を与えました。これらのNFSベースのデプロイに対するパフォーマンスの回避策として、私たちは古いRuggedコードの一部を再導入しました。この再導入されたコードは非公式に “Ruggedパッチ “と呼ばれています。

自動検出

GitLab 15.3ではRuggedの自動検出は無効になっています。

フラグ: セルフマネジメントのGitLabでは、デフォルトではRuggedを使用すべきかどうかの自動検出(ストレージごと)は利用できません。これを利用可能にするには、管理者がskip_rugged_auto_detect という機能フラグを無効にします。

Git に直接アクセスする Ruby のメソッドは機能フラグの後ろにあり、デフォルトでは無効になっています。最高のパフォーマンスを得るために機能フラグを設定するのは不便だったので、Gitへの直接アクセスを可能にする自動メカニズムを追加しました。

GitLabが “Rugged patch “を持つ関数を呼び出すと、2つのチェックを行います:

  • このパッチの機能フラグがデータベースに設定されているか?もしそうなら、機能フラグの設定はGitLabが “Rugged patch “コードを使うかどうかをコントロールします。
  • 機能フラグが設定されていない場合、GitLabはGitalyサーバーの下のファイルシステムに直接アクセスしようとします。もし可能であれば、”Rugged patch “を使用します:

これらのチェックの結果はキャッシュされます。

GitLab がリポジトリのファイルシステムに直接アクセスできるかどうかを調べるには、次のヒューリスティックを使います:

  • Gitalyは、ファイルシステムのルートにUUIDを持つメタデータファイルがあることを確認します。
  • GitalyはこのUUIDをServerInfo RPCを使ってGitLabにレポーターします。
  • GitLab Railsはメタデータファイルを直接読み込もうとします。もしそれが存在し、UUIDが一致すれば、直接アクセスできたとみなします。

Git への直接アクセスとは

  • GitLab 15.3 以降では、Praefect が生成するレプリカパスとの互換性のため、デフォルトで無効になっています。Rugged機能フラグが有効な場合は有効にできます。
  • GitLab 15.2以前では、GitLab設定ファイルconfig/gitlab.yml に正しいリポジトリパスが入力されるため、デフォルトで有効になっています。これはUUIDチェックを満たします。

Gitalyクラスタへの移行

複雑さを取り除くために、GitLabのGitへの直接アクセスを削除しなければなりません。しかし、いくつかのGitLabインストールがNFS上のGitリポジトリを必要とする限り、削除することはできません。

GitLabでGitへの直接アクセスを削除するための私たちの取り組みの2つの側面があります:

  • GitLabが行う非効率的なGitalyクエリの数を減らすこと。
  • フォールト・トレラントまたは水平にスケールされたGitLabインスタンスの管理者にNFSからのマイグレーションを説得します。

2つ目の側面は、唯一の真の解決策を提示します。このために私たちはGitalyクラスタを開発しました。