サービスPingの実装

Service Pingは2種類のデータから構成されています:

  • カウンタ:カウンタ:CI/CDパイプラインが何回実行されたかなど、あるイベントがどのくらいの頻度で発生したかを追跡します。これらは単調で、通常は上昇傾向にあります。
  • オブザベーション:1つ以上のGitLabインスタンスから収集された事実で、任意のデータを運ぶことができます。データの性質上、収集方法に関する一般的なガイドラインはありません。

Service Pingに新しいメトリクスを実装するには、以下の手順に従ってください:

  1. 必要なカウンターの実装
  2. メトリクスに名前を付けて配置します。
  3. Railsコンソールを使って手動でカウンタをテストします。
  4. SQLクエリを生成します。
  5. Database Labでクエリを最適化
  6. メトリクス辞書にメトリクスの定義を追加します。
  7. マージリクエストを作成します。
  8. メトリックの検証
  9. Service Pingのローカル設定とテスト

インストルメンテーション・クラス

note
usage_data.rb で直接メトリクスを実装することは非推奨です。Service Ping メトリックを追加または変更する場合は、メトリックをインスツルメンテーション・クラスにマイグレーションする必要があります。Service Ping メトリクスのマイグレーションの進捗については、このエピックを参照してください。

例えば、次のインスツルメンテーション・クラスがあります:lib/gitlab/usage/metrics/instrumentations/count_boards_metric.rb.

これをusage_data.rb に次のように追加します:

boards: add_metric('CountBoardsMetric', time_frame: 'all'),

カウンターの種類

メトリクスには、いくつかの種類のカウンターがあります:

note
提供されているカウンタ・メソッドのみを使用してください。各カウンタ・メソッドには、Service Pingプロセス全体が壊れないように各カウンタを分離するフェイルセーフ・メカニズムが組み込まれています。

バッチカウンタ

大きなテーブルの場合、PostgreSQLはMVCC(複数バージョン同時実行制御)のために行のカウントに時間がかかることがあります。バッチカウンタは、1つの大きなクエリを複数の小さなクエリに分割してカウントする方法です。例えば、1,000,000レコードのクエリを1回実行する代わりに、バッチカウントでは10,000レコードずつのクエリを100回実行することができます。バッチカウンティングはデータベースのタイムアウトを回避するのに便利です。

GitLab.com では、15 秒のクエリタイムアウトが発生するような非常に大きなテーブルがあります。以下に GitLab.com のテーブルのサイズを示します:

テーブル行数(単位:百万
merge_request_diff_commits2280
ci_build_trace_sections1764
merge_request_diff_files1082
events514

バッチカウンティングでは、最大、最小、範囲クエリを計算するためにカラムにインデックスが必要です。場合によっては、カウンターに関係するカラムに専用のインデックスを追加する必要があります。

通常のバッチカウンタ

count オペレーションを持つ新しいデータベース・メトリクス・インスツルメンテーション・クラスを作成します。ActiveRecord_Relation

メソッドを使用します:

add_metric('CountIssuesMetric', time_frame: 'all')

例:

usage_data.rb を使用した例は非推奨となりました。インストルメンテーション・クラスの使用を推奨します。

個別のバッチ・カウンタ

与えられたActiveRecord_Relation に対して、distinct_count オペレーションを持つ新しいデータベース・メトリクス・インスツルメンテーション・クラスを作成します。

メソッドを使用します:

add_metric('CountUsersAssociatingMilestonesToReleasesMetric', time_frame: 'all')
caution
一意でないカラムをカウントすると、パフォーマンスのイシューが発生する可能性があります。詳細については、バッチでのテーブルの反復処理ガイドを参照してください。

例:

usage_data.rb を使用した例は非推奨となりました。インストルメンテーション・クラスの使用を推奨します。

一括オペレーション

与えられたカラムの与えられたActiveRecord_Relationの値を合計し、エラーを処理します。ActiveRecord::StatementInvalid エラーを処理します。

メソッドを使用します:

add_metric('JiraImportsTotalImportedIssuesCountMetric')

平均バッチオペレーション

指定された列の指定されたActiveRecord_Relation の値を平均し、エラーを処理します。

メソッドを使用します:

add_metric('CountIssuesWeightAverageMetric')

例:

usage_data.rb を使用した例は非推奨となりました。インストルメンテーション・クラスの使用を推奨します。

グループ化とバッチオペレーション

count,distinct_count およびsum バッチカウンタは、指定したカラムでグループ化するActiveRecord::Relation オブジェクトを受け取ることができます。グループ化された関係で、メソッドはバッチカウントを行い、エラーを処理し、キーと値のペアのハッシュテーブルを返します。

例:

count(Namespace.group(:type))
# returns => {nil=>179, "Group"=>54}

distinct_count(Project.group(:visibility_level), :creator_id)
# returns => {0=>1, 10=>1, 20=>11}

sum(Issue.group(:state_id), :weight))
# returns => {1=>3542, 2=>6820}

