마이그레이션 중 다운타임 방지

데이터베이스 작업 시 특정 작업은 다운타임을 요구할 수 있습니다. 마이그레이션 중에는 다운타임이 발생할 수 없기 때문에 다운타임 없이 동일한 최종 결과를 얻기 위해 일련의 단계를 사용해야 합니다. 이 가이드는 다운타임이 필요해 보일 수 있는 다양한 작업과 그 영향, 그리고 다운타임 없이 수행하는 방법을 설명합니다.

열 삭제

열을 제거하는 것은 까다롭습니다. GitLab 프로세스가 이러한 열이 존재할 것으로 기대하기 때문에 ActiveRecord가 테이블 스키마를 캐시하기 때문입니다. 열이 참조되지 않더라도 마찬가지입니다. 열이 명시적으로 무시되지 않으면 발생하는 문제입니다. 이를 안전하게 해결하기 위해서는 세 가지 단계로 세 번의 릴리스를 필요로 합니다:

  1. 열 무시하기 (릴리즈 M)

  2. 열 삭제하기 (릴리즈 M+1)

  3. 무시 규칙 제거하기 (릴리즈 M+2)

열을 삭제하는 것은 쉽게 롤백할 수 없는 파괴적인 작업이기 때문에, 이러한 단계를 세 번의 릴리스를 통해 나누어 수행하는 이유입니다.

이 절차를 따르면 GitLab.com에 배포가 없고 셀프 관리 설치에 대한 업그레이드 프로세스가 이러한 단계를 함께 묶지 않도록 하는 데 도움이 됩니다.

