마이그레이션 중단시간 방지

데이터베이스 작업 시 특정 작업은 중단시간이 필요할 수 있습니다. 마이그레이션 중단 시간을 피해야 하므로 중단 없이 동일한 결과를 얻을 수 있는 단계 세트를 사용해야 합니다. 본 안내서에서는 중단이 필요해 보일 수 있는 여러 작업, 그 영향 및 중단 없이 수행하는 방법에 대해 설명합니다.

컬럼 삭제

컬럼 제거는 복잡한 작업입니다. 왜냐하면 실행 중인 GitLab 프로세스는 이러한 컬럼이 존재할 것으로 예상하며, 컬럼이 참조되지 않더라도 ActiveRecord는 테이블 스키마를 캐시합니다. 이는 컬럼이 명시적으로 무시되지 않는 이상 발생합니다. 이를 안전하게 우회하기 위해, 3가지 단계를 3개의 릴리스로 나누어야 합니다.

  1. 컬럼 무시 (릴리스 M)
  2. 컬럼 제거 (릴리스 M+1)
  3. 무시 규칙 제거 (릴리스 M+2)

컬럼을 세 릴리스에 걸쳐 변경하는 이유는 컬럼 제거가 쉽게 롤백되지 않는 파괴적인 작업이기 때문입니다.

이 절차를 따르면 GitLab.com에 대한 배포 또는 GitLab이 Self-managed하는 설치의 업그레이드 프로세스에서 이러한 단계를 묶어서 실행하지 않도록 할 수 있습니다.

컬럼 무시 (릴리스 M)

첫 번째 단계는 애플리케이션 코드에서 컬럼을 무시하고 모델 유효성 확인을 포함하여 해당 컬럼에 대한 모든 코드 참조를 제거하는 것입니다. 이 단계는 Rails가 컬럼을 캐시하고 다양한 곳에서 이 캐시를 재사용하기 때문에 필요합니다. 컬럼 무시는 컬럼을 무시하도록 정의하여 수행할 수 있습니다. 예를 들어, 릴리스 12.5에서 User 모델에서 updated_at을 무시하려면 다음과 같이 사용합니다:

class User < ApplicationRecord
  include IgnorableColumns
  ignore_column :updated_at, remove_with: '12.7', remove_after: '2019-12-22'
end

여러 컬럼을 무시할 수도 있습니다:

ignore_columns %i[updated_at created_at], remove_with: '12.7', remove_after: '2019-12-22'

모델이 CE와 EE에 모두 존재하는 경우, 컬럼은 CE 모델에서 무시해야 합니다. 모델이 EE에만 존재하는 경우 EE에 추가해야 합니다.

컬럼을 제거할 수 있는 안전한 시기를 표시해야 합니다:

  • remove_with: 일반적으로 두 릴리스(M+2)(12.7가 예시로 들 수 있음) 뒤에 설정하여 컬럼 무시를 추가한 후 컬럼 무시를 제거할 수 있는 시기를 표시합니다.
  • remove_after: 컬럼 무시를 제거할 수 있는 시기를 나타내는데, 일반적으로 M+1 릴리스 날짜 이후, M+2 개발 주기 동안에 나타냅니다. 예를 들어, 12.7의 개발 주기가 2019-12-18부터 2020-01-17이고 12.6컬럼 제거의 릴리스일 때, 2019-12-2212.6 릴리스 날짜로 설정하는 것이 안전합니다.

이 정보를 통해 컬럼 무시에 대해 더 나은 이해를 할 수 있으며, 정기적인 릴리스와 GitLab.com에 대한 배포 양쪽에서 컬럼 무시를 너무 이른 시기에 제거하지 않도록 할 수 있습니다. 예를 들어, 컬럼을 무시하는 변경 사항과 이어서 컬럼 무시를 제거하는 변경 사항을 함께 배포하는 상황(여기에는 중단 시간이 발생합니다)을 피할 수 있습니다.

이 예에서 컬럼을 무시하는 변경은 릴리스 12.5에 들어갔습니다.

컬럼 제거 (릴리스 M+1)

이어지는 예시를 계속하면, 컬럼 제거는 릴리스 12.6포스트-배포 마이그레이션에 들어갑니다:

먼저 포스트-배포 마이그레이션을 생성하세요:

