CIミラーテーブル

問題ステートメント

GitLabが使用している単一のデータベースを、mainci の2つのデータベースに分割することを目的としたデータベース分割作業の一環として、 mainci テーブルの間のすべての結合を削除するという大きな課題が発生しました。PostgreSQLは異なるデータベースに属するテーブル間の結合をサポートしていないからです。しかし、メインデータベースにあるいくつかのコアアプリケーションモデルは、CIサイドから非常に頻繁にクエリされます。例えば

  • Namespace namespaces
  • Project projects

これらのテーブルでjoins 。チームは、メイン・データベースからCIデータベースへ、これらのテーブルを新しいテーブルに論理レプリケーションすることを選択しました:

  • ci_namespace_mirrors namespaces テーブルのミラーとして
  • ci_project_mirrors projects テーブルのミラーとして

この論理レプリケーションには2つの意味があります:

  1. main データベースのテーブルをクエリし、namespaces およびprojects テーブルに結合できます。
  2. ci データベース・テーブルは、ci_namespace_mirrors およびci_project_mirrors テーブルと結合できます。
graph LR subgraph "Main database (tables)" A[namespaces] -->|updates| B[namespaces_sync_events] A -->|deletes| C[loose_foreign_keys_deleted_records] D[projects] -->|deletes| C D -->|updates| E[projects_sync_events] end B --> F C --> G E --> H subgraph "Sidekiq worker jobs" F[Namespaces::ProcessSyncEventsWorker] G[LooseForeignKeys::CleanupWorker] H[Projects::ProcessSyncEventsWorker] end F -->|do update| I G -->|delete records| I G -->|delete records| J H -->|do update| J subgraph "CI database (tables)" I[ci_namespace_mirrors] J[ci_project_mirrors] end

このレプリケーションは、それぞれのモデルから必要とされるいくつかの属性のみに制限されています:

  • Namespace から、traversal_ids を複製します。
  • Project からは、プロジェクトが属するグループを表すnamespace_id のみを複製します。

CIでミラーリングされたテーブルをソーステーブルと同期させる方法

ソース・テーブルとターゲット・テーブルを同期させるためには、2つのタイプ3のイベントに注意する必要があります:

  1. 新しいネームスペースまたはプロジェクトの作成。
  2. ネームスペースまたはプロジェクトの更新。
  3. ネームスペース/プロジェクトの削除。
graph LR subgraph CI["CI Tables"] E[other CI tables] F{queries with joins allowed} G[ci_project_mirrors] H[ci_namespace_mirrors] E---F F---G F---H end Main["Main Tables"]---L["⛔ ← Joins are not allowed → ⛔"] L---CI subgraph Main["Main Tables"] A[other main tables] B{queries with joins allowed} C[projects] D[namespaces] A---B B---C B---D end

作成と更新

新しく作成または更新されたネームスペースまたはプロジェクトのデータの同期は、この順序で行われます:

  1. ** main データベース** :namespaces またはprojects テーブル上のINSERT またはUPDATE は、テーブルnamespaces_sync_eventsおよびprojects_sync_eventsにエントリを追加します。これらのテーブルはmain データベースにも存在します。これらのエントリは、両方のテーブルのトリガによって追加されます。
  2. モデルレベルではソース・モデルNamespace またはProject のいずれかでコミットが発生すると、対応するSidekiqジョブNamespaces::ProcessSyncEventsWorker またはProjects::ProcessSyncEventsWorker の実行がスケジュールされます。
  3. これらのワーカーは次に
    1. main データベースから(namespaces/project)_sync_events テーブルのエントリを読み込んで、同期するネームスペースやプロジェクトをチェックします。
    2. 更新されたレコードのデータをターゲット・テーブルci_namespace_mirrors,ci_project_mirrors にコピーします。

削除

namespaces またはprojects のいずれかが削除されると、緩い外部キー (LFK) メカニズムを使用して、ミラーリングされた CI テーブルの対象レコードが削除されます。

config/gitlab_loose_foreign_keys.yml にこれらの項目があることで、LFK メカニズムはすでに期待通りに動作していました。これは、main データベースで削除されたnamespaces またはprojects にマッピングされた CI ミラーテーブル上のレコードを削除します。

ci_namespace_mirrors:
  - table: namespaces
    column: namespace_id
    on_delete: async_delete
ci_project_mirrors:
  - table: projects
    column: project_id
    on_delete: async_delete

整合性チェック

両方の同期メカニズムが期待通りに動作することを確認するために、数分ごとに cron ジョブによって起動される 2 つの特別なワーカージョブをデプロイします:

  1. Database::CiNamespaceMirrorsConsistencyCheckWorker
  2. Database::CiProjectMirrorsConsistencyCheckWorker

これらのジョブは

  1. カーソルを使用して、main データベース上の両方のソース・テーブルをスキャンします。
  2. namespaces およびprojects の項目をci データベースのターゲット・テーブルと比較します。
  3. 同期していない項目を Kibana と Prometheus にレポーターします。
  4. 不一致を修正します。