Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
proposed |
@mattkasa
@jon_jenkins
|
@DylanGriffith
|
@rogerwoo
@alexives
| devops data_stores | 2023-02-08 |
自動クエリ分析
問題の概要
私たちの包括的な目標は、GitLabデータベースレビュープロセスの信頼性とスループットを改善することです。現在のプロセスでは、新しいクエリを導入したり既存のクエリを更新したりする際に、マージリクエスト作成者が手動でクエリプランと生のSQLを提供する必要があります。これには時間がかかり、エラーも起こりがちです。
新しく導入された SQL クエリを自動的に識別および分析することで、オペレーション効率を改善できると考えています。これにより、人為的なエラーのリスクが減少し、システムの安定性が向上し、パフォーマンスの低下が全体的に減少します。
私たちの主な成功メトリクスは、データベース関連のコード貢献に対する一貫した基準を維持しながら、コード貢献者とデータベースレビュアーの両方が必要とする手動アクションの数を削減することです。
目標
- 作成者が手動でSQLとクエリプランを取得する現在のプロセスを、自動化されたプロセスに置き換えること。
- 手動プロセスによって性能の低いクエリが見逃されることによる性能低下の発生を減少させます。
- データベースレビューのクエリテスト部分を自動化することで、貢献者とレビュアーの効率を高めます。
課題
-
gitlab-org/gitlab
のような規模のアプリケーションで生成される SQL クエリの数を、CIの時間やリソースを増加させることなくキャプチャすることは困難です。 -
gitlab-org/gitlab
のサイズのアプリケーションによって生成された SQL クエリの数を保存することは、大量のデータベースストレージを消費する可能性があります。
機会
- 自動化されたテスト・スイートは、すでに大量の SQL クエリを生成しています。例えば、
rspec
テスト・スイートは、自動化された分析を実行するためにキャプチャして使用することができます。 - 私たちはすでにクエリ・パフォーマンスを分析するために
postgres.ai
を利用しています。また、自動分析を実行するために、本番環境に近い現実的なデータを持つデータベース・クローンの作成を自動化できる API を持っています。 -
postgres.ai
のようなものを使用せず、CIでテストデータベースに接続している顧客に対しては、この接続を使用してクエリプランを生成します。これらのクエリプランの精度は、テストデータがどの程度現実的であるかに影響されます。 - クエリとそのクエリプランを保存することで、クエリプランをプランコンポーネントにトークン化し、コストと重みを割り当て、それらを機械学習モデルと照合することができます。遅いクエリログのクエリプランを生成し、実際のコストと重みをプランコンポーネントに割り当てることで、このモデルを構築することができます。これにより、クエリのコーパスと低速クエリログを活用し、他のアプリケーションや顧客の任意のクエリテキストの性能を予測することができます。
提案
新しいデータベースクエリや変更されたデータベースクエリを特定するプロセスを自動化し、貢献者やレビュアーがコード変更によるデータベースパフォーマンスへの影響をより正確かつ効率的に評価できるようにする予定です。
CI でのテスト実行の副作用として生成されたクエリをキャプチャし、正規化、重複排除、1 つ以上のアナライザを使用して分析し、将来の検索や比較のために分析結果やその他のメタデータと一緒に保存する予定です。
新しいクエリや変更されたクエリの概要、分析へのリンク、確立されたタイミングやその他のパフォーマンスガイドラインを超えたクエリのハイライトを含むコメントをマージリクエストに投稿します。
デザインおよび実施内容
反復1
最初のイテレーションでは、正規化、重複排除、保存を含むクエリのキャプチャ方法に焦点を当てます。キャプチャ中のCIパイプラインのパフォーマンスとリソースの影響を考慮し、保存する情報のパーティショニングや時間減衰などを含める必要があります。
クエリのキャプチャ
CIパイプラインに与える時間とリソースの影響をできる限り抑えるように努めます。クエリをキャプチャするためのオプションのいくつかを紹介します:
- **
ActiveRecord
。ruby
**- 課題
-
ruby
のプロジェクトにのみ適用されるため、container-registry
のようなプロジェクトには適用されません。 - CIパイプラインにおける時間とリソースへの影響はゼロではありません(これらの影響は!111638で確認できます)。
-
- 機会:
- シンプルで導入が簡単。
- より多くの情報(スタックトレースや呼び出し位置など)にアクセスできます。
- 課題
-
ロギング機能付き接続プロキシ
- 課題
- 複雑さとパフォーマンスのオーバーヘッドの可能性
- プロキシ用のコードのメンテナーが必要。
- 機会:
- キャプチャをカスタマイズできます。
- キャプチャ時に正規化/重複排除を実行できます。
- 課題
-
内蔵ロギング
postgresql
- 課題
- ロギングを有効にする設定を追加する必要があります。
- 結果のログを取得するのが難しい場合があります。
- 機会:
- コードをメンテナーする必要がありません。
- パフォーマンスへの影響が少ない
- 課題
-
キャプチャ
pg_stat_statements
- 課題
- テストデータベースで拡張機能を作成する必要があります。
-
pg_stat_statements.max
をすべてのクエリを捕捉するのに十分な値に設定する設定を追加する必要があります。 -
pg_stat_statements.max
に比例して共有メモリを消費します。
- 機会:
- 最小限のコードで済みます。
- データの取得が簡単。
- データはすでに正規化されています。
- 課題
ruby
、ActiveRecord
のインスツルメンテーションの概念実証はすでに!111638で構築済みです。そこで最初のステップとして、他のキャプチャー方法をベンチマークし、最適なオプションを選択します。
クエリの保存
最初の反復の次のステップでは、!111638の概念実証と他のキャプチャ方法をテストして収集したデータを使用して、プロジェクトごとの行数を推定し、gitlab-org/gitlab
のパイプライン実行統計を使ってスループットを推定します。これらの見積もりによって、私たちの目的に適したストレージメカニズムを評価することができます。
評価する予定のストレージメカニズムには、以下のようなものがあります:
-
GitLabデータベースインスタンスの
ci
。- 課題
-
GitLab.com
、このリソースにさらなる負担がかかります。
-
- 機会:
-
CI_JOB_TOKEN
という形で、既存の認証やアクセス制御を利用することができます。 -
ci_builds
やci_pipelines
との関連を活用することができます。 - 自己管理のためのデプロイを簡素化します。
-
- 課題
-
GitLabデータベースインスタンスの新しい分解されたデータベースで
- 課題
- 必要な開発者とテストの労力が増えます。
-
GitLab.com
のデプロイ作業が追加されます。
- 機会:
- 既存の
main
およびci
データベースインスタンスからデータベースパフォーマンスの影響を分離します。
- 既存の
- 課題
-
新しい外部サービスでは
- 課題
- 必要な開発者とテストの労力が増えます。
-
GitLab.com
、自己管理のためのデプロイ作業が追加されます。
- 機会:
- パフォーマンスの影響を
gitlab-org/gitlab
から切り離します。 - メインアプリケーションに影響を与えることなく、より高速な反復処理を可能にします。
- パフォーマンスの影響を
- 課題
-
クリックハウスでは
- 課題
- 自主管理ではまだ利用できません。
- 機会:
- 既存の
main
およびci
データベースインスタンスからデータベースパフォーマンスの影響を分離します。
- 既存の
- 課題
クエリを格納するためのデータベーススキーマの例:
CREATE TABLE queries (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
id bigint NOT NULL,
project_id bigint NOT NULL,
analysis_id bigint,
hash text,
sql text
);
CREATE TABLE pipeline_queries (
id bigint NOT NULL,
project_id bigint NOT NULL,
pipeline_id bigint NOT NULL,
query_id bigint NOT NULL
);
CREATE TABLE analyses (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
id bigint NOT NULL,
project_id bigint NOT NULL,
query_id bigint NOT NULL,
buffers int,
walltime int,
explain text,
analysis_url text
);
上記の例のようなスキーマをパーティショニングする1つの方法として、サブパーティショニングを利用することが考えられます。project_id
、次にupdated_at
の間隔でパーティショニングし、クエリを見つけたらその行をタッチすれば、コードベースがまだ実行中のクエリだけを保存し、コードがもう生成していないクエリだけを含むパーティションを削除することができます。
反復2
2回目の反復では、新しいクエリや変更されたクエリを特定し、要約を含むMRコメントを投稿する予定です。情報の正確性と有用性に関するフィードバックを募集し、有用性を最大化するために改善やフィルタリングを行う予定です。
3回目以降
3回目以降の反復では、1つ以上のアナライザを使用してクエリ分析を自動化し、これらの分析を保存し、MRコメントに追加する予定です。また、クエリ情報を保存するためのデータベースと、それを取得するためのAPIを再評価し、外部サービスに移行する可能性もあります。