bundle exec rails g post_deployment_migration remove_users_updated_at_column

컬럼을 제거하는 마이그레이션을 작성할 때 다음 시나리오를 고려해야 합니다:

제거된 컬럼에 인덱스 또는 제약 조건이 없는 경우

이 경우, 트랜잭션 마이그레이션을 사용할 수 있습니다:

class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.1]
  def up
    remove_column :users, :updated_at
  end
  
  def down
    add_column :users, :updated_at, :datetime
  end
end

제거된 컬럼에 인덱스 또는 제약 조건이 있는 경우

만약 down 메서드가 삭제된 인덱스나 제약 조건을 다시 추가해야 한다면, 그것은 트랜잭션 마이그레이션에서는 수행할 수 없습니다. 마이그레이션은 다음과 같을 것입니다:

class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.1]
  disable_ddl_transaction!
  
  def up
    remove_column :users, :updated_at
  end
  
  def down
    unless column_exists?(:users, :updated_at)
      add_column :users, :updated_at, :datetime
    end
    
    # 반드시 추가된 인덱스나 제약 조건을 다시 추가하십시오.
    # 이 예시에서는 다음과 같습니다:
    add_concurrent_index(:users, :updated_at)
  end
end

down 메서드에서 마이그레이션이 실행 중일 때 실패할 수 있으므로 해당 컬럼이 이미 존재하는지 확인합니다.

disable_ddl_transaction!는 전체 마이그레이션을 감싸는 트랜잭션을 비활성화하는 데 사용됩니다.

더 많은 정보를 원하시면 마이그레이션 스타일 가이드 페이지를 참조하십시오.

무시 규칙 제거 (릴리스 M+2)

다음 릴리스인 이 예시에서는 12.7에 대한 다른 Merge Request를 설정하여 무시 규칙을 제거합니다. 이로써 ignore_column 라인과(만약 더 이상 필요하지 않다면) IgnoreableColumns의 포함도 제거합니다.

이것은 remove_with로 표시된 릴리스에서만 Merge되어야 하며, remove_after 날짜가 지난 후에 Merge되어야 합니다.

컬럼 이름 변경

일반적인 방법으로 컬럼 이름을 변경하는 것은 애플리케이션이 데이터베이스 마이그레이션 중이거나 이후에도 이전 컬럼 이름을 계속 사용할 수 있기 때문에 중단시간이 필요합니다. 중단시간이 필요없이 컬럼 이름을 변경하려면, 두 개의 마이그레이션이 필요합니다: 일반 마이그레이션과 포스트-배포 마이그레이션. 이러한 두 가지 마이그레이션은 동일한 릴리스에 들어갈 수 있습니다. 단계:

  1. 일반 마이그레이션 추가 (릴리스 M)
  2. 컬럼 무시 (릴리스 M)
  3. 포스트-배포 마이그레이션 추가 (릴리스 M)
  4. 무시 규칙 제거 (릴리스 M+1)
note
기본 값을 가진 컬럼의 이름을 변경하는 것은 불가능합니다. 자세한 내용은 이 Merge Request를 참조하십시오.

일반 마이그레이션 추가하기 (릴리스 M)

먼저 일반 마이그레이션을 생성해야 합니다. 이 마이그레이션은 Gitlab::Database::MigrationHelpers#rename_column_concurrently를 사용하여 이름을 변경해야 합니다. 예를 들면 다음과 같습니다.

# db/migrate에 있는 일반 마이그레이션
class RenameUsersUpdatedAtToUpdatedAtTimestamp < Gitlab::Database::Migration[2.1]
  disable_ddl_transaction!
  
  def up
    rename_column_concurrently :users, :updated_at, :updated_at_timestamp
  end
  
  def down
    undo_rename_column_concurrently :users, :updated_at, :updated_at_timestamp
  end
end

이를 통해 열 이름을 변경하고 데이터가 동기화되도록 보장하며 인덱스와 외래 키도 복사합니다.

열에 하나 이상의 인덱스가 포함되어 있어 이 인덱스의 이름이 원래 열의 이름을 포함하지 않으면 이전에 설명한 절차가 실패합니다. 이 경우 이러한 인덱스의 이름도 변경해야 합니다.

열 무시하기 (릴리스 M)