オペレーション追加

パラメータとして与えられた値を合計します。StandardError を処理します。-1 引数のいずれかが . -1

メソッドを使用します:

add(*args)

例:

project_imports = distinct_count(::Project.where.not(import_type: nil), :creator_id)
bulk_imports = distinct_count(::BulkImport, :user_id)

 add(project_imports, bulk_imports)

推定バッチカウンター

GitLab 13.7 で導入されました

推定バッチカウンタ機能は、提供されたestimate_batch_distinct_count メソッドで使用された場合にActiveRecord::StatementInvalid エラーを処理します。エラーは-1 の値を返します。

caution
この関数は、HyperLogLogアルゴリズムを使用して、指定された列内の特定のActiveRecord_Relationの個別のカウントを推定します。HyperLogLogアルゴリズムは確率的なので、結果には常にエラーが含まれます。最も高いエラー率は4.9%です。

estimate_batch_distinct_count メソッドを正しく使用すると、他のカウンタでは保証できない、一意でない値を含むカラムを効率的にカウントすることができます。

estimate_batch_distinct_count メソッド

メソッドを使用します:

estimate_batch_distinct_count(relation, column = nil, batch_size: nil, start: nil, finish: nil)

メソッドには以下の引数があります:

  • relation:カウントを実行する ActiveRecord_Relation。
  • column:個別カウントを行うカラム。デフォルトは主キー。
  • batch_size:Gitlab::Database::PostgresHll::BatchDistinctCounter::DEFAULT_BATCH_SIZE から。デフォルト値:10,000。
  • start:バッチカウントのカスタム開始値。
  • finish:複雑な最大値の計算を避けるための、バッチカウントのカスタム終了値。

このメソッドには以下の前提条件があります:

  • 提供されるrelation には、数値カラムとして定義された主キーが含まれていなければなりません。例:id bigint NOT NULL
  • estimate_batch_distinct_count は結合されたリレーションを扱うことができます。一意でない列をカウントする機能を使用するには、has_many :boards のように、結合されたリレーションが一対多のリレーションであってはなりません
  • startfinish の両引数は、推定カウントが別の列を参照する場合などであっても、常に主キー関係の値を表す必要があります:

       estimate_batch_distinct_count(::Note, :author_id, start: ::Note.minimum(:id), finish: ::Note.maximum(:id))
    

例:

  1. 推定バッチカウンタの単純な実行で、リレーションのみが提供され、返される値はProject リレーションのid カラム (これはプライマリキーです) の一意な値の推定数を表します:

      estimate_batch_distinct_count(::Project)
    
  2. 推定バッチカウンタの実行。提供されたリレーションに追加フィルタ(.where(time_period))が適用され、カスタムカラム(:author_id)の一意な値の推定数が返されます。パラメータ:startfinish は、提供されたリレーションの分析範囲を定義する境界を適用します:

      estimate_batch_distinct_count(::Note.with_suggestions.where(time_period), :author_id, start: ::Note.minimum(:id), finish: ::Note.maximum(:id))
    

