- 高度な検索マイグレーションの新規作成
- マイグレーションにおけるダウンタイムの回避
- マイグレーション実行時間の計算
- 高度な検索マイグレーションのベストプラクティス
- メジャーバージョンアップにおける高度な検索マイグレーションの削除
高度な検索マイグレーションスタイルガイド
高度な検索マイグレーションの新規作成
スクリプト
GitLab 16.3 で導入されました。
scripts/elastic-migration
を実行し、プロンプトに従って作成してください:
- マイグレーションを定義するマイグレーションファイル:
ee/elastic/migrate/YYYYMMDDHHMMSS_migration_name.rb
- マイグレーションをテストするための spec ファイル:
ee/spec/elastic/migrate/YYYYMMDDHHMMSS_migration_name_spec.rb
- マイグレーションを識別するための辞書ファイル:
ee/elastic/docs/YYYYMMDDHHMMSS_migration_name.yml
手動
GitLab 13.6で導入されました。
ee/elastic/migrate/
フォルダに、YYYYMMDDHHMMSS_migration_name.rb
というファイル名で新しいファイルを作成します。この形式はRailsデータベースのマイグレーションでも同じです。
# frozen_string_literal: true
class MigrationName < Elastic::Migration
# Important: Any updates to the Elastic index mappings must be replicated in the respective
# configuration files:
# - `Elastic::Latest::Config`, for the main index.
# - `Elastic::Latest::<Type>Config`, for standalone indices.
def migrate
end
# Check if the migration has completed
# Return true if completed, otherwise return false
def completed?
end
end
適用されたマイグレーションはgitlab-#{RAILS_ENV}-migrations
インデックスに保存されます。実行されなかったマイグレーションはすべて、Elastic::MigrationWorker
cronワーカーによって順次適用されます。
Elasticインデックスのマッピングを更新するには、それぞれのファイルに設定を適用します:
- メインインデックスには
Elastic::Latest::Config
. - スタンドアロン・インデックスの場合:
Elastic::Latest::<Type>Config
.
マイグレーションは再試行回数を制限して構築することができ、失敗して停止とマークすることができます。マイグレーションの再試行をサポートするために必要なデータやインデックスのクリーンアップは、マイグレーション内で処理する必要があります。
マイグレーションヘルパー
ee/app/workers/concerns/elastic/
では、以下のマイグレーションヘルパーが利用可能です:
Elastic::MigrationBackfillHelper
インデックス内の特定のフィールドを埋め戻します。ほとんどの場合、そのフィールドのマッピングはすでに追加されているはずです。
単一のフィールドを埋め戻すにはindex_name
およびfield_name
メソッドが必要です。
class MigrationName < Elastic::Migration
include Elastic::MigrationBackfillHelper
private
def index_name
Issue.__elasticsearch__.index_name
end
def field_name
:schema_version
end
end
いずれかのフィールドが NULL の場合に複数のフィールドを埋め戻すには、index_name
およびfield_names
メソッドが必要です。
class MigrationName < Elastic::Migration
include Elastic::MigrationBackfillHelper
private
def index_name
Issue.__elasticsearch__.index_name
end
def field_names
%w[schema_version visibility_level]
end
end
Elastic::MigrationUpdateMappingsHelper
マッピングを指定してput_mapping
を呼び出すことで、インデックス内のマッピングを更新します。
index_name
およびnew_mappings
メソッドが必要です。
class MigrationName < Elastic::Migration
include Elastic::MigrationUpdateMappingsHelper
private
def index_name
Issue.__elasticsearch__.index_name
end
def new_mappings
{
schema_version: {
type: 'short'
}
}
end
end
Elastic::MigrationRemoveFieldsHelper
インデックスから指定したフィールドを削除します。
index_name
,document_type
メソッドが必要です。削除するフィールドが 1 つの場合はfield_to_remove
メソッドを追加し、そうでない場合はフィールドの配列を指定してfields_to_remove
を追加します。
document_type
にマッチするドキュメントが Elasticsearch で指定されたフィールドを持っているかバッチでチェックします。ドキュメントが存在する場合は、Painlessスクリプトを使ってupdate_by_query
を実行します。
class MigrationName < Elastic::Migration
include Elastic::MigrationRemoveFieldsHelper
batched!
throttle_delay 1.minute
private
def index_name
User.__elasticsearch__.index_name
end
def document_type
'user'
end
def fields_to_remove
%w[two_factor_enabled has_projects]
end
end
デフォルトのバッチサイズは10_000
です。この値をオーバーライドするにはBATCH_SIZE
を指定します:
class MigrationName < Elastic::Migration
include Elastic::MigrationRemoveFieldsHelper
batched!
BATCH_SIZE = 100
...
end
Elastic::MigrationObsolete
マイグレーションが不要になった場合に、そのマイグレーションを廃止済みとしてマークします。
class MigrationName < Elastic::Migration
include Elastic::MigrationObsolete
end
Elastic::MigrationCreateIndex
新しいインデックスを作成します。
必要です:
-
target_class
およびdocument_type
メソッド。 -
ee/lib/elastic/latest/
のクラスのマッピングとインデックスの設定。ee/lib/elastic/v12p1/
class MigrationName < Elastic::Migration
include Elastic::MigrationCreateIndex
retry_on_failure
def document_type
:epic
end
def target_class
Epic
end
end
Search::Elastic::MigrationReindexBasedOnSchemaVersion
指定 さ れた文書種別が格納 さ れてい る イ ンデ ッ ク ス内のすべての文書の イ ンデ ッ ク ス を再作成 し 、schema_version
を更新 し ます。
DOCUMENT_TYPE
とNEW_SCHEMA_VERSION
定数が必要です。インデックスマッピングはYYMM
形式のschema_version
整数フィールドを持たなければなりません。
class MigrationName < Elastic::Migration
include Search::Elastic::MigrationReindexBasedOnSchemaVersion
batched!
batch_size 9_000
throttle_delay 1.minute
DOCUMENT_TYPE = WorkItem
NEW_SCHEMA_VERSION = 23_08
UPDATE_BATCH_SIZE = 100
end
Elastic::MigrationHelper
マイグレーションがこれまでの例に当てはまらない場合に使用できるメソッドがコンテナに含まれています。
class MigrationName < Elastic::Migration
include Elastic::MigrationHelper
def migrate
...
end
def completed?
...
end
end
がサポートするマイグレーションオプションです。Elastic::MigrationWorker
Elastic::MigrationWorker
は以下のマイグレーションオプションをサポートしています:
-
batched!
- マイグレーションをバッチで実行できるようにします。設定された場合、Elastic::MigrationWorker
は、後述するthrottle_delay
オプションで設定される遅延を伴ってそれ自身を再エンキューします。バッチ処理はmigrate
メソッドで処理する必要があります。この設定は再エンキューのみを制御します。 -
batch_size
-batched!
マイグレーション実行中に変更される文書の数を設定します。こ のサ イ ズ は、 更新が完了す る ま でに充分な時間を と る こ と がで き る 値に設定す る 必要があ り ます。こ れは後述のthrottle_delay
オプシ ョ ン と 組み合わせて調整する こ と がで き ます。バ ッ チ処理は、 カ ス タ ムのmigrate
メ ソ ッ ド か、 ま たは こ の設定を用い るElastic::MigrationBackfillHelper
migrate
メ ソ ッ ド で行 う 必要があ り ます。デフ ォル ト 値は 1000 文書です。 -
throttle_delay
- 待ち時間 バッチ実行間の待ち時間を設定します。こ の時間は、 各マ イ グ リ バ ッ チが完了す る に十分な時間を与え る ために、 十分に長 く 設定す る 必要があ り ます。さらに、この時間はElastic::MigrationWorker
cronワーカーが実行する頻度であるため、5分未満であるべきです。デフォルト値は3分です。 -
pause_indexing!
- マイグレーション実行中はインデックス作成を一時停止します。この設定はマイグレーションが実行される前にインデックス設定を記録し、マイグレーションが完了したときにその値に戻します。 -
space_requirements!
- マイグレーション実行時にクラスターに十分な空き領域があることを確認します。この設定は、マイグレーション実行時に必要なストレージが利用できない場合にマイグレーションを停止します。マイグレーションでは、space_required_bytes
メソッドを定義して、必要な容量をバイト単位で提供する必要があります。 -
retry_on_failure
- 失敗時の再試行機能を有効にします。デフォルトでは、マイグレーションは30回再試行されます。リトライ回数がなくなると、マイグレーションは中止されたとマークされます。再試行回数をカスタマイズするには、max_attempts
引数を渡します:retry_on_failure max_attempts: 10
# frozen_string_literal: true
class BatchedMigrationName < Elastic::Migration
# Declares a migration should be run in batches
batched!
throttle_delay 10.minutes
pause_indexing!
space_requirements!
retry_on_failure
# ...
end
マイグレーションにおけるダウンタイムの回避
マイグレーションの取り消し
GitLab.comでマイグレーションが失敗したり停止したりした場合、私たちはマイグレーションを導入した変更を元に戻すことを好みます。こうすることで、セルフマネジメントの顧客が壊れたマイグレーションを受け取ることを防ぎ、バックポートの必要性を減らすことができます。
マージするタイミング
リリースから1週間以内にはマイグレーションをマージしないことを推奨します。これにより、マイグレーションが失敗したり、期待通りに動作しなかったりした場合に、マイグレーションを差し戻す時間を確保できます。リリースの最終週にまだ開発中またはレビュー中のマイグレーションは、次のマイルストーンにプッシュしてください。
複数バージョンの互換性
高度な検索のマイグレーションは、他のGitLabの変更と同様に、複数のバージョンのアプリケーションが同時に稼働している場合をサポートする必要があります。
デプロイの順序によっては、マイグレーションが開始または終了しても、マイグレーション前のアプリケーションコードを実行しているサーバーが残っている可能性があります。すべての高度な検索マイグレーションがデプロイ終了後に開始されるようになるまでは、このことを考慮する必要があります。
リスクの高いマイグレーション
Elasticsearchはトランザクションをサポートしていないため、マイグレーションを開始した後や終了した後にアプリケーションコードが差し戻される事態を想定してマイグレーションを設計する必要があります。
このような理由から、通常、破壊的なアクション(例えば、データを移動した後の削除など)はマイグレーションが正常に完了した後のマージリクエストに延期します。安全のため、自主管理されているお客様については、重要なデータ損失のリスクがある場合は、別のリリースに延期することも必要です。
マイグレーション実行時間の計算
GitLab.comでのマイグレーションの実行にかかる時間を理解することは重要です。マイグレーションによって処理されるドキュメントの数を導き出します。この数は、データベースや既存のElasticsearchインデックスへのクエリから得られるかもしれません。実行時間の計算には以下の式を使います:
> batch_size = 9_000
=> 9000
> throttle_delay = 1.minute
=> 1 minute
> number_of_documents = 15_536_906
=> 15536906
> (number_of_documents / batch_size) * throttle_delay
=> 1726 minutes
> (number_of_documents / batch_size) * throttle_delay / 1.hour
=> 28
高度な検索マイグレーションのベストプラクティス
最良の結果を得るために、以下のベストプラクティスに従ってください:
-
Elastic::MigrationBackfillHelper
を使用するマイグレーションの前に、Elastic::MigrationUpdateMappingsHelper
を使用するマイグレーションが実行されるように、ドキュメントタイプごとにすべてのマイグレーションを順序付けます。これにより、すべてのマイグレーションが未適用の場合に同じドキュメントのインデックスを何度も再作成することを回避し、バックフィル時間を短縮します。 - バ ッ チで作業す る 場合は、 バ ッ チサ イ ズ を 9,000 文書以下に保ち ます。バルクインデクサーは毎分実行し、10,000 文書のバッチを処理するように設定します。こうすることで、別のマイグレーションバッチが試行される前に、バルクインデクサーはレコードを処理する時間があります。
- 文書数が最新であることを確認するために、マイグレーションが完了したかどうかを確認する前にインデックスを更新する必要があります。
- マイグレーションが開始したとき、完了チェックが発生したとき、そしてマイグレーションが完了したときに、それぞれのマイグレーションにログステートメントを追加します。これらのログはマイグレーションのイシューをデバッグするときに役立ちます。
- Elasticsearch Reindex APIオペレーションを使用している場合は、インデックス作成を一時停止してください。
- マイグレーションが失敗する可能性がある場合は、リトライ制限を追加することを検討してください。これにより、イシューが発生した場合にマイグレーションを停止できるようになります。
メジャーバージョンアップにおける高度な検索マイグレーションの削除
高度な検索マイグレーションは通常、長期間にわたって複数のコードパスをサポートする必要があるため、安全にできるときにそれらをクリーンアップすることが重要です。
GitLab のメジャーバージョンアップグレードは、完全にはマイグレーションされていないインデックスの後方互換性を削除する安全なタイミングとして選択します。このことは、アップグレードのドキュメントで説明しています。また、マイグレーションコードを停止したマイグレーションに置き換え、テストを削除することにしました:
- 高度な検索マイグレーションから呼び出されるコードをメンテナーする必要はありません。
- もうサポートしないマイグレーションのテストを実行するために CI の時間を浪費することもありません。
- このマイグレーションを実行しておらず、ターゲットバージョンに直接アップグレードするオペレーションには、インデックスをゼロから再作成するよう促すメッセージが表示されます。
念のため、メジャーアップグレード前の最後のマイナーバージョンで作成されたマイグレーションは削除しません。ですから、%14.0
にアップグレードする場合は、%13.12
で追加されたマイグレーションを削除してはいけません。このようなセーフティネットがあることで、GitLab.comでのマイグレーションが完了するまでに何週間もかかるような場合にも対応することができます。%13.12
のマイグレーションが完了する前に GitLab.com を%14.0
にアップグレードしてしまったら大変です。GitLab.comへのデプロイは自動化されており、これを防ぐための自動チェックもありません。さらに、仮にこれを防ぐための自動チェックがあったとしても、高度な検索のマイグレーションで GitLab.com のデプロイを止めたいとは思いません。
マイグレーションを削除する手順
アップグレード先のメジャーバージョンより2つ前のマイナーバージョンで作成されたすべてのマイグレーションについて、以下の処理を行います:
- GitLab.com へのマイグレーションが正常に完了したことを確認します。
-
マイグレーションの内容を置き換えます:
include Elastic::MigrationObsolete
- このマイグレーションをサポートする仕様ファイルをすべて削除してください。
- このマイグレーションの後方互換性を処理するロジックを削除してください。このロジックは
Elastic::DataMigrationService.migration_has_finished?(:migration_name_in_lowercase)
で見つけることができます。 - これらの変更でマージリクエストを作成してください。メジャーリリースが開始される前に誤ってマージしないように注意してください。