다음 단계는 애플리케이션 코드에서 열을 무시하고 사용되지 않도록 만드는 것입니다. Rails는 열을 캐시하고 다양한 곳에서 이 캐시를 재사용하기 때문에 이 단계가 필요합니다. 이 단계는 열이 삭제될 때의 첫 번째 단계와 유사하며 동일한 요구사항이 적용됩니다.

class User < ApplicationRecord
  include IgnorableColumns
  ignore_column :updated_at, remove_with: '12.7', remove_after: '2019-12-22'
end

사후 배포 마이그레이션 추가하기 (릴리스 M)

이름 변경 절차에는 사후 배포 마이그레이션에서 정리가 필요합니다. 이 정리를 Gitlab::Database::MigrationHelpers#cleanup_concurrent_column_rename를 사용하여 수행할 수 있습니다.

# db/post_migrate에 있는 사후 배포 마이그레이션
class CleanupUsersUpdatedAtRename < Gitlab::Database::Migration[2.1]
  disable_ddl_transaction!
  
  def up
    cleanup_concurrent_column_rename :users, :updated_at, :updated_at_timestamp
  end
  
  def down
    undo_cleanup_concurrent_column_rename :users, :updated_at, :updated_at_timestamp
  end
end

대규모 테이블을 이름을 변경하는 경우, 첫 번째 마이그레이션이 실행되었지만 두 번째 정리 마이그레이션이 아직 실행되지 않은 상태에서 시스템 상태를 주의깊게 고려하세요. Canary를 사용하면 시스템이 상당한 시간 동안이 상태로 실행될 수 있습니다.

무시 규칙 제거하기 (릴리스 M+1)

열이 삭제될 때와 마찬가지로 이름 변경이 완료된 후, 다음 릴리스에서 무시 규칙을 제거해야 합니다.

열 제약 조건 변경하기

NOT NULL 절을 추가하거나 제거하는 것은 일반적으로 다운타임 없이 수행할 수 있습니다. 그러나 이는 애플리케이션 변경이 먼저 배포되어야 한다는 것을 의미합니다. 따라서 열 제약 조건을 변경하는 것은 사후 배포 마이그레이션에서 수행되어야 합니다.

이러한 행위는 전체 열 타입을 다시 정의하기 때문에 비효율적인 쿼리를 생성하는 change_column을 피해야 합니다.

다음 특정 사용 사례에 대한 가이드를 확인할 수 있습니다:

열 타입 변경하기

열의 유형을 변경하는 것은 Gitlab::Database::MigrationHelpers#change_column_type_concurrently를 사용하여 수행할 수 있습니다. 이 방법은 rename_column_concurrently와 유사하게 작동합니다. 예를 들어, users.username의 유형을 string에서 text로 변경하려면:

  1. 일반 마이그레이션 생성하기
  2. 사후 배포 마이그레이션 생성하기
  3. 새 유형으로 데이터 캐스팅하기

일반 마이그레이션 생성하기

일반 마이그레이션은 새로운 이름을 지닌 임시 열을 생성하고 데이터를 동기화하기 위해 트리거를 설정하는 데 사용됩니다. 이러한 마이그레이션은 다음과 같이 보일 수 있습니다.

# db/migrate에 있는 일반 마이그레이션
class ChangeUsersUsernameStringToText < Gitlab::Database::Migration[2.1]
  disable_ddl_transaction!
  
  def up
    change_column_type_concurrently :users, :username, :text
  end
  
  def down
    undo_change_column_type_concurrently :users, :username
  end
end

사후 배포 마이그레이션 생성하기

다음으로, 사후 배포 마이그레이션을 사용하여 변경 사항을 정리해야 합니다.

# db/post_migrate에 있는 사후 배포 마이그레이션
class ChangeUsersUsernameStringToTextCleanup < Gitlab::Database::Migration[2.1]
  disable_ddl_transaction!
  
  def up
    cleanup_concurrent_column_type_change :users, :username
  end
  
  def down
    undo_cleanup_concurrent_column_type_change :users, :username, :string
  end
end

이로써 작업이 완료되었습니다!

데이터를 새 유형으로 캐스팅하기