推定バッチカウンタの使用量でメトリクスを計測する場合、その名前に_estimated というサフィックスをつけてください:

  "counts": {
    "ci_builds_estimated": estimate_batch_distinct_count(Ci::Build),
    ...

Redis カウンター

::Redis::CommandErrorGitlab::UsageDataCounters::BaseCounter::UnknownEvent を扱います。ブロックが送信された場合は -1、すべての値を含むハッシュが送信された場合は -1、counter(Gitlab::UsageDataCounters) が送信された場合は -1 を返します。挙動が異なるのは、Redisカウンタの実装が2つ異なるためです。

メソッドを使用します:

redis_usage_data(counter, &block)

引数:

  • counter fallback_totals メソッドを実装したGitlab::UsageDataCounters のカウンタ。
  • またはblock: 評価されます。

通常のRedisカウンター

実装例:Gitlab::UsageDataCounters::WikiPageCounterRedis のメソッドINCR およびGETを使用します。

イベントは、BaseCounter を継承したGitlab::UsageDataCounters 名前空間のカウンター・クラスによって処理されます:

  1. Gitlab::UsageDataCounters::COUNTERS にリストされ、Gitlab::UsageData に含まれます。

  2. prefix オプションによってRedisMetric インストルメンテーション・クラスを使用してメトリック定義で指定され、メトリック・インストルメンテーション・フレームワークを使用してピックアップされます。実装例については、Redisメトリクスのドキュメントを参照してください。

継承するクラスは、イベント名と関連するメトリクスを構築するために、KNOWN_EVENTSPREFIX 定数をオーバーライドすることが期待されます。例えば、プレフィックスissues とイベント配列%w[create, update, delete] の場合、3 つのメトリクスが Service Ping ペイロードに追加されます:counts.issues_createcounts.issues_update およびcounts.issues_delete

UsageData API

UsageData API を使用してイベントを追跡できます。イベントを追跡するには、usage_data_api 機能フラグが有効(default_enabled: true に設定)になっている必要があります。GitLab 13.7以降ではデフォルトで有効になっています。

UsageData APIのトラッキング
  1. UsageData API を使用してイベントをトラッキングします。

    指定されたイベント名に対して、通常の Redis カウンタを使用してイベントカウントをインクリメントします。

    APIリクエストは、有効なCSRFトークンをチェックすることで保護されます。

    POST /usage_data/increment_counter
    
    属性種類必須説明
    event文字列です。yes追跡するイベント名。

    レスポンス

    • 200 イベントが追跡された場合。
    • 400 Bad request イベントパラメータがない場合。
    • 401 Unauthorized ユーザーが認証されていない場合。
    • 403 Forbidden 無効な CSRF トークンが提供された場合。
  2. UsageData APIを呼び出す JavaScript/Vue API ヘルパーを使用してイベントを追跡します。

    イベントを追跡するには、usage_data_apiusage_data_#{event_name} を有効にする必要があります。

    import api from '~/api';
       
    api.trackRedisCounterEvent('my_already_defined_event_name'),
    

Redis HLLカウンター

caution
HyperLogLog(HLL) は確率的アルゴリズムであり、その結果には常に若干のエラーが含まれます。Redisのドキュメントによると、使用されているHLL実装からのデータは「0.81%の標準エラーで近似」されています。
note
パフォーマンス上の理由から、usage_stats (User.single_user&.requires_usage_stats_consent?) に対するユーザーの同意は、データ追跡ステージではチェックされません。これらのカウンターに対応するキーは、usage_stats_consent 必要 usage_stats_consentであってもRedisに存在します。usage_stats_consent しかし、必要とされる限り、Redisからメトリクスが収集され、GitLabにレポートバックさ usage_stats_consentれることはありません。

Gitlab::UsageDataCounters::HLLRedisCounter 、ユニークな値をカウントするためのデータ構造が利用できます。

RedisのメソッドPFADDと PFCOUNTを使って実装されています。

新しいイベントを追加
  1. 必要なメトリクスにイベントを追加するか(例を参照)、メトリクスを作成します。

  2. イベントを追跡するには、次のいずれかの方法を使用します:

    • ProductAnalyticsTracking モジュールと以下のフォーマットを使用します:

       track_event(*controller_actions, name:, action:, label:, conditions: nil, destinations: [:redis_hll], &block)
      

      引数:

      • controller_actions追跡するコントローラのアクション。
      • nameイベント名。
      • action: destination が `:snowplow’ の場合は必須。トリガーされたイベントのアクション名。詳細はイベントスキーマを参照してください。
      • labeldestination が `:snowplow’ の場合は必須。トリガーされたイベントのラベル。詳細はイベントスキーマを参照してください。
      • conditionsオプションのカスタム条件。Railsコールバックと同じ形式を使用します。
      • destinationsオプションの宛先リスト。現在は:redis_hll:snowplowをサポートしています。デフォルト::redis_hll.
      • &block: 追跡したいcustom_id を計算して返すオプションのブロック。これはvisitor_idを上書きします。

      使用例:

       # controller
       class ProjectsController < Projects::ApplicationController
         include ProductAnalyticsTracking
            
         skip_before_action :authenticate_user!, only: :show
         track_event :index, :show,
           name: 'users_visiting_projects',
           action: 'user_perform_visit',
           label: 'redis_hll_counters.users_visiting_project_monthly',
           destinations: %i[redis_hll snowplow]
            
         def index
           render html: 'index'
         end
            
        def new
          render html: 'new'
        end
            
        def show
          render html: 'show'
        end
       end
      
    • API 内でincrement_unique_values(event_name, values) ヘルパーメソッドを使用します。

      引数:

      • event_nameイベント名。
      • valuesカウントされる値。1つの値または値の配列。

      使用例:

       get ':id/registry/repositories' do
         repositories = ContainerRepositoriesFinder.new(
           user: current_user, subject: user_group
         ).execute
            
         increment_unique_values('users_listing_repositories', current_user.id)
            
         present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
       end
      
    • サービスとGraphQLでtrack_usage_event(event_name, values)

      Redis HLLを使用して、指定されたイベント名に対して一意な値のカウントを増やします。

      例:

         track_usage_event(:incident_management_incident_created, current_user.id)
      
    • UsageData APIを使用します。

      Redis HLL を使用して、指定されたイベント名のユニークユーザーカウントをインクリメントします。

      APIリクエストは、有効なCSRFトークンをチェックすることで保護されます。

       POST /usage_data/increment_unique_users
      
      属性種類必須説明
      event文字列です。yes追跡するイベント名

      レスポンス

      • 200 イベントが追跡された場合、または何らかの理由で追跡が失敗した場合。
      • 400 Bad request イベントパラメータが見つからない場合。
      • 401 Unauthorized ユーザーが認証されていない場合。
      • 403 Forbidden 無効な CSRF トークンが提供された場合。
    • UsageData APIを呼び出す JavaScript/Vue API ヘルパーを使用します。

      すでにメトリクスフィールドで定義されている既存のイベントの例:

       import api from '~/api';
            
       api.trackRedisHllUserEvent('my_already_defined_event_name'),
      
  3. Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names:, start_date:, end_date:, context: '') を使用してイベントデータを取得します。

    引数:

    • event_namesイベント名のリスト。
    • start_dateイベントデータを取得したい期間の開始日。
    • end_dateイベントデータを取得したい期間の終了日。
    • contextイベントのコンテキスト。指定できる値はdefault,free,bronze,silver,gold,starter,premium,ultimateです。
  4. トラッキングのテストとユニークイベントの取得

