Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby로 PostgreSQL 파티션 테이블 자동 관리하기 — pg_partition_manager 젬 활용법

대용량 테이블에서 오래된 데이터를 한꺼번에 삭제하면 데이터베이스 성능이 크게 저하될 수 있습니다. 이를 피하기 위해 저희는 기본 PostgreSQL 데이터베이스에서 파티션 테이블을 사용해 만료된 데이터를 효율적으로 제거하고 있습니다.

PostgreSQL 10 이전 버전에는 파티션 테이블에 대한 네이티브 지원이 없었기 때문에, 저희는 pg_partman 확장을 사용해 파티셔닝을 구현했습니다. 이 확장은 PostgreSQL의 테이블 상속을 활용해 파티션 대상 테이블의 자식 테이블을 생성하고, 트리거를 통해 부모 테이블이 아닌 자식 테이블에 데이터를 삽입하는 방식으로 동작합니다.

그동안 이 확장은 잘 작동해 왔지만 한 가지 단점이 있었습니다. 바로 Amazon RDS에서는 지원되지 않는다는 점입니다. 이제 PostgreSQL이 네이티브 파티션을 공식 지원하게 되었으므로, RDS도 선택지로 활용할 수 있도록 해당 확장을 걷어낼 적절한 시점이라고 판단했습니다.

파티셔닝 구조: 시간 기반 분할

저희의 파티셔닝 사용 사례는 비교적 단순합니다. 시간을 기준으로 테이블을 나누고, 전체 파티션에 저장하려는 행 수와 데이터 보관 기간에 따라 매일, 매주 또는 매월 새로운 파티션을 생성하는 방식입니다.

모든 파티션 테이블에는 각 행이 어느 파티션에 저장될지 결정하는 created_at 컬럼이 포함됩니다. 예를 들어 다음과 같이 테이블을 정의할 수 있습니다.

create table events (
  project_id integer,
  data jsonb,
  created_at timestamp
)
partition by range (created_at);

주간 단위 파티션을 운영하고 싶다면 다음과 같이 생성합니다.

create table events_p2019_10_28 partition of events for values from ('2019-10-28') to ('2019-11-04');
create table events_p2019_11_04 partition of events for values from ('2019-11-04') to ('2019-11-11');

시간 기반 파티셔닝의 가장 큰 장점은 오래된 데이터 삭제가 파티션 하나를 드롭하는 것만큼 간단하다는 점입니다. 따라서 필요한 정기 유지 관리는 두 가지뿐입니다.

  • 다가오는 날짜 범위에 맞춰 새 파티션을 미리 생성하는 것
  • 더 이상 보관할 필요가 없는 데이터가 담긴 오래된 파티션을 삭제하는 것

pg_partition_manager 젬 소개

이러한 유지 관리 작업을 더욱 편리하게 처리하기 위해 pg_partition_manager 젬을 만들었습니다. 이름에서 알 수 있듯이, 그동안 저희에게 큰 도움이 된 pg_partman 확장에서 영감을 받은 프로젝트입니다.

앞서 살펴본 events 테이블과 파티셔닝 방식을 기준으로 이 젬을 사용하는 방법을 확인해 보겠습니다. 다음과 같은 스크립트나 rake 태스크를 작성하면 됩니다.

require "pg_partition_manager"

PgPartitionManager::Time.process([{parent_table: "public.events", period: "week", premake: 1, retain: 3}])

주요 설정 옵션

  • parent_table: schema.table_name 형식으로 지정합니다. public은 기본 스키마로, Rails 개발자들이 주로 사용하는 스키마입니다.
  • period: day, week, month 중 하나를 선택할 수 있습니다.
  • premake: 현재 기간 이후 미리 생성해 둘 파티션 테이블의 개수를 지정합니다. 값을 생략하면 기본적으로 4개의 테이블이 미리 생성됩니다.
  • retain: 현재 기간 이전의 파티션 중 보관할 개수를 지정합니다. 값을 생략하면 일/주/월 단위 기준으로 각각 7일, 4주, 6개월간 데이터를 보관합니다.

이 스크립트나 태스크를 매일 실행되는 cron 작업으로 등록해 두기만 하면 준비가 끝납니다. 이후에는 필요한 시점에 자동으로 파티션을 생성하고, 불필요한 파티션을 삭제해 줍니다.

ActiveRecord 코드 변경 없이 그대로 사용

모든 ActiveRecord 쿼리는 파티션되지 않은 일반 테이블과 완전히 동일하게 동작하므로, 애플리케이션 코드를 수정할 필요가 전혀 없습니다. 즉, Event.create, Event.where 등이 항상 그래왔던 것처럼 작동하며, 데이터 삽입 시 PostgreSQL이 알아서 올바른 파티션에 데이터를 배치해 줍니다.

다만 데이터 양이 많다면 한 가지 긍정적인 변화를 체감할 수 있습니다. 쿼리에 created_at 조건을 포함하면, PostgreSQL이 모든 파티션을 훑는 대신 where 절에서 지정한 기간 범위에 해당하는 파티션만 스캔하기 때문에 조회 성능이 향상됩니다.

정리

만료 시점에 삭제해야 하는 시간 기반 데이터를 대량으로 다루고 있다면, PostgreSQL 네이티브 파티션 테이블과 pg_partition_manager 젬을 활용해 보세요. 대량 DELETE로 인한 성능 저하 없이 데이터를 깔끔하게 관리할 수 있으며, Amazon RDS 환경에서도 문제없이 사용할 수 있습니다. :)