특정 유형 변경에는 데이터를 새 유형으로 캐스팅해야 할 수 있습니다. 예를 들어 text에서 jsonb로 변경할 때입니다. 이 경우 type_cast_function 옵션을 사용합니다. 나쁜 데이터가 없고 캐스트가 항상 성공한다는 것을 확인하세요. 또한 캐스트 오류를 처리하는 사용자 정의 함수를 제공할 수도 있습니다.

예시 마이그레이션:

  def up
    change_column_type_concurrently :users, :settings, :jsonb, type_cast_function: 'jsonb'
  end

열 기본값 변경하기

열 기본값을 변경하는 것은 Rails가 기본값과 같은 값을 명시적으로 INSERT 쿼리에 지정할 때 데이터베이스에 태스크를 넘기는 방식 때문에 어렵습니다.

note
Rails는 데이터베이스 마이그레이션에서 열의 기본값을 PostgreSQL에 보내지 않습니다. 이 작업은 데이터베이스에 남깁니다. 마이그레이션이 열의 기본값을 변경하면 실행 중인 애플리케이션이 스키마 캐시 때문에 이 변경 사항을 인식하지 못합니다. 특히 데이터베이스 마이그레이션을 실행한 후 코드의 새 버전을 배포하는 경우 오래된 데이터가 실수로 데이터베이스에 잘못 기록되는 위험이 있습니다.

이러한 이유로 코드 실행이 특정 열의 이전 기본값을 명시적으로 기록할 경우, Rails는 INSERT 쿼리에서 이전 기본값을 새 기본값으로 잘못 대체하는 것을 방지하기 위해 다단계 프로세스를 따라야 합니다.

이를 위해 두 개의 마이너 릴리스가 필요합니다:

  1. 모델에 SafelyChangeColumnDefault concern을 추가하고 사후 마이그레이션에서 기본값을 변경합니다.
  2. 다음 마이너 릴리스에서 SafelyChangeColumnDefault concern을 정리합니다.

자체 호스팅 릴리스는 완전한 마이너 릴리스를 단일 제로 다운타임 배포로 묶습니다. 따라서 SafelyChangeColumnDefault를 정리하는 것은 마이너 릴리스를 기다려야합니다.

모델에 SafelyChangeColumnDefault concern을 추가하고 post-migration에서 기본값 변경하기

첫 번째 단계는 응용 프로그램 코드에서 해당 열을 안전하게 변경할 수 있도록 표시하는 것입니다.

class Ci::Build < ApplicationRecord
  include SafelyChangeColumnDefault
  
  columns_changing_default :partition_id
end

그런 다음 기본값을 변경하기 위해 포스트-배포 마이그레이션을 생성합니다.

bundle exec rails g post_deployment_migration change_ci_builds_default
class ChangeCiBuildsDefault < Gitlab::Database::Migration[2.1]
  def change
    change_column_default('ci_builds', 'partition_id', from: 100, to: 101)
  end
end

다음 소규모 릴리스에서 SafelyChangeColumnDefault concern 정리

다음 소규모 릴리스에서 columns_changing_default 호출을 제거하는 새로운 Merge Request을 생성하세요. 또한 다른 열에 대해 필요하지 않다면 SafelyChangeColumnDefault를 제거하세요.

대규모 테이블에 대한 스키마 변경

change_column_type_concurrentlyrename_column_concurrently는 다운타임 없이 테이블의 스키마를 변경하는 데 사용될 수 있지만, 대규모 테이블에 대해 제대로 작동하지 않습니다. 모든 작업이 순차적으로 수행되기 때문에 마이그레이션이 매우 오랜 시간이 걸릴 수 있으며 배포를 방해할 수 있습니다. 또한 연속적으로 많은 행을 빠르게 업데이트하므로 데이터베이스에 많은 압력을 줄 수 있습니다.

데이터베이스 압력을 줄이려면 대규모 테이블의 열을 마이그레이션할 때 백그라운드 마이그레이션을 대신 사용해야 합니다(예: issues와 같은). 백그라운드 마이그레이션을 사용하면 작업/부하를 오랜 기간에 걸쳐 분산시켜 배포를 늦추지 않고 진행할 수 있습니다.

자세한 내용은 배치 백그라운드 마이그레이션 정리 문서를 참조하세요.

인덱스 추가

add_concurrent_index를 사용하면 인덱스 추가 시 다운타임이 필요하지 않습니다.

더 많은 정보는 마이그레이션 스타일 가이드를 참조하세요.