track_event メソッドを使用して、Rails コンソールでイベントをトリガーします。

Gitlab::UsageDataCounters::HLLRedisCounter.track_event('users_viewing_compliance_audit_events', values: 1)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('users_viewing_compliance_audit_events', values: [2, 3])

次に、現在の週のユニークなイベントを取得します。

# Get unique events for metric for current_week
Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'users_viewing_compliance_audit_events',
start_date: Date.current.beginning_of_week, end_date: Date.current.next_week)
推奨

新しいイベントを追加するために、以下のことをお勧めします:

  • 新しいメトリクスを追加する場合は、機能フラグを使用して影響を制御します。デフォルトでは、新機能フラグを無効にすることをお勧めします(default_enabled: false に設定)。
  • イベントは、UsageData API を使用してトリガすることができます。
Redis HLLトラッキングの有効化または無効化

グローバルフラグを使うことで、トラッキングを完全に無効にすることができます:

/chatops run feature set redis_hll_tracking true
/chatops run feature set redis_hll_tracking false
既知のイベントは自動的にサービスデータのペイロードに追加されます。

Service PingはすべてのイベントをService Data生成にredis_hll_counters キーで追加します。このカラムはJSONとしてversion-appに保存されます。各イベントに対して、週単位と月単位のメトリクスを追加し、該当する場合はそれぞれの合計を追加します:

  • #{event_name}_weekly:日次集計イベントの場合は7日分のデータ、週次集計イベントの場合は直近1週間分のデータ。
  • #{event_name}_monthly:日次集計イベントの場合は28日分のデータ、週次集計イベントの場合は直近4週間分のデータ。

