다운타임 피하기

데이터베이스 작업 중 특정 작업이 다운타임을 필요로 할 수 있습니다. 마이그레이션에서 다운타임이 발생할 수 없으므로 다운타임 없이 동일한 결과를 얻기 위해 일련의 단계를 사용해야 합니다. 이 안내서에서는 다운타임이 필요해 보일 수 있는 다양한 작업, 그 영향 및 다운타임 없이 수행하는 방법에 대해 설명합니다.

열 삭제하기

열을 제거하는 것은 까다로운 작업입니다. 왜냐하면 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(Community Edition) 및 EE(Enterprise Edition)에 모두 존재하는 경우, 열은 CE 모델에서 무시되어야 합니다. 모델이 EE에만 존재하는 경우에는 EE에 추가해야 합니다.

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

  • remove_with: 일반적으로 추가한 열 무시 후 두 릴리스(M+2) (12.7이 우리의 예시에서) 이후의 GitLab 릴리스로 설정합니다.
  • 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

    # `up` 메서드에서 삭제된 모든 인덱스 또는 제약을 다시 추가해야 합니다.
    # 예를 들어:
    add_concurrent_index(:users, :updated_at)
  end
end

down 메서드에서 다시 열을 추가하기 전에 해당 열이 이미 존재하는지 확인합니다. 이는 마이그레이션이 트랜잭션을 처리하지 않고 실행 중에 실패할 수 있기 때문에 필요합니다.

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

더 많은 정보는 데이터베이스 마이그레이션에 관한 페이지 마이그레이션 스타일 가이드를 참조하세요.

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

다음 릴리스에서, 이 예제의 경우 12.7, 우리는 무시 규칙을 제거하기 위한 또 다른 병합 요청을 설정합니다. 이는 ignore_column 라인을 제거하며 - 더 이상 필요하지 않은 경우에는 IgnoreableColumns의 포함 또한 제거합니다.

이는 오직 remove_with로 표시된 릴리스가 지나고 나서만 병합되어야 합니다.

컬럼 이름 변경

표준 방법으로 컬럼 이름을 변경하려면 응용 프로그램이 데이터베이스 이관 전 또는 후에도 이전 컬럼 이름을 계속 사용할 수 있으므로 다운타임이 필요합니다. 다운타임이 필요하지 않게 컬럼의 이름을 변경하려면, 우리는 두 가지 이관이 필요합니다: 보통 이관(regular migration)과 이후 배포 이관(post-deployment migration). 이 두 개의 이관은 동일한 릴리스에 배치될 수 있습니다. 수행해야 할 단계:

  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가 기본값과 동일한 값을 처리하는 방식 때문에 어려울 수 있습니다.

참고: 마이그레이션에서 기본값을 변경할 때, 실행 중인 응용 프로그램은 스키마 캐시로 인해 이 변경 사항을 인지하지 못합니다. 따라서, 새 코드의 배포가 마이그레이션을 실행한 후 오랜 시간이 지난 경우 특히, 응용 프로그램은 실수로 잘못된 데이터를 데이터베이스에 작성할 위험에 노출됩니다.

실행 코드가 열의 이전 기본값을 명시적으로 쓰는 경우, 기존 기본값을 새 기본값으로 교체하는 것을 방지하기 위해 다단계 프로세스를 따라야 합니다.

이를 위해서는 두 개의 소형 릴리스 단계가 필요합니다:

  1. 모델에 SafelyChangeColumnDefault를 concern으로 추가하고, 기본값을 포스트 마이그레이션에서 변경합니다.
  2. 다음 소형 릴리스에서 SafelyChangeColumnDefault를 정리하기

데이터베이스 마이그레이션을 실행한 후 새 코드의 배포가 오랜 시간이 지나는 경우, 스키마 캐시로 인해 애플리케이션이 이러한 변경 사항을 인지하지 못할 수 있습니다. 응용 프로그램은 올바르지 않은 데이터를 데이터베이스에 실수로 작성할 위험이 있습니다.

이를 방지하려면 모델에 SafelyChangeColumnDefault를 concern으로 추가하고, 기본값을 포스트-마이그레이션에서 변경해야 합니다.

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 호출을 제거하는 새 병합 요청을 만듭니다. 또한, 다른 열에 필요하지 않다면 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)를 사용하여 오버플로우 리스크(Overflow Risk)를 방지하기 위해, 해당 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 개요: 기본 데이터베이스 서버에서 높은 시스템 사용률이나 초당 트랜잭션이 있으면 마이그레이션이 문제를 일으킬 수 있습니다.

Prometheus 메트릭

각 일괄 배경 마이그레이션의 메트릭 수는 Prometheus에 발행됩니다. 이러한 메트릭은 Thanos에서 검색하고 시각화할 수 있습니다 (예시 보기).

열 교체 (릴리스 N + 1)

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

  1. 제공된 ensure_batched_background_migration_is_finished 도우미를 사용하여 일괄 마이그레이션이 완료되었는지 확인합니다 (예시 보기). 마이그레이션이 완료되지 않았을 경우, 후속 단계는 어차피 실패합니다. 미리 확인함으로써 더 유용한 오류 메시지를 얻고자 합니다.
  2. Gitlab::Database::MigrationHelpers::ConvertToBigint 모듈에서 제공되는 add_bigint_column_indexes 도우미 메서드를 사용하여 기존 인덱스에 대한 integer 열과 일치하는 bigint 열로 인덱스를 생성합니다.
    • 도우미 메서드는 필요한 모든 bigint 인덱스를 생성하기를 기대하지만, 기존 인덱스 중 일부를 놓친 것은 아닌지 다시 확인하는 것이 좋습니다. 도우미에 대한 자세한 정보는 135781번 MR에서 찾을 수 있습니다.
  3. 기존 FK를 사용하여 기존 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 requestmigration를 참조하세요.

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

후방 배포 이관 및 제공된 cleanup_conversion_of_integer_to_bigint 도우미를 사용하여 데이터베이스 트리거와 이전 정수 열을 제거하세요 (예시 보기).

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

열이 삭제된 이후의 다음 릴리스에서는 더는 필요 없으므로 무시 규칙을 제거하세요 (예시 보기).

데이터 이관

데이터 이관은 까다로울 수 있습니다. 데이터를 이관하는 보통적인 방법은 다음과 같은 3단계 접근법을 취하는 것입니다:

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

보통 이 방법이 작동하지만 항상 그렇지는 않습니다. 예를 들어, 필드 형식을 JSON에서 다른 형식으로 변경해야 한다면 약간의 문제가 발생할 수 있습니다. 애플리케이션 코드를 배포하기 전에 기존 데이터를 변경하려고 한다면 대부분의 경우 오류가 발생할 것입니다. 반면, 애플리케이션 코드를 배포한 후에 이관하려고 한다면 동일한 문제에 부딪힐 수 있습니다.

단순히 잘못된 데이터를 수정해야 하는 경우 후방 배포 이관이 보통 충분합니다. 데이터 형식을 변경해야 하는 경우 (예: JSON에서 다른 형식으로) 대부분 새로운 열을 새 데이터 형식을 위해 추가하고 애플리케이션에서 해당 열을 사용하는 것이 일반적으로 가장 좋습니다. 이러한 경우 절차는 다음과 같습니다:

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

일반적으로 일괄된 해결책은 없으므로 가능한 최상의 방법으로 구현되도록 이러한 종류의 이관을 논의하는 것이 가장 좋습니다.