인덱스 삭제

인덱스 삭제는 다운타임이 필요하지 않습니다.

테이블 추가

이 작업은 아직 테이블을 사용하는 코드가 없으므로 안전합니다.

테이블 삭제

테이블 삭제는 포스트-배포 마이그레이션을 사용하여 안전하게 수행할 수 있지만, 애플리케이션이 더는 해당 테이블을 사용하지 않아야만 가능합니다.

database dictionary의 설명에 따라 db/docs/deleted_tables에 테이블을 추가하세요. 테이블이 삭제되더라도 데이터베이스 마이그레이션에서 여전히 참조됩니다.

테이블 이름 변경

테이블 이름 변경은 데이터베이스 마이그레이션 중 또는 후에 애플리케이션이 이전 테이블 이름을 계속 사용할 수 있기 때문에 다운타임이 필요합니다.

테이블과 ActiveRecord 모델이 아직 사용되지 않는 경우 이전 테이블을 제거하고 새 테이블을 만드는 것이 테이블 이름을 “변경”하는 우선된 방법입니다.

GitLab은 멀티 릴리스 다운타임 없이 테이블 이름 변경 프로세스를 따르면 테이블 이름을 변경할 수 있습니다.

외래 키 추가

외래 키 추가는 일반적으로 3단계로 진행됩니다:

  1. 트랜잭션 시작
  2. 제약 조건 추가를 위해 ALTER TABLE 실행
  3. 모든 기존 데이터 확인

보통 ALTER TABLE은 트랜잭션의 끝까지 배타적 잠금을 획들하기 때문에 이 방법은 다운타임이 필요합니다.

GitLab은 Gitlab::Database::MigrationHelpers#add_concurrent_foreign_key를 사용하여 이를 우회할 수 있습니다. 이 방법을 사용하면 다운타임이 필요하지 않습니다.

외래 키 제거

이 작업은 다운타임이 필요하지 않습니다.

integer 기본 키를 bigint로 마이그레이션

[integer 기본 키를bigint로 마이그레이션의 오버플로우 리스크를 방지](https://gitlab.com/groups/gitlab-org/-/epics/4785)하기 위해 일부 테이블에 대해 integer 기본 키 (PK)를 bigint`로 마이그레이션해야 합니다. 데이터베이스에 너무 많은 부하를 일으키지 않으면서도 다운타임 없이 이 작업을 수행하는 프로세스는 아래와 같습니다.

변환 초기화 및 기존 데이터 마이그레이션 시작 (릴리스 N)

프로세스를 시작하려면 새로운 bigint 열을 생성하는 일반 마이그레이션을 추가하세요. 제공된 initialize_conversion_of_integer_to_bigint 헬퍼를 사용하세요. 해당 헬퍼는 새로운 레코드의 양쪽 열을 동기화하기 위해 데이터베이스 트리거를 생성합니다 (code):

# frozen_string_literal: true

class InitializeConversionOfMergeRequestMetricsToBigint < Gitlab::Database::Migration[2.1]
  disable_ddl_transaction!
  
  TABLE = :merge_request_metrics
  COLUMNS = %i[id]
  
  def up
    initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
  end
  
  def down
    revert_initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
  end
end

새로운 bigint 열을 무시하세요:

# frozen_string_literal: true

class MergeRequest::Metrics < ApplicationRecord
  include IgnorableColumns
  ignore_column :id_convert_to_bigint, remove_with: '16.0', remove_after: '2023-05-22'
end

일괄 배경 마이그레이션을 인큐하세요 (code) 기존 데이터를 마이그레이션하기 위해:

# frozen_string_literal: true

class BackfillMergeRequestMetricsForBigintConversion < Gitlab::Database::Migration[2.1]
  restrict_gitlab_migration gitlab_schema: :gitlab_main
  
  TABLE = :merge_request_metrics
  COLUMNS = %i[id]
  
  def up
    backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS, sub_batch_size: 200)
  end
  
  def down
    revert_backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS)
  end
end

백그라운드 마이그레이션 모니터링

마이그레이션이 실행되는 동안 마이그레이션 수행을 확인하세요. 실행 중인 마이그레이션을 확인하는 여러 방법에 대한 설명이 아래에 있습니다.