열 무시하기 (릴리즈 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에만 존재하는 경우, 해당 모델에 추가해야 합니다.

열 무시 규칙을 제거할 안전한 시점을 표시해야 합니다:

  • remove_with: 열 무시를 추가한 후 일반적으로 두 개의 릴리스(M+2) 후의 GitLab 릴리즈로 설정합니다 (12.7이 예제입니다).
  • remove_after: 열 무시를 제거하는 것이 안전하다고 간주되는 날짜로 설정합니다. 일반적으로 M+1 릴리스 날짜 이후, M+2 개발 주기 동안입니다. 예를 들어, 12.7의 개발 주기가 2019-12-182020-01-17 사이이므로, 12.6열 삭제하기 릴리즈인 만큼 12.6 릴리즈 날짜인 2019-12-22로 날짜를 설정하는 것이 안전합니다.

이 정보는 열 무시와 관련된 정보를 더 잘 이해하는 데 도움이 되며, 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
    add_column(:users, :updated_at, :datetime, if_not_exists: true)

    # 반드시 `up` 메서드에서 드롭된 인덱스나 제약 조건을 다시 추가해야 합니다.
    add_concurrent_index(:users, :updated_at)
  end
end

down 메서드에서, 우리는 열이 다시 추가되기 전에 이미 존재하는지 확인합니다.

이는 마이그레이션이 비트랜잭셔널하고 실행 중에 실패했을 수 있기 때문입니다.

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

데이터베이스 마이그레이션에 대한 자세한 내용은 마이그레이션 스타일 가이드 페이지를 참조하세요.

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

다음 릴리즈인 12.7에서는 무시 규칙을 제거하기 위한 또 다른 머지 요청을 설정합니다.

이것은 ignore_column 행을 제거하고, 더 이상 필요하지 않은 경우 IgnoreableColumns의 포함도 제거합니다.

이것은 remove_with로 표시된 릴리즈와 remove_after 날짜가 지난 후에만 병합되어야 합니다.

열 이름 변경

열 이름을 표준 방법으로 변경하려면 다운타임이 필요합니다.

응용 프로그램이 데이터베이스 마이그레이션 중이거나 그 후에도 이전 열 이름을 계속 사용할 수 있기 때문입니다.

다운타임 없이 열 이름을 변경하려면 두 개의 마이그레이션이 필요합니다: 정규 마이그레이션과 배포 후 마이그레이션.

이 두 마이그레이션은 같은 릴리즈에 포함될 수 있습니다. 단계는 다음과 같습니다:

  1. 정규 마이그레이션 추가 (릴리즈 M)
  2. 열 무시 (릴리즈 M)
  3. 배포 후 마이그레이션 추가 (릴리즈 M)
  4. 무시 규칙 제거 (릴리즈 M+1)

정기 마이그레이션 추가 (릴리스 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가 기본값과 같은 값을 처리하는 방식 때문에 어렵습니다.

참고: Rails는 레코드를 작성할 때 PostgreSQL에 기본값을 전송하는 것을 무시합니다. 이 작업은 데이터베이스에 맡깁니다. 마이그레이션이 열의 기본값을 변경할 때, 실행 중인 애플리케이션은 스키마 캐시로 인해 이 변경 사항을 인식하지 못합니다. 그러면 애플리케이션은 잘못된 데이터를 데이터베이스에 작성할 위험이 있으며, 특히 데이터베이스 마이그레이션을 실행한 후 오랜 시간이 지나서 새로운 버전의 코드를 배포할 때 더 그렇습니다.

실행 중인 코드가 열의 이전 기본값을 명시적으로 작성하는 경우, INSERT 쿼리에서 이전 기본값을 명시적으로 지정할 때 Rails가 이전 기본값을 새로운 기본값으로 교체하지 않도록 방지하기 위해 다단계 프로세스를 따라야 합니다.

이 작업을 수행하려면 두 개의 마이너 릴리스에서 단계가 필요합니다:

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

SafelyChangeColumnDefault를 정리하기 전에 마이너 릴리스를 기다려야 합니다. 자가 관리 릴리스는 전체 마이너 릴리스를 단일 제로 다운타임 배포로 묶기 때문입니다.

SafelyChangeColumnDefault 커넥션을 모델에 추가하고 마이그레이션 후 기본값을 변경합니다.

첫 번째 단계는 애플리케이션 코드에서 열을 변경할 수 있는 안전한 것으로 표시하는 것입니다.

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 커넥션 정리

다음 소규모 릴리즈에서 columns_changing_default 호출을 제거하기 위한 새 병합 요청을 생성합니다. 또한 다른 열에 필요하지 않을 경우 SafelyChangeColumnDefault 포함도 제거합니다.

큰 테이블의 스키마 변경

change_column_type_concurrentlyrename_column_concurrently는 다운타임 없이 테이블의 스키마를 변경하는 데 사용할 수 있지만, 큰 테이블에는 잘 작동하지 않습니다. 모든 작업이 순차적으로 진행되기 때문에 마이그레이션이 완료되는 데 시간이 매우 오래 걸릴 수 있으며, 배포가 진행되지 못하게 됩니다. 또한 많은 행을 순차적으로 빠르게 업데이트하기 때문에 데이터베이스에 많은 압박을 가할 수 있습니다.

데이터베이스 압박을 줄이기 위해 큰 테이블(예: issues)의 열을 마이그레이션할 때는 배경 마이그레이션을 사용하는 것이 좋습니다. 배경 마이그레이션은 작업/부하를 더 긴 기간에 걸쳐 분산시키므로 배포가 느려지지 않습니다.

자세한 내용은 배치 배경 마이그레이션 정리에 대한 문서를 참조하세요.

인덱스 추가

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

자세한 내용은 마이그레이션 스타일 가이드를 참조하세요.

인덱스 삭제

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

테이블 추가

이 작업은 테이블을 사용하는 코드가 아직 없기 때문에 안전합니다.

테이블 삭제

테이블을 삭제하는 것은 배포 후 마이그레이션을 사용하여 안전하게 수행할 수 있지만, 애플리케이션이 더 이상 해당 테이블을 사용하지 않는 경우에만 가능합니다.

db/docs/deleted_tables에 테이블을 추가하고, 데이터베이스 사전에 설명된 프로세스를 사용하십시오.

테이블이 삭제되더라도 데이터베이스 마이그레이션에서 여전히 참조됩니다.

테이블 이름 변경

테이블 이름 변경은 애플리케이션이 데이터베이스 마이그레이션 중/후에 구 버전의 테이블 이름을 계속 사용할 수 있으므로 다운타임이 필요합니다.

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

다운타임 없이 테이블 이름을 변경하려면 다중 릴리즈 테이블 이름 변경 프로세스를 따르세요.

외래 키 추가

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

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

ALTER TABLE이 일반적으로 트랜잭션 종료까지 독점 잠금을 획득하므로 이 방법은 다운타임이 필요합니다.

GitLab은 Gitlab::Database::MigrationHelpers#add_concurrent_foreign_key를 사용하여 이를 우회할 수 있도록 허용합니다. 이 방법은 다운타임이 필요하지 않도록 보장합니다.

외래 키 제거

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

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

일부 테이블에서 integer 기본 키(PK)에 대한 오버플로우 위험을 방지하기 위해 PK를 bigint로 마이그레이션해야 합니다. 다운타임 없이 데이터베이스에 과부하를 주지 않고 이 작업을 수행하는 과정은 아래에 설명되어 있습니다.

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

과정을 시작하기 위해 새로운 bigint 열을 생성하는 정기 마이그레이션을 추가합니다. 제공된 initialize_conversion_of_integer_to_bigint 헬퍼를 사용하십시오. 이 헬퍼는 또한 데이터베이스 트리거를 생성하여 새 레코드의 두 열을 동기화합니다 (코드):

# 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

기존 데이터를 마이그레이션하기 위해 배치 백그라운드 마이그레이션을 예약합니다 (코드):

# 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)이 높은 경우 마이그레이션이 문제를 일으키고 있을 수 있습니다.

Prometheus 메트릭

각 배치된 백그라운드 마이그레이션에 대한 메트릭이 Prometheus에 게시됩니다. 이러한 메트릭은 Grafana에서 검색 및 시각화할 수 있습니다 (예제 보기).

열 교환 (릴리즈 N + 1)

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

  1. 제공된 ensure_batched_background_migration_is_finished 헬퍼를 사용하여 배치 마이그레이션이 완료되었는지 확인하세요. (예제 보기). 마이그레이션이 완료되지 않았다면 이후 단계가 실패합니다. 미리 확인함으로써 더 유용한 오류 메시지를 제공할 수 있습니다.

  2. Gitlab::Database::MigrationHelpers::ConvertToBigint 모듈의 add_bigint_column_indexes 헬퍼 메서드를 사용하여 기존 정수 열과 일치하는 bigint 열에 인덱스를 생성합니다.

    • 헬퍼 메서드는 필요한 모든 bigint 인덱스를 생성할 것으로 예상되지만, 기존 인덱스가 누락되지 않도록 재확인하는 것이 좋습니다. 헬퍼에 대한 더 많은 정보는 병합 요청 135781에서 찾을 수 있습니다.
  3. 기존 정수 열과 일치하는 bigint 열을 사용하여 외래 키(FK)를 생성합니다. 이는 다른 테이블을 참조하는 FK와 마이그레이션 중인 테이블을 참조하는 FK 모두에 대해 수행합니다. (예제 보기).

  4. 트랜잭션 내에서 열을 교환합니다:

    1. 관련 테이블을 잠급니다. 교착 상태에 걸릴 가능성을 줄이기 위해, 부모에서 자식으로 진행하는 것이 좋습니다. (예제 보기).

    2. 열 이름을 바꾸어 교환합니다. (예제 보기)

    3. 트리거 함수를 재설정합니다. (예제 보기).

    4. 기본값을 교환합니다. (예제 보기).

    5. 기본 키 제약 조건을 교환합니다 (있는 경우). (예제 보기).

    6. 이전 인덱스를 제거하고 새 인덱스의 이름을 변경합니다. (예제 보기).

      • add_bigint_column_indexes 헬퍼를 사용하여 생성된 bigint 인덱스의 이름은 Gitlab::Database::MigrationHelpers::ConvertToBigint 모듈의 bigint_index_name을 호출하여 가져올 수 있습니다.
    7. 이전 외래 키(여전히 존재하는 경우)를 제거하고 새 외래 키의 이름을 변경합니다. (예제 보기).

예제 병합 요청마이그레이션을 참조하세요.

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

배포 후 마이그레이션 및 제공된 cleanup_conversion_of_integer_to_bigint 도우미를 사용하여, 데이터베이스 트리거 및 이전 integer 열을 제거합니다 (예시 보기).

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

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

데이터 마이그레이션

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

  1. 초기 데이터 배치를 마이그레이션합니다.
  2. 애플리케이션 코드를 배포합니다.
  3. 나머지 데이터를 마이그레이션합니다.

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

단순히 유효하지 않은 데이터를 수정해야 하는 경우, 배포 후 마이그레이션으로 충분합니다. 데이터 형식(예: JSON에서 다른 형식으로)을 변경해야 하는 경우, 새로운 데이터 형식에 대해 새로운 열을 추가하고 애플리케이션이 이를 사용하도록 하는 것이 일반적으로 가장 좋습니다. 이 경우 프로세스는 다음과 같습니다:

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

일반적으로 모든 경우에 맞는 해결책은 없으므로, 이러한 유형의 마이그레이션에 대해서는 머지 요청에서 논의하여 가능한 최상의 방법으로 구현되도록 하는 것이 가장 좋습니다.