본문 바로가기

MySQL

[MySQL] pt-osc를 활용한 online 테이블 파티션 변경

MySQL 서버에서 파티션 테이블을 생성했는데 얼마 지나지 않아(데이터가 쌓인 시점에서) 파티션 생성 조건을 변경해야하는 일이 생겼다. 파티션을 변경하는 경우 기존 파티션에 존재하던 데이터는 삭제되기 때문에 이를 나이스하게 해결할 방법이 필요했다. 단순히 데이터를 백업했다가 그 데이터를 다시 재구성된 파티션 테이블로 옮기는 방법은 작업 시간동안 발생한 DML과의 순서(PK)를 보장할 수 없을 뿐더러, 데이터를 옮기고 rename하고, 다시 데이터를 검증하고 ..여러 복잡한 문제들이 있었다. 아쉽지만 pt-online-schema-change에도 뭔가 이를 지원하는 기능이 따로 존재하지 않았다.

하지만,

MySQL 서버의 Online DDL을 instant 또는 inplace, nolock 옵션으로 진행할 수 없을 때, 즉 shared lock 또는 copy 알고리즘 방식을 사용해야할 때 pt-online-schema-change 도구를 사용한다. pt-online-schema-change는 크게는 아래와 같은 단계로 작업이 진행되는데,

  1. 원본 테이블과 동일한 new 테이블 생성
  2. _{테이블명}_new 테이블에 DDL 적용
  3. 트리거 생성(원본 테이블에 트리거가 생성되어 있으면 중단됨)
  4. 복사할 데이터의 추정치 계산
  5. 원본 테이블에서 신규 테이블로 데이터 복사
  6. ANALYZE TABLE 신규 테이블

이 때 위에서 2번 단계를 진행한 후에 잠시 작업을 멈추고 _new 테이블에 변경하고자 하는 파티션을 적용하면 online 중에 파티션을 변경할 수 있다(물론 이번 작업에 있어서 pause는 3번 단계를 진행한 이후에 수행하여도 상관없다). 여기서 중요한 점은 꼭 데이터를 복사하기 전에 pause를 해야한다는 것이다.

이제 위 작업을 수행하기 위해 pt-osc(pt-online-schema-change)의 소스코드를 일부 수정해주어야 한다.

 

pt-online-schema-change 소스코드 수정

참고로 나의 pt-osc 버전은 3.5.0이다. 소스는 실행파일 경로에 있는 pt-online-schema-change 소스 자체를 변경해주면 된다. 아래 소스 코드를 트리거가 생성되기 전의 소스 위치에 넣어준다(전체 소스 코드는 깃헙을 참조, direct url).

 

#1. by silver
   if($o->has('pause-before-data-copy') && defined $o->get('pause-before-data-copy')){
        my $user_input;
        do{
           print "********************************************************\n";
           print " Pause before data copy. Enter [go] when you are done.\n";
           print "********************************************************\n";
           print ": ";
           chomp ($user_input = <STDIN>);
        }while(!($user_input =~ /go/i));
   }

#2. by silver
=item --pause-before-data-copy
Pause before data copy into _[table]_new

 

위 소스의 item 부분은 pt-online-schema-change 명령어 수행 시 신규 파라미터를 하나 더 추가하기 위함이다.

 

수정된 버전으로 pt-osc 실행

수정된 버전의 pt-osc를 수행할 때는 파라미터에다가 위의 소스에서 추가한 옵션만 넣어주면 된다.

 

pt-online-schema-change --alter "ADD seq3 int null" D=test,t=test \
--no-drop-old-table \
--no-drop-new-table \
--chunk-size=1000 \
--chunk-size-limit=2 \
--host=127.0.0.1 \
--user=root \
--progress=time,30 \
--max-load="Threads_running=20" \
--critical-load="Threads_running=50" \
--chunk-index=PRIMARY \
--charset=UTF8MB4 \
--sleep=0.05 \
--pause-before-data-copy \
--execute

 

그러면 아래와 같이 데이터 복사 전 go를 입력할 때까지 다음 작업을 무한정 대기하게 된다.

 

 

위의 pause 상태에서 다른 세션을 열어서 테이블 리스트를 확인해보면 test 테이블의 신규 테이블인 _test_new 테이블이 생성되어 있는 것을 확인할 수 있다.

 

 

이제 이 세션에서 _test_new 테이블에 파티션을 적용한다.

 

 

그리고 다시 본래 세션으로 돌아와서 go를 입력한다. 그러면 아래와 같이 다음 과정인 데이터 복사 작업이 진행되는 것을 확인할 수 있다.