일괄 백그라운드 마이그레이션의 상태 확인

일괄 백그라운드 마이그레이션의 상태를 확인하는 방법을 참조하세요.

데이터베이스 조회

관련 데이터베이스 테이블을 직접 조회할 수 있습니다. 읽기 전용 레플리카에 액세스할 수 있어야 합니다. 예시 쿼리:

-- 주어진 테이블에 대한 일괄 배경 마이그레이션 세부 정보 가져오기
SELECT * FROM batched_background_migrations WHERE table_name = 'namespaces'\gx

-- 주어진 테이블의 상태에 따른 일괄 배경 마이그레이션 작업 수 가져오기
SELECT
  batched_background_migrations.id, batched_background_migration_jobs.status, COUNT(*)
FROM
  batched_background_migrations
  JOIN batched_background_migration_jobs ON batched_background_migrations.id = batched_background_migration_jobs.batched_background_migration_id
WHERE
  table_name = 'namespaces'
GROUP BY
  batched_background_migrations.id, batched_background_migration_jobs.status;

-- 주어진 테이블의 일괄 배경 마이그레이션 진행 상황 (추정 총 튜플 수에 기반함)
SELECT
  m.table_name,
  LEAST(100 * sum(j.batch_size) / pg_class.reltuples, 100) AS percentage_complete
FROM
  batched_background_migrations m
  JOIN batched_background_migration_jobs j ON j.batched_background_migration_id = m.id
  JOIN pg_class ON pg_class.relname = m.table_name
WHERE
  j.status = 3 AND m.table_name = 'namespaces'
GROUP BY m.id, pg_class.reltuples;

Sidekiq 로그

일괄 배경 마이그레이션 작업을 실행하는 워커를 모니터링하기 위해 Sidekiq 로그를 사용할 수도 있습니다:

  1. @gitlab.com 이메일 주소로 Kibana에 로그인합니다.
  2. 인덱스 패턴을 pubsub-sidekiq-inf-gprd*로 변경합니다.
  3. json.queue: cronjob:database_batched_background_migration 필터를 추가합니다.

PostgreSQL 느린 쿼리 로그

데이터베이스에서 1초 이상 걸린 느린 쿼리를 추적하는 느린 쿼리 로그가 있습니다. 일괄 배경 마이그레이션에 대해 보려면:

  1. @gitlab.com 이메일 주소로 Kibana에 로그인합니다.
  2. 인덱스 패턴을 pubsub-postgres-inf-gprd*로 변경합니다.
  3. json.endpoint_id.keyword: Database::BatchedBackgroundMigrationWorker 필터를 추가합니다.
  4. 선택 사항. 갱신만 보려면 json.command_tag.keyword: UPDATE 필터를 추가합니다.
  5. 선택 사항. 실패한 문만 보려면 json.error_severity.keyword: ERROR 필터를 추가합니다.
  6. 테이블 이름으로 필터를 추가합니다.

Grafana 대시보드

데이터베이스의 상태를 모니터링하기 위해 다음 추가 메트릭을 사용합니다:

  • PostgreSQL 튜플 통계: 활성으로 변환되는 테이블에 대한 업데이트 속도가 높거나 해당 테이블의 데드 튜플 백분율이 증가하는 경우, autovacuum이 따라가지 못할 수 있습니다.
  • PostgreSQL 개요: 주 서버에서 높은 시스템 사용 또는 초당 트랜잭션(TPS)이 발생하는 경우, 마이그레이션이 문제를 일으킬 수 있습니다.

프로메테우스 메트릭

각 일괄 배경 마이그레이션에 대한 메트릭 수는 프로메테우스에 발행됩니다. 이러한 메트릭은 Thanos에서 검색하고 시각화할 수 있습니다 (예시).

열 교체 (릴리스 N + 1)

