-
새로운 고급 검색 마이그레이션 생성
- 스크립트를 사용하여
- 수동으로
- 건너뛴 마이그레이션
-
마이그레이션 헬퍼
Elastic::MigrationBackfillHelper
Elastic::MigrationUpdateMappingsHelper
Elastic::MigrationRemoveFieldsHelper
Elastic::MigrationObsolete
Elastic::MigrationCreateIndex
Search::Elastic::MigrationReindexBasedOnSchemaVersion
Search::Elastic::MigrationDeleteBasedOnSchemaVersion
Search::Elastic::MigrationDatabaseBackfillHelper
Elastic::MigrationHelper
Elastic::MigrationWorker
에서 지원하는 마이그레이션 옵션
- 마이그레이션 중 다운타임 피하기
- 마이그레이션 실행 시간 계산
- 고급 검색 마이그레이션을 위한 모범 사례
- 고급 검색 마이그레이션 정리
고급 검색 마이그레이션 스타일 가이드
새로운 고급 검색 마이그레이션 생성
스크립트를 사용하여
- GitLab 16.3에서 도입됨.
scripts/elastic-migration
를 실행하고 프롬프트에 따라 다음을 생성합니다:
- 마이그레이션을 정의하는 마이그레이션 파일:
ee/elastic/migrate/YYYYMMDDHHMMSS_migration_name.rb
- 마이그레이션을 테스트하는 스펙 파일:
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
# 중요한 사항: Elastic 인덱스 매핑에 대한 모든 업데이트는 해당
# 구성 파일에도 복제되어야 합니다:
# - `Elastic::Latest::Config`, 주 인덱스의 경우.
# - `Elastic::Latest::<Type>Config`, 독립형 인덱스의 경우.
def migrate
end
# 마이그레이션이 완료되었는지 확인
# 완료되면 true를 반환하고, 그렇지 않으면 false를 반환
def completed?
end
end
적용된 마이그레이션은 gitlab-#{RAILS_ENV}-migrations
인덱스에 저장됩니다. 실행되지 않은 모든 마이그레이션은 Elastic::MigrationWorker
크론 작업에 의해 순차적으로 적용됩니다.
Elastic 인덱스 매핑을 업데이트하려면, 해당 파일에 구성을 적용합니다:
- 주 인덱스의 경우:
Elastic::Latest::Config
. - 독립형 인덱스의 경우:
Elastic::Latest::<Type>Config
.
마이그레이션은 재시도 제한과 함께 구축할 수 있으며, 실패로 표시하고 중지된 것으로 마크할 수 있는 기능이 있습니다.
마이그레이션 재시도를 지원하는 데 필요한 데이터나 인덱스 정리는 마이그레이션 내에서 처리되어야 합니다.
건너뛴 마이그레이션
true
또는 false
로 평가되는 skip_if
proc를 추가하여 마이그레이션을 건너뛸 수 있습니다:
class MigrationName < Elastic::Migration
skip_if ->() { true|false }
조건이 false
일 때만 마이그레이션이 실행됩니다. 건너뛴 마이그레이션은 보류 중인 마이그레이션의 일부로 표시되지 않습니다.
건너뛴 마이그레이션은 구식으로 표시할 수 있지만, skip_if
조건은 유지되어야 하며 이 마이그레이션은 항상 건너뛰어야 합니다.
건너뛴 마이그레이션이 구식이 되면, 변경 사항을 적용하는 유일한 방법은 인덱스를 처음부터 다시 생성하는 것입니다.
건너뛴 마이그레이션의 문서 파일을 다음 속성으로 업데이트합니다:
skippable: true
skip_condition: '<description>'
마이그레이션 헬퍼
다음 마이그레이션 헬퍼는 ee/app/workers/concerns/elastic/
에서 사용할 수 있습니다:
Elastic::MigrationBackfillHelper
인덱스에서 특정 필드를 백필합니다. 대부분의 경우, 해당 필드에 대한 매핑이 이미 추가되어 있어야 합니다.
단일 필드를 백필하기 위해 field_name
메소드와 DOCUMENT_TYPE
상수가 필요합니다.
class MigrationName < Elastic::Migration
include Elastic::MigrationBackfillHelper
DOCUMENT_TYPE = Issue
private
def field_name
:schema_version
end
end
어떤 필드가 null인 경우 여러 필드를 백필하기 위해 field_names
메소드와 DOCUMENT_TYPE
상수가 필요합니다.
class MigrationName < Elastic::Migration
include Elastic::MigrationBackfillHelper
DOCUMENT_TYPE = Issue
private
def field_names
%w[schema_version visibility_level]
end
end
Elastic::MigrationUpdateMappingsHelper
지정된 매핑으로 put_mapping
을 호출하여 인덱스의 매핑을 업데이트합니다.
new_mappings
메소드와 DOCUMENT_TYPE
상수가 필요합니다.
class MigrationName < Elastic::Migration
include Elastic::MigrationUpdateMappingsHelper
DOCUMENT_TYPE = Issue
private
def new_mappings
{
schema_version: {
type: 'short'
}
}
end
end
Elastic::MigrationRemoveFieldsHelper
지정된 필드를 인덱스에서 제거합니다.
index_name
, document_type
메소드가 필요합니다. 제거할 필드가 하나이면 field_to_remove
메소드를 추가하고, 그렇지 않으면 필드 배열로 fields_to_remove
를 추가합니다.
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
건너뛰기 가능한 마이그레이션을 구식으로 표시할 때는 skip_if
조건을 유지해야 합니다.
Elastic::MigrationCreateIndex
새 인덱스를 생성합니다.
필요한 것:
-
target_class
와document_type
메소드 - 클래스에 대한 매핑 및 인덱스 설정
경고: 동일한 마일스톤에서 인덱스를 채우기 위해 후속 마이그레이션을 수행해야 합니다.
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
Search::Elastic::MigrationDeleteBasedOnSchemaVersion
지정된 문서 유형을 저장하고 주어진 값보다 schema_version
이 작은 인덱스의 모든 문서를 삭제합니다.
DOCUMENT_TYPE
상수와 schema_version
메서드가 필요합니다.
인덱스 매핑에는 YYMM
형식의 schema_version
정수 필드가 있어야 합니다.
class MigrationName < Elastic::Migration
include ::Search::Elastic::MigrationDeleteBasedOnSchemaVersion
DOCUMENT_TYPE = Issue
batch_size 10_000
batched!
throttle_delay 1.minute
retry_on_failure
def schema_version
23_12
end
end
Search::Elastic::MigrationDatabaseBackfillHelper
limited_indexing
설정을 준수하여 데이터베이스의 모든 문서를 엘라스틱 검색 인덱스로 재색인합니다.
DOCUMENT_TYPE
상수와 respect_limited_indexing?
메서드가 필요합니다.
class MigrationName < Elastic::Migration
include ::Search::Elastic::MigrationDatabaseBackfillHelper
batch_size 10_000
batched!
throttle_delay 1.minute
retry_on_failure
DOCUMENT_TYPE = Issue
def respect_limited_indexing?
true
end
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
크론 워커가 실행되는 빈도인 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
# 배치로 실행될 마이그레이션 선언
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::MigrationUpdateMappingsHelper
를 사용하는 마이그레이션이Elastic::MigrationBackfillHelper
를 사용하는 마이그레이션보다 먼저 실행되도록 합니다. 이렇게 하면 모든 마이그레이션이 적용되지 않은 경우 같은 문서를 여러 번 재색인하는 것을 피하고 다시 채우는 시간도 줄입니다. -
배치로 작업할 때, 배치 크기를 9,000 문서 이하로 유지합니다.
대량 인덱서가 매 분마다 실행되도록 설정되어 있으며, 10,000 문서의 배치를 처리합니다. 이렇게 하면 대량 인덱서가 다른 마이그레이션 배치를 시도하기 전에 레코드를 처리할 시간이 생깁니다.
-
문서 수가 최신 상태인지 확인하기 위해 마이그레이션이 완료되었는지 확인하기 전에 인덱스를 새로 고쳐야 합니다.
-
마이그레이션이 시작될 때, 완료 확인이 발생할 때, 그리고 마이그레이션이 완료되었을 때 각 마이그레이션에 로깅 문장을 추가합니다. 이러한 로그는 마이그레이션 문제를 디버깅하는 데 유용합니다.
-
Elasticsearch 재인덱스 API 작업을 사용하는 경우 인덱싱을 일시 중지합니다.
-
마이그레이션이 실패할 가능성이 있는 경우 재시도 한계를 추가하는 것을 고려합니다. 이는 문제가 발생할 경우 마이그레이션을 중단할 수 있도록 보장합니다.
고급 검색 마이그레이션 정리
고급 검색 마이그레이션은 일반적으로 오랜 기간 동안 여러 코드 경로를 지원해야 하므로, 안전하게 청소할 수 있을 때 이를 정리하는 것이 중요합니다.
우리는 GitLab 필수 중지를 사용하여, 완전히 마이그레이션되지 않은 인덱스에 대한 하위 호환성을 제거하는 안전한 시점으로 선택합니다. 우리는 이를 업그레이드 문서에 기록합니다.
GitLab Housekeeper는 청소 프로세스를 자동화하는 데 사용됩니다. 이 프로세스에는 기존 마이그레이션을 쓸모없게 표시하고 쓸모없는 마이그레이션을 삭제하는 것이 포함됩니다. 마이그레이션이 쓸모없게 표시되면, 마이그레이션 코드는 쓸모없는 마이그레이션 코드로 대체되고 테스트는 쓸모없는 마이그레이션 공유 예제로 대체됩니다. 그래서:
-
우리는 고급 검색 마이그레이션에서 호출되는 코드를 유지할 필요가 없습니다.
-
더 이상 지원하지 않는 마이그레이션에 대해 테스트를 실행하는 데 CI 시간을 낭비하지 않습니다.
-
이 마이그레이션을 실행하지 않고 대상 버전으로 직접 업그레이드하는 운영자는 최종 사용자에게 처음부터 다시 인덱싱하라는 메시지를 받습니다.
안을 더 안전하게 하기 위해, 우리는 마지막 필수 중지 이전의 마지막 소규모 버전에서 생성된 마이그레이션을 정리하지 않습니다. 예를 들어, 마지막 필수 중지가 %14.0
인 경우 %13.12
에서만 추가된 마이그레이션을 정리해서는 안 됩니다. 이 추가 안전망은 GitLab.com에서 여러 주가 걸릴 수 있는 마이그레이션을 허용합니다. GitLab.com에 대한 배포는 자동화되어 있으며 이 청소를 방지할 자동화된 검사가 없기 때문에 추가 예방 조치가 필요합니다.
또한, 만약 우리가 자동화된 검사가 있었다고 하더라도, 우리는 고급 검색 마이그레이션에 대한 GitLab.com 배포를 실제로 막고 싶지 않습니다. 이는 여전히 일주일이 더 필요할 수 있으며, 배포를 차단하기에는 너무 긴 시간입니다.
마이그레이션을 쓸모없게 만드는 프로세스
마이그레이션을 쓸모없게 표시하기 위해 Keeps::MarkOldAdvancedSearchMigrationsAsObsolete
Keep을 수동으로 실행합니다.
마지막 필수 중지 이전의 두 버전 전에 생성된 각 마이그레이션에 대해, Keep은 다음을 수행합니다:
-
마이그레이션의 내용을 유지하고 아래에 prepend를 추가합니다:
ClassName.prepend ::Elastic::MigrationObsolete
-
스펙 파일의 내용을
'a deprecated Advanced Search migration'
공유 예제로 대체합니다. -
Global Search 백엔드 엔지니어를 무작위로 할당합니다.
-
마이그레이션을 쓸모없게 표시하기 위해 사전 파일을 업데이트합니다.
MR 할당자는:
-
사전 파일에
marked_obsolete_by_url
및marked_obsolete_in_milestone
이 올바르게 명시되어 있는지 확인합니다. -
.rubocop_todo/
디렉토리에 마이그레이션 또는 스펙 파일에 대한 참조가 존재하지 않는지 검증합니다. -
Elastic::DataMigrationService.migration_has_finished?(:migration_name_in_lowercase)
를 찾아서 이 마이그레이션에 대한 하위 호환성을 처리하는 모든 논리를 제거합니다. -
병합 요청에 필요한 변경 사항을 푸시합니다.
쓸모없는 마이그레이션을 제거하는 프로세스
Keeps::DeleteObsoleteAdvancedSearchMigrations
Keep을 수동으로 실행하여 쓸모없는 마이그레이션과 스펙을 제거합니다. Keep은 가장 최근의 쓸모없는 마이그레이션을 제외한 모든 것을 제거합니다.
-
마지막 필수 중지 이전에 쓸모없게 표시된 쓸모없는 마이그레이션을 선택합니다.
-
첫 번째 단계에서 모든 쓸모없는 마이그레이션이 포함되면, 적용되지 않은 마이그레이션이 있는 고객을 위해 하나의 쓸모없는 마이그레이션을 보존합니다.
-
해당 마이그레이션에 대한 마이그레이션 파일과 스펙 파일을 삭제합니다.
-
병합 요청을 생성하고 Global Search 팀원에게 할당합니다.
MR 할당자는:
-
기본 브랜치에서 마이그레이션 묘지로 마이그레이션을 백업합니다.
-
.rubocop_todo/
디렉토리에 마이그레이션 또는 스펙 파일에 대한 참조가 존재하지 않는지 확인합니다. -
병합 요청에 필요한 변경 사항을 푸시합니다.