redis_hll_counters データの例:

{:redis_hll_counters=>
  {"compliance"=>
    {"users_viewing_compliance_dashboard_weekly"=>0,
     "users_viewing_compliance_dashboard_monthly"=>0,
     "users_viewing_compliance_audit_events_weekly"=>0,
     "users_viewing_audit_events_monthly"=>0,
     "compliance_total_unique_counts_weekly"=>0,
     "compliance_total_unique_counts_monthly"=>0},
 "analytics"=>
    {"users_viewing_analytics_group_devops_adoption_weekly"=>0,
     "users_viewing_analytics_group_devops_adoption_monthly"=>0,
     "analytics_total_unique_counts_weekly"=>0,
     "analytics_total_unique_counts_monthly"=>0},
   "ide_edit"=>
    {"users_editing_by_web_ide_weekly"=>0,
     "users_editing_by_web_ide_monthly"=>0,
     "users_editing_by_sfe_weekly"=>0,
     "users_editing_by_sfe_monthly"=>0,
     "ide_edit_total_unique_counts_weekly"=>0,
     "ide_edit_total_unique_counts_monthly"=>0}
 }
}

使用例:

# Redis Counters
redis_usage_data(Gitlab::UsageDataCounters::WikiPageCounter)

# Tracking events
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('users_expanding_vulnerabilities', values: visitor_id)

# Get unique events for metric
redis_usage_data { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'users_expanding_vulnerabilities', start_date: 28.days.ago, end_date: Date.current) }

代替カウンター

StandardError と -1 へのフォールバックを処理します。これにより、1 つの例外が発生しても、すべてのメジャーが失敗することはありません。主に設定と構成に使用されます。

メソッドを使用します:

alt_usage_data(value = nil, fallback: -1, &block)

引数:

  • valueこの場合、値が返されます。
  • またはblock: 評価されます。
  • fallback: -1: 失敗しているメトリクスに使用される共通の値。

使用例:

alt_usage_data { Gitlab::VERSION }
alt_usage_data { Gitlab::CurrentSettings.uuid }
alt_usage_data(999)

新しいメトリクスを構築するためのカウンターの追加

2 つのカウンターの結果を追加する場合は、フォールバック値と例外を処理するadd Service Data メソッドを使用します。また、有効なSQL エクスポートも生成します。

使用例:

add(User.active, User.bot)

クエリ

オペレーション・メトリクスをService Pingの一部とする場合、データベースやRedisクエリでは有用なデータは得られないでしょう。なぜなら、ほとんどのGitLabアーキテクチャ・コンポーネントはPrometheusにメトリクスを公開しており、それをクエリバックして集計し、サービス・データとして含めることができるからです。

note
サービスPingのデータソースとしてのPrometheusは、バンドルされているPrometheusインスタンスを実行しているシングルノードのOmnibusインストールでのみ利用可能です。

yield Prometheus にメトリクスをクエリするには、ヘルパー・メソッドを使用してPrometheusClientを完全に設定します:

with_prometheus_client do |client|
  response = client.query('<your query>')
  ...
end

データをクエリするための API の使用方法については、 PrometheusClient 定義 を参照してください。

サービスPingのフォールバック値

これらの場合、フォールバック値を返します:

ケース
非推奨メトリクス(バージョン14.3で削除)-1000
タイムアウト、一般的な障害-1
カウンターの標準エラー-2
ヒストグラム・メトリクスの失敗{ ‘-1’ => -1 }

