데이터 증가와 운영 작업의 영향
DSQL의 DDL·진단·성장 대응은 얼마나 간편하며 제약은 무엇인가?
결과 요약
이 실험은 서비스가 운영 중일 때 스키마를 바꾸거나 인덱스를 만드는 작업이 DSQL에서 얼마나 쉽고 업무에 어떤 영향을 주는지, 그리고 DSQL의 트랜잭션 제약이 실제로 어떻게 드러나는지를 확인했습니다. 최소 범위(MVP)로, E002 규모 데이터가 있는 DSQL 클러스터에 초당 1,000건의 주문 업무를 보내면서 인덱스 생성과 열 추가·삭제를 실행하고, 같은 부하만 보낸 셀과 비교했습니다. 대조군은 이번에 측정하지 않았습니다.
주문 1,100만 행의 status 열에 CREATE INDEX ASYNC로 인덱스를 만들자, 명령은 0.1초 만에 돌아왔고 인덱스가 실제로 쓸 수 있는 상태(indisvalid)가 되기까지 736초(약 12분)가 걸렸습니다. 빌드가 진행된 5분 측정 구간에서 주문 생성 p95는 27.5 ms에서 52.0 ms로, p99는 30.7 ms에서 79.8 ms로 늘었고, 주문 이력 조회 p99도 9.8 ms에서 45.7 ms로 늘었습니다. 그래도 모든 업무가 SLO 안에 있었고 실패는 0건, 업무 불변식 위반도 0건이었습니다. 이어서 실행한 열 추가·열 삭제·인덱스 삭제는 각각 0.1초 안에 끝났습니다.
DSQL의 제약은 분명하게 드러났습니다. 5,000행을 한 트랜잭션에서 바꾸려 하자 “transaction row limit exceeded”(54000)로 거절되었고, 트랜잭션을 310초 동안 열어 두자 “transaction age limit of 300s exceeded”로 거절되었습니다. 대량 변경은 3,000행 이하로 나누고, 5분을 넘는 작업은 트랜잭션을 나눠야 합니다. E002에서도 이 제약 때문에 적재·정리 코드를 나눠 쓰고, 대량 삭제가 느려 측정 방식을 바꿔야 했습니다.
프로덕션 사용 관점
운영 중 인덱스 추가와 열 변경은 DSQL에서 서비스를 멈추지 않고 할 수 있었습니다. 1,100만 행 인덱스 빌드 중 쓰기 지연이 2–3배 늘었지만 목표 안이었고 실패도 없었습니다. 다만 인덱스는 명령이 끝난 뒤에도 약 12분 동안 쓸 수 없으므로, 배포 절차가 indisvalid를 확인하고 나서 새 인덱스에 의존하는 코드를 켜야 합니다. 3,000행과 300초 트랜잭션 한도는 대량 수정·삭제, 긴 배치 작업을 여러 트랜잭션으로 나누도록 강제하므로, 기존 배치나 데이터 이관 스크립트는 다시 작성해야 합니다. vacuum 같은 유지보수는 사용자가 할 일이 없지만, 대조군과의 운영 부담 비교는 하지 않았습니다.
확인할 질문
DSQL의 DDL·진단·성장 대응은 얼마나 간편하며 제약은 무엇인가?
실행 조건
- 리전과 일시: 서울(ap-northeast-2), 2026-09-29 10:27–10:53 UTC.
- 구성: D1 Aurora DSQL 단일 리전, E002 규모 데이터(주문 1,100만, 주문 품목 2,750만 행, 약 5 GiB). E002 2차 측정과 같은 클러스터이며, 그 측정이 쌓은 행이 포함됩니다.
- 부하: E002와 같은 업무 혼합, 고정 도착률 1,000 TPS, 워밍업 60초 + 측정 300초. 부하만 보낸 기준 셀과 DDL을 함께 실행한 셀을 차례로 실행했습니다.
- DDL 순서: 측정 시작과 함께
CREATE INDEX ASYNC orders_status_mvp ON orders (status)→indisvalid가 참이 될 때까지 5초마다 확인 →ALTER TABLE customers ADD COLUMN→DROP COLUMN→DROP INDEX. 인덱스 빌드가 측정 구간보다 길어, 열 변경과 인덱스 삭제는 측정 구간이 끝난 뒤 실행되었습니다. - 한도 시험: 상품 5,000행을 한 트랜잭션에서 갱신, 트랜잭션을 연 채 310초 기다린 뒤 조회.
- 부하 발생기:
m7g.4xlargeSpot 러너 1대. - 계획과 달라진 점: 공통 Q의 60% 대신 1,000 TPS를 썼고, 4시간 갱신·삭제 부하, 3회 반복, 용량 증설·업그레이드 분기, 대조군 비교, 진단 지표 수집은 실행하지 않았습니다.
성능 결과
p95 / p99, 단위 ms. 두 셀 모두 성공 약 927 TPS, 실패 0, 불변식 위반 0건, SLO 통과.
| 업무 | 부하만 | 인덱스 빌드 중 |
|---|---|---|
| 상품 조회 | 6.0 / 6.9 | 5.9 / 6.7 |
| 주문 이력 | 8.7 / 9.8 | 9.4 / 45.7 |
| 주문 생성 | 27.5 / 30.7 | 52.0 / 79.8 |
| 주문 취소 | 27.0 / 29.2 | 29.8 / 66.1 |
| DDL·한도 시험 | 결과 |
|---|---|
CREATE INDEX ASYNC(1,100만 행) |
명령 0.1초, 사용 가능까지 735.8초 |
ALTER TABLE ... ADD COLUMN / DROP COLUMN |
0.04초 / 0.12초 |
DROP INDEX |
0.05초 |
| 5,000행 갱신 트랜잭션 | 거절: 54000 transaction row limit exceeded |
| 310초 동안 열린 트랜잭션 | 거절: 54000 transaction age limit of 300s exceeded |
- 성공 처리량(약 927 TPS)이 도착률(1,000 TPS)보다 낮은 것은 취소 요청 일부가 “이미 취소된 주문”으로 거절되어 성공으로 세지 않았기 때문으로 봅니다(앞선 측정이 같은 데이터에서 취소를 누적).
개발·운영 편의성
- 비동기 인덱스: 명령이 즉시 끝나고 빌드는 서비스가 뒤에서 합니다. 인덱스가
pg_indexes에는 바로 보이지만indisvalid가 참이 되기 전에는 쓸 수 없어, E002에서 이 차이를 놓쳐 초기화가 전체 스캔을 하는 문제를 겪었습니다. - 외래 키 역방향 인덱스: DSQL은 외래 키를 참조하는 쪽 열의 인덱스를 자동으로 만들지 않습니다. E002에서 원장의
order_id인덱스가 없어 주문 삭제가 원장 전체를 훑다가 300초 한도에 걸렸습니다. - 한도에 맞춘 코드: 적재·삭제·배치 작업을 3,000행 이하, 300초 이하 트랜잭션으로 나눠야 했습니다.
- 유지보수: vacuum·통계 갱신 같은 작업을 사용자가 설정하거나 실행할 필요가 없었습니다. 실행 계획과 진단 지표의 접근성은 이번에 평가하지 않았습니다.
비용
같은 클러스터를 쓴 E002 2차 측정의 일부로, 이 시험 구간(10:28–10:54 UTC)의 DSQL 사용량은 142,954 DPU(약 $1.43)였습니다. 이 가운데 두 부하 셀(각 6분, 1,000 TPS)은 약 2만 DPU로 추정되므로, 대부분은 1,100만 행 인덱스 빌드가 쓴 것으로 봅니다(약 12만 DPU, 약 $1.2, 분 단위 합계로 나눈 추정). 클러스터와 러너 비용은 E002 보고서의 비용 절에 포함했습니다.
결론과 한계
- DSQL은 부하 중 인덱스 추가와 열 변경을 서비스 중단 없이 처리했고, 인덱스 빌드 중에도 SLO를 지켰습니다. 대신 트랜잭션 행 수·시간 한도가 대량 작업의 구조를 바꾸게 만듭니다.
- 한계: 1회 실행, 1,000 TPS 한 수준, DSQL 단독 측정입니다. 대조군의 인덱스 생성 영향과 비교하지 않았고, 장기 성장과 운영 작업 시간은 측정하지 않았습니다.
정리 기록
- 이 시험은 E002 2차 측정 실행(
e002-20260929t081139z-4dce)의 클러스터와 러너를 썼습니다. 시험용 인덱스와 열은 시험 안에서 지웠습니다. 자원은 11:08–11:10 UTC에 삭제했고,e002.py verify의remaining_count=0(11:10:30 UTC)과 수동 교차 확인(DSQL 클러스터·실험 VPC·실험 IAM 역할·열린 Spot 요청 0개)을 마쳤습니다.