본문 바로가기
SingleStoreDB/엔지니어링

Making Painless Schema Changes

by 에이플랫폼 [Team SingleStore Korea] 2021. 10. 18.

다운타임 없이 테이블의 스키마를 변경할 수 있는 능력은 모든 데이터베이스 크리티컬한 특징입니다. 그럼에도 불구하고 기존의 관계형 데이터베이스는 스키마 변경의 지원이 부족했습니다. 초기의 분산형 NoSQL은 스키마가 없어 좀 더 자유롭게 데이터를 관리할 있게 되었지만, 관계적 기능이 없었습니다.

따라서 보편적인 생각은 관계형 모델을 유지한 채, 쉬운 스키마 변경이 가능하도록 하는 것이었습니다. SingleStore는 ALTER TABLE 작업이 워크로드 실행에 미치는 영향을 최소화하도록 노력했습니다. 이 기능을 일반적으로 “online” ALTER TABLE이라고 불립니다. 대부분의 관계형 데이터베이스는 “online” ALTER TABLE의 개념을 지원하지만, 그 의미에 대해 다른 정의를 내리고 있습니다. SingleStore에서는 진정한 online ALTER TABLE에 대해 다음과 같이 정리합니다.


ONLINE ALTER TABLE

1) 실행 중, 테이블의 disk나 memory의 사용량을 2배로 늘릴 필요가 없다. (원 테이블을 파괴하지 않고 테이블의 두 번째

복사본을 만드는 것은 허용되지 않는다.)

2) 실행 중, 테이블을 잠그거나 장시간 쿼리(읽기 또는 쓰기)를 막지 않는다. (1초 미만의 지연(blocking)은 OK)

3) 테이블의 크기나 테이블에 대해 실행되는 워크로드에 관계없이 과도한 시스템 리소스를 사용하지 않는다. (CPU, Disk, Network)

SingleStore는 3가지를 모두 달성할 수 있는 유일한 분산 관계형 데이터베이스입니다. 예를 들어, MySQL Cluster는 (1)을 수행하지 못합니다. – 많은 경우에 테이블을 복사합니다. VoltDB, Vertica 및 Redshift는 (2)를 수행하지 못합니다. – 전체 ALTER 작업 전반에 걸쳐 테이블을 잠그고, 프로덕션 시스템을 효과적으로 다운시키거나 번거로운 복제본이 필요합니다.


ALTER TABLE 실행 과정 4 STEP

다음과 같은 rowstore 테이블에 컬럼을 추가한다고 가정합니다.

CREATE TABLE example(c1 int primary key); ALTER TABLE example ADD COLUMN c2 VARCHAR(100) DEFAULT NULL;

다음은 SingleStore rowstore에서 ALTER가 4단계 실행 과정을 어떻게 실행하는지 개략적으로 설명하는 다이어그램입니다.

 

Step1) 클러스터 내부에 있는 모든 노드에서 테이블의 구조(메타데이터라고도 함)를 “New Row Memory”처럼 새 컬럼 c2가 포함되도록 변경한다. 테이블 잠금은 메타데이터 변경 시간 동안만 유지되며, 1초도 걸리지 않는다. 클러스터에 있는 모든 노드를 동기화하기 위해 분산 잠금이 필요하며, 동시에 새로운 컬럼을 보여주기 시작한다. 이 시점에서 row 데이터는 수정되지 않았으며 테이블의 메타데이터만 수정되었다.

Step2) 완료 전, SELECT 쿼리는 c2 컬럼을 볼 수 있지만, 테이블의 row에는 실제로 존재하지 않는다. 쿼리 실행 중, SingleStore는 필요할 때마다 c2의 기본값(default; 현재 예시에서는 null)을 즉시 생성한다.

Step3) INSERT(또는 모든 쓰기 쿼리)에 c2에 대한 데이터를 제공해야 하며, 그렇지 않으면 c2는 NULL로 기본값이 된다. 이 새로운 row들은 c2가 없는 이전의 row와 함께 테이블에 삽입될 것이다. 위의 그림처럼 Index Memory 공간과 Row Memory 공간이 분리되어 있기 때문에 이 작업들이 가능하다. Index는 row에 대한 액세스가 필요할 때마다 memory 포인터를 따라간다. 이 설계는 Old Row Memory 와 New Row Memory를 공존할 수 있도록 해준다.

메타데이터 변경 시 “New Row Memory"을 영역을 설정하여 새 테이블 스키마에 대한 row를 할당한다. 새로 삽입된 row는 이 memory 영역에 할당된다. 원 테이블 row는 "Old Row Memory" 영역에 남아 있다.

Step 4) ALTER는 이제 old row 형식에서 new row 형식으로 row 데이터를 전송하기 시작한다. "Old Row Memory"를 사용하여 작업을 상당히 간단하게 수행할 수 있다. 전송 프로세스는 테이 블 업데이트와 동일하다. 변경 스레드는 단일 트랜잭션에서 전체 테이블이 중복되지 않도록 수 mbytes 정도의 row마다 커밋 된다. 이 작업은 “Old Row Memory"를 축소시키다. 프로덕션 워크로드는 이 프로세스 전반에 걸쳐 모두 발생한다. 이 워크로드들은 간단한 체크로 각 row에 새 컬럼이 있는지를 알아내서 적절하게 패치한다. 전송 프로세스는 더 큰 테이블에 시간이 걸릴 수 있지만 일부 CPU를 사용하는 것 외에 쿼리 실행에는 영향을 미치지 않는다.


ALTER의 구현 시, 작업의 영향을 최소화하기 위한 주의사항

  • Step1이 완료된 후, ALTER TABLE을 취소할 수 없습니다. row 전송 프로세스(Step 3)는 트랜잭션(memory 사용을 2배로 늘려야 함)이 아니기 때문에 시작 후에는 롤백 하거나 중지할 수 없습니다.
  • Step1에서의 잠금은 장기 실행 쿼리를 대기(blocking) 시키므로, 이 쿼리가 시작되기 전에 ALTER가 시작되어 완료될 수 있도록 합니다.
  • 일부 ALTER 작업은 온라인으로 수행할 수 없습니다. 예를 들어 ALTER가 작업 도중 중복 키 오류가 발생할 수 있으므로, 현재 버전 SingleStore에서는 온라인에서 고유키를 추가할 수 없습니다. 따라서 그러한 종류의 명령은 차단됩니다.
  • 하나의 테이블에 대해 한 번에 하나의 ALTER만 실행할 수 있습니다. ALTER는 기본적으로 오래 실행되는 쿼리이므로 두 번째 ALTER는 첫 번째 ALTER가 완료될 때까지 기다립니다. 그러나 각기 다른 테이블에 대한 ALTER는 동시에 실행할 수 있습니다.

요약하면, SingleStore를 사용하면, “ONLINE ALTER TABLE”이라는 새로운 기능을 사용할 수 있습니다. 다운 타임 없이 새로운 인덱스나 컬럼을 추가하는 것은 기업 사용자가 원하는 것입니다. 스키마 변경의 유연성과 분산 in-memory 데이터베이스의 강력한 쿼리 기능을 모두 갖춘 것은 고유한 조합입니다.

 

August 20th, 2015

Adam Prout