Railsコンソールを使って手動でカウンタをテストします。

# count
Gitlab::UsageData.count(User.active)
Gitlab::UsageData.count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)

# count distinct
Gitlab::UsageData.distinct_count(::Project, :creator_id)
Gitlab::UsageData.distinct_count(::Note.with_suggestions.where(time_period), :author_id, start: ::User.minimum(:id), finish: ::User.maximum(:id))

SQLクエリを生成します。

Railsコンソールは生成されたSQLクエリを返します。たとえば

pry(main)> Gitlab::UsageData.count(User.active)
   (2.6ms)  SELECT "features"."key" FROM "features"
   (15.3ms)  SELECT MIN("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
   (2.4ms)  SELECT MAX("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
   (1.9ms)  SELECT COUNT("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4)) AND "users"."id" BETWEEN 1 AND 100000

データベースラボでクエリを最適化

Database Labは、本番クローンを使ってクエリをテストするサービスです。

  • GitLab.comの本番データベースには15秒のタイムアウトがあります。
  • コールドキャッシュを使う場合は、クエリの実行時間を1秒以内に抑えなければなりません。
  • 実行時間を短縮するために、関係するカラムに特化したインデックスを追加します。

クエリの実行を理解するために、マージリクエストの記述に以下の情報を追加します:

  • time_period テストを持つカウンターの場合、両方の情報を追加します:
    • time_period = {} の両方の情報を追加します。
    • time_period = { created_at: 28.days.ago..Time.current } 過去28日間
  • 最適化前後の実行プランとクエリ時間。
  • インデックスと時間に対して生成されたクエリ。
  • 上下実行のマイグレーション出力。

詳細については、データベースレビューガイドを参照してください。

最適化の推奨事項と例

  • 特殊なインデックスを使用してください。例については、これらのマージリクエストを参照してください:
  • 定義されたstartfinishを使用してください。これらの値は、このマージリクエスト例のように、メモして再利用することができます。
  • クエリの結合や不必要な複雑さは避けてください。例としてこのマージリクエスト例を参照してください。
  • このマージリクエスト例のように、distinct_countにカスタムbatch_size を設定します。

メトリクス定義を追加します。

詳細については、『メトリクス辞書』ガイドを参照してください。

マージリクエストの作成

新しい Service Ping メトリクスのマージ・リクエストを作成し、以下を実行します:

  • マージリクエストにfeature ラベルを追加します。メトリクスはユーザー向けの変更であり、Service Ping 機能の拡張の一部です。
  • 変更ログエントリガイドに準拠した変更ログエントリを追加します。
  • Analytics Instrumentation のレビューを依頼してください。GitLab.com では、Analytics Instrumentation 関連のファイルを監視し、Analytics Instrumentation のレビューを推奨するために DangerBot を設定しています。

メトリクスを確認

GitLab.comでは、プロダクトインテリジェンスチームが定期的にService Pingを監視しています。あなたのメトリクスをより速く、より成功させるためにさらなる最適化が必要であることを警告してくれるかもしれません。

GitLab.com の Service Ping JSON ペイロードは、毎週#g_product_intelligenceSlack チャンネルで共有されます。

ServicePing QAダッシュボードを使って、メトリクスがどの程度機能しているかをチェックすることもできます。このダッシュボードでは、GitLabのバージョン、”Self-managed “と “SaaS “によるフィルタリングが可能で、各メトリクスの障害発生件数が表示されます。失敗率が高いことに気づいたら、いつでもメトリックを再最適化することができます。

メトリクスディクショナリの クリップボードへのクエリのコピー機能を使用すると、特定のメトリクスに対してSisenseで実行できるクエリを取得できます。

ローカルでのサービスPingの設定とテスト

Service Pingをローカルで設定するには、以下の手順が必要です:

  1. ローカルリポジトリを設定します。
  2. ローカルのセットアップをテストします。
  3. オプションPrometheus ベースのサービス Ping をテストします。

ローカルリポジトリの設定

  1. GitLabをクローンして起動します。
  2. Versions Applicationをクローンして起動します。PostgreSQLとRedisのインスタンスを起動するためにdocker-compose up
  3. GitLab をデフォルトのエンドポイントではなく、Versions Application のエンドポイントに指定します:
    1. ローカルでservice_ping/submit_service.rbを開き、STAGING_BASE_URL を修正します。
    2. ローカルのVersions Application URLに設定します:http://localhost:3000.

ローカルセットアップのテスト

  1. gitlab Railsコンソールを使って、手動でService Pingをトリガーします:

    GitlabServicePingWorker.new.perform('triggered_from_cron' => false)
    
  2. versions Rails コンソールを使用して、Service Ping が正常に受信、解析され、Versions データベースに保存されたことを確認します:

    UsageData.last
    

PrometheusベースのサービスPingのテスト

送信されたデータに、検査および検証したいPrometheusからクエリされたメトリクスが含まれている場合は、以下の手順が必要です:

  • Prometheus サーバーがローカルで実行されていることを確認します。
  • それぞれのGitLabコンポーネントがPrometheusサーバーにメトリクスをエクスポートしていることを確認します。

Prometheusからのデータをテストする必要がない場合は、これ以上のアクションは必要ありません。Prometheusサーバーが稼働していない場合、サービスPingは優雅に低下するはずです。

3種類のコンポーネントがPrometheusにデータをエクスポートし、Service Pingに含まれます:

  • node_exporter:ホスト・マシンからノードのメトリクスをエクスポートします。
  • gitlab-exporter:GitLabの様々なコンポーネントからプロセスのメトリクスをエクスポートします。
  • SidekiqやRailsサーバなど、独自のメトリクスをエクスポートする他の様々なGitLabサービス。

Omnibus コンテナでのテスト

Prometheus ベースの Service Ping をテストするには、この方法をお勧めします。

変更を検証するには、CI/CDを使用してコードブランチから新しいOmnibusイメージをビルドし、イメージをダウンロードしてローカルコンテナインスタンスを実行します:

  1. マージリクエストからqa ステージを選択し、e2e:package-and-test ジョブをトリガーします。このジョブは、omnibus-gitlab-mirror プロジェクト](https://gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/-/pipelines)の[ダウンストリームパイプラインで Omnibus ビルドをトリガーします。
  2. ダウンストリームパイプラインでは、gitlab-docker ジョブの終了を待ちます。
  3. ジョブログを開き、バージョンを含む完全なコンテナ名を確認します。それは次の形式をとります:registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:<VERSION>.
  4. ローカルマシンで、GitLab Dockerレジストリにサインインしていることを確認します。この手順は、Authenticate to the GitLab Container Registryに記載されています。
  5. サインインしたら、新しいイメージをダウンロードします。docker pull registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:<VERSION>
  6. DockerでのOmnibus GitLabコンテナの操作と実行についての詳細は、GitLab Docker imagesdocumentationを参照してください。

GitLab開発ツールキットでのテスト

実際のGitLabのデプロイをエミュレートするときに多くの困難が伴うので、これはあまり推奨されないアプローチです。

GDKはPrometheusサーバーやnode_exporter 、他のGitLabコンポーネントと一緒に実行するようには設定されていません。もしそうしたいのであれば、Prometheusを使ってGDKをモニタリングするのが良いスタートです。

GCKはPrometheusベースのService Pingをテストするための限られたサポートしか持っていません。デフォルトでは、多くのコンポーネントをスクレイピングするように設定されたPrometheusサービスが付属しています。しかし、これには以下の制限があります:

  • それはgitlab-exporter インスタンスを実行しないので、Gitalyのようなサービスからのいくつかのprocess_* メトリクスが欠落している可能性があります。
  • node_exporter を実行する一方で、docker-compose サービスはホストをエミュレートします。つまり、通常、それ自身は実行中の他のどのサービスとも関連していないとレポーターします。これは、本番環境ではノードのメトリクスがどのようにレポートされるかということではありませんnode_exporter 。Service Pingでは、どのノード・データも、実行中のどのサービスにも関連していないように見えます。この問題を軽減 node_exporterするために、GCKの内部はweb サービスに任意に “割り当て “られ、このサービスnode_* メトリクスだけがService Pingに表示されるようになりました。

集約されたメトリクス

GitLab 13.6で導入されました

caution
この機能はGitLab内部での使用のみを目的としています。

集約メトリクス機能は、Service Ping メトリクスのコレクション内のデータ属性に関するインサイトを提供します。この集約により、複数のイベントで同じデータ属性が発生するたびにカウントすることなく、イベント内のデータ属性をカウントできます。例えば、新しいイシューの作成や新しいマージ・リクエストのオープンなど、複数のアクションを実行したユーザー数を集計できます。そして、これらのアクションの任意の組み合わせを実行した各ユーザをカウントできます。

メトリックYAML定義による集約メトリックの定義

サービスPingペイロードに集約メトリクスのデータを追加するには、Aggregated metric instrumentationガイドに従ってメトリクスYAML定義ファイルを作成します。

Redisソース集約メトリクス

GitLab 13.6で導入されました

Redis HLL Countersで収集したイベントの集約を宣言するには、time_frameall の値が含まれていないことを確認してください。これはRedisソースの集約メトリクスでは利用できません。

EEだけのイベントをすべてのGitLabエディションで発生したイベントと一緒に集計することは可能ですが、そうすることでEEとCEのGitLabインスタンスから収集したデータの間に大きなばらつきが生じる可能性があることを覚えておくことが重要です。

データベースソースで集計されたメトリクス

GitLab 13.9 で導入されました

データベースから収集したイベントに基づくメトリクスの集計を宣言するには、以下の手順に従ってください:

  1. 集約するメトリクスを永続化します。
  2. 新しい集約メトリクス定義を追加します。

集約のためのメトリクスの永続化

推定バッチ・カウンターを使用して計算されたメトリクスのみを、データベースから取得した集約メトリクスのために永続化できます。メトリックを永続化するには、estimate_batch_distinct_count メソッドに Ruby ブロックを注入します。このブロックは、Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll.save_aggregated_metrics メソッドを呼び出す必要があります。 メソッドは、estimate_batch_distinct_count の結果を保存して、将来的に集約メトリクスで使用できるようにします。

Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll.save_aggregated_metrics メソッドには以下の引数を指定します:

  • metric_name:集約に使用するメトリックの名前。Service Ping に追加されるメトリックのキーと同じでなければなりません。
  • recorded_at_timestamp:指定された Service Ping ペイロードが収集された瞬間を表すタイムスタンプ。recorded_at_timestamp 引数を埋めるには、次のような便利なメソッドrecorded_at を使用する必要があります:recorded_at_timestamp: recorded_at
  • time_period:estimate_batch_distinct_count に渡されるrelation 引数を構築するために使用される期間。利用可能なすべての履歴データでメトリクスを収集するには、nil の値を期間として設定します:time_period: nil
  • data:relation の一意のエントリを表す HyperLogLog バケツ構造。estimate_batch_distinct_count メソッドは常に正しい引数をブロックに渡すので、data 引数は常にブロックの引数と同じ値でなければなりません:data: result

メトリクスの永続化の例:

class UsageData
  def count_secure_pipelines(time_period)
    ...
    relation = ::Security::Scan.by_scan_types(scan_type).where(time_period)

    pipelines_with_secure_jobs['dependency_scanning_pipeline'] = estimate_batch_distinct_count(relation, :pipeline_id, batch_size: 1000, start: start_id, finish: finish_id) do |result|
      ::Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll
        .save_aggregated_metrics(metric_name: 'dependency_scanning_pipeline', recorded_at_timestamp: recorded_at, time_period: time_period, data: result)
    end
  end
end

新しい集約メトリクス定義の追加

すべてのメトリクスが永続化された後、Aggregated metric instrumentation ガイドに従って集約メトリクス定義を追加できます。Estimated Batch Countersで収集したメトリクスの集約を宣言するには、以下の要件を満たす必要があります:

  • events: 属性にリストされているメトリクス名は、前のステップでメトリクスを永続化する際にmetric_name 引数に渡したものと同じ名前を使用する必要があります。
  • events: 属性にリストされているすべてのメトリクスは、選択したtime_frame:ごとに永続化する必要があります。