백그라운드 마이그레이션이 완료되고 모든 레코드에 대해 새로운 bigint 열이 채워지면 열을 교체할 수 있습니다. 교체는 포스트-배포 마이그레이션으로 수행됩니다. 정확한 프로세스는 변환되는 테이블에 따라 다르지만, 일반적으로 다음 단계로 수행됩니다:

  1. 제공된 ensure_batched_background_migration_is_finished 도우미를 사용하여 일괄 마이그레이션이 완료되었는지 확인합니다 (예시). 마이그레이션이 완료되지 않은 경우 후속 단계가 실패합니다. 미리 확인함으로써 더 유용한 오류 메시지를 얻고자 합니다.
  2. Gitlab::Database::MigrationHelpers::ConvertToBigint 모듈의 add_bigint_column_indexes 도우미 메서드를 사용하여 기존 인덱스와 일치하는 integer 열을 사용하는 bigint 열로 인덱스를 생성합니다.
    • 도우미 메서드는 필요한 모든 bigint 인덱스를 생성하는 것으로 예상되지만, 기존 인덱스 중 누락되지 않았는지 다시 확인하는 것이 좋습니다. 도우미에 대한 자세한 정보는 Merge Request 135781에서 찾을 수 있습니다.
  3. 기존 integer 열을 사용하는 기존 FK와 일치하는 bigint 열을 사용하여 FK를 생성합니다. 다른 테이블을 참조하는 FK 및 마이그레이션 대상 테이블을 참조하는 FK에 대해 모두 수행합니다 (예시).
  4. 트랜잭션 내에서 열을 교체합니다:
    1. 관련된 테이블을 잠금합니다. 교착 상태를 줄이기 위해 이를 부모부터 자식 순서로 수행하는 것이 권장됩니다 (예시).
    2. 열 이름을 교체하여 열을 교환합니다 (예시).
    3. 트리거 기능을 재설정합니다 (예시).
    4. 기본값을 교환합니다 (예시).
    5. PK 제약 조건을 교체합니다(있는 경우) (예시).
    6. 기존 인덱스를 제거하고 새로운 인덱스의 이름을 변경합니다 (예시).
      • add_bigint_column_indexes 도우미를 사용하여 작성된 bigint 인덱스의 이름은 Gitlab::Database::MigrationHelpers::ConvertToBigint 모듈에서 bigint_index_name을 호출하여 검색할 수 있습니다.
    7. 기존 외래 키를 제거하고 새로운 외래 키의 이름을 변경합니다(있는 경우) (예시).

예시 Merge Request마이그레이션 참조.

트리거 및 이전 integer 열 제거 (릴리스 N + 2)

포스트-배포 마이그레이션 및 제공된 cleanup_conversion_of_integer_to_bigint 헬퍼를 사용하여, 데이터베이스 트리거와 이전 integer 열을 제거합니다 (예시 참조).

무시 규칙 제거 (릴리스 N + 3)

열이 제거된 다음 릴리스에서는 더 이상 필요하지 않으므로 무시 규칙을 제거합니다 (예시 참조).

데이터 마이그레이션

데이터 마이그레이션은 까다로울 수 있습니다. 데이터를 마이그레이션하는 일반적인 접근 방식은 3단계 접근법을 채택하는 것입니다:

  1. 초기 데이터 일괄 처리 마이그레이션
  2. 애플리케이션 코드 배포
  3. 남은 데이터 마이그레이션

보통은 이 접근 방식이 동작하지만 항상 그렇지는 않습니다. 예를 들어, 필드의 형식을 JSON에서 다른 형식으로 변경해야 하는 경우 문제가 발생할 수 있습니다. 기존 데이터를 애플리케이션 코드를 배포하기 전에 변경하려고 한다면 오류가 발생할 가능성이 높습니다. 반면에, 애플리케이션 코드를 배포한 후에 데이터를 마이그레이션하려고 한다면 동일한 문제에 봉착할 수 있습니다.

잘못된 데이터를 단순히 수정해야 하는 경우 포스트-배포 마이그레이션이 보통 충분합니다. 데이터 형식을 변경해야 하는 경우에는 일반적으로 새로운 데이터 형식의 새 열을 추가하고 애플리케이션이 해당 열을 사용하도록 하는 것이 가장 좋습니다. 이러한 경우 절차는 다음과 같습니다:

  1. 새로운 형식의 새 열 추가
  2. 기존 데이터를 이 새 열로 복사
  3. 애플리케이션 코드 배포
  4. 포스트-배포 마이그레이션에서 나머지 데이터 복사

일반적으로 일괄적인 해결책은 없습니다. 그러므로 가능한 최선의 방법으로 이러한 종류의 마이그레이션을 구현하도록 Merge Request에서 이야기를 나누는 것이 가장 좋습니다.