CI 데이터베이스에 새로운 테이블 추가하기
파이프라인 데이터 파티셔닝 디자인 청사진에서는 CI 도메인의 기존 테이블을 파티션으로 나누는 방법을 설명합니다. 그러나 여전히 새로운 기능을 위한 테이블을 추가해야 합니다. 때로는 이러한 테이블에는 파티션을 분할해야 하는 대규모 테이블에 대한 참조가 있습니다. 미래의 작업을 줄이기 위해 파티셔너블 테이블에 속하는 모든 테이블은 시작부터 파티셔닝되어야 합니다.
새로운 라우팅 테이블 만들기
다음은 데이터베이스 헬퍼를 사용하여 새로운 테이블과 외래 키를 생성하는 예시입니다:
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
def up
create_table(:p_ci_examples, primary_key: [:id, :partition_id], options: 'PARTITION BY LIST (partition_id)', if_not_exists: true) do |t|
t.bigserial :id, null: false
t.bigint :partition_id, null: false
t.bigint :build_id, null: false
end
add_concurrent_partitioned_foreign_key(
:p_ci_examples, :p_ci_builds,
column: [:partition_id, :build_id],
target_column: [:partition_id, :id],
on_update: :cascade,
on_delete: :cascade,
reverse_lock_order: true
)
end
def down
drop_table :p_ci_examples
end
이 테이블은 라우팅 테이블이라고 하며 어떤 데이터도 보유하지 않습니다. 데이터는 파티션에 저장됩니다.
라우팅 테이블을 생성할 때:
- 테이블 이름은
p_
접두사로 시작해야 합니다. 모든 쿼리가 라우팅 테이블을 통해 이루어지고 파티션에 직접 액세스하지 않도록 보장하는 분석기가 있습니다. - 각 새로운 테이블은
partition_id
열이 필요하며 해당 값은 관련 협회의 값과 같아야 합니다. 이 예시에서는p_ci_builds
입니다. 파이프라인에 속하는 모든 리소스는 동일한partition_id
값을 공유합니다. - 기본 키는 효율적인
id
에 의한 검색만을 허용하기 위해 열을 이 순서대로 가져야 합니다. - 외래 키 제약 조건은
ON UPDATE CASCADE
옵션을 포함해야 합니다. 왜냐하면partition_id
값이 파티션의 재균형을 위해 업데이트 될 수 있어야 하기 때문입니다.
첫 번째 파티션 생성
보통은 애플리케이션에게 부팅 시 초기 파티션을 생성하도록 의존합니다. 그러나 CI 테이블에 대한 고트래픽과 노드 수가 많다 보니 참조된 테이블에 잠금을 얻기가 어려울 수 있습니다. 결과적으로 배포 중에 노드가 시작에 실패할 수 있습니다. 이러한 실패를 방지하려면 애플리케이션이 실행되기 전에 파티션이 이미 생성되어 있는지 확인해야 합니다:
disable_ddl_transaction!
def up
with_lock_retries do
connection.execute(<<~SQL)
LOCK TABLE p_ci_builds IN SHARE ROW EXCLUSIVE MODE;
LOCK TABLE ONLY p_ci_examples IN ACCESS EXCLUSIVE MODE;
SQL
connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_examples_100
PARTITION OF p_ci_examples
FOR VALUES IN (100);
SQL
end
end
파티션은 gitlab_partitions_dynamic
스키마에 생성됩니다.
파티션을 생성할 때 기억해야 할 것:
- 파티션 이름은
p_
접두사를 사용하지 않습니다. -
partition_id
에 대한 시작 값은100
입니다.
파티션 값을 캐스캐이드하기
파티션 값을 캐스캐이드하려면 모듈이 Ci::Partitionable
모듈을 사용해야 합니다:
class Ci::Example < Ci::ApplicationRecord
include Ci::Partitionable
self.table_name = :p_ci_examples
self.primary_key = :id
belongs_to :build, class_name: 'Ci::Build'
partitionable scope: :build, partitioned: true
end
파티션 관리하기
모델은 PARTITIONABLE_MODELS
디렉터리에 포함되어 있어야 합니다. 이는 partition_id
가 올바르게 전파되었는지 테스트하는 데 사용되기 때문입니다.
이 디렉터리에 없는 경우, partitioned: true
를 지정하면 첫 번째 파티션을 만듭니다. 또한 모델은
postgres_partitioning.rb
초기화 파일에 등록되어야 합니다.