데이터 적재 트랜잭션
요약 Apache Doris는 모든 데이터 적재를 트랜잭션으로 처리합니다. 하나의
BEGIN ... COMMIT으로 여러 삽입 작업을 묶고, 데이터 적재Label로 재시도에 따른 중복을 제거하며, Stream Load HTTP 요청의 헤더로 두 단계 커밋을 제어할 수 있습니다. 이 두 단계 커밋 덕분에 Flink, Spark, CDC 파이프라인은 별도의 처리 내역 관리 테이블 없이도 Doris에 exactly-once 방식으로 데이터를 쓸 수 있습니다.

Apache Doris에서 데이터 적재 트랜잭션을 사용해야 하는 이유는 무엇인가요?
Apache Doris 데이터 적재 트랜잭션은 중복 행과 부분 쓰기 문제를 애플리케이션 대신 웨어하우스가 처리하도록 합니다. 따라서 Flink 재처리, 도중에 중단된 여러 테이블 쓰기, 파일 재업로드도 올바르게 처리됩니다. 웨어하우스에 데이터를 적재할 때 발생하는 문제는 대체로 예상할 수 있습니다. Flink 작업이 체크포인트 도중에 재시작되어 마지막 배치를 재처리하면 행이 두 배로 늘어납니다. CDC 파이프라인이 팩트 테이블을 업데이트하지만 함께 수행하는 차원 테이블 쓰기에 실패하면, 다음 백필까지 두 테이블의 데이터가 서로 일치하지 않게 됩니다. 재시도 스크립트는 이전 시도가 실제로 반영되었는지 확인할 방법이 없어 같은 파일을 다시 업로드합니다. 이런 문제마다 애플리케이션에 번거로운 처리 내역 관리 로직을 넣어야 합니다.
- 중단된 스트리밍 작업이 데이터를 재처리하면 행이 중복됩니다.
- 함께 반영되어야 하는 여러 테이블 쓰기가 도중에 중단될 수 있습니다.
- 같은 파일을 다시 제출하면, 직접 이력을 추적하지 않는 한 데이터가 두 번 반영됩니다.
Apache Doris는 이 세 가지 문제를 모두 서버에서 해결하므로 데이터 적재 클라이언트를 단순하게 유지할 수 있습니다.
Apache Doris 데이터 적재 트랜잭션이란 무엇인가요?
Apache Doris 데이터 적재 트랜잭션은 모든 데이터 수집 경로의 기반이 되는 원자적 쓰기 단위입니다. Doris에 대한 모든 쓰기는 트랜잭션 내에서 실행됩니다. 여기에는 INSERT INTO, Stream Load, Routine Load, Broker Load가 포함됩니다. 각 트랜잭션에는 고유한 Label이 부여되며, FE가 관리하고 추적하는 수명 주기 상태를 차례로 거칩니다. Apache Doris가 데이터 적재마다 암시적으로 트랜잭션을 열고 커밋하도록 하거나, 명시적인 BEGIN/COMMIT/ROLLBACK으로 직접 제어하거나, 스트리밍 싱크를 위해 HTTP로 커밋을 두 단계로 나눌 수 있습니다.
주요 용어
Label: 트랜잭션을 식별하는 데이터베이스별 문자열입니다. 같은 Label로 다시 제출하면 데이터 적재의 중복이 제거됩니다.Implicit transaction: 개별 데이터 적재가 각각 하나의 트랜잭션이며, 성공하면 자동으로 커밋됩니다.Explicit transaction:BEGIN ... COMMIT;은 같은 데이터베이스에 대한 여러 쓰기를 하나의 원자적 단위로 묶습니다.Stream Load 2PC: 후속 HTTP 호출로 커밋하거나 중단할 때까지 PRECOMMITTED 상태에 머무르는 Stream Load입니다.Lifecycle states:PREPARE→PRECOMMITTED→COMMITTED→VISIBLE(또는ABORTED). 행은VISIBLE이후에만 쿼리할 수 있습니다.
Apache Doris 데이터 적재 트랜잭션은 어떻게 동작하나요?
Apache Doris 데이터 적재 트랜잭션에서는 모든 쓰기가 FE가 관리하는 다섯 가지 상태(PREPARE → PRECOMMITTED → COMMITTED → VISIBLE, 실패 시 ABORTED)를 거칩니다. Label로 재시도에 따른 중복을 제거하고, 마지막으로 복제본 수준에서 게시를 수행해 행들을 한 시점부터 쿼리할 수 있게 합니다.
- 시작. 데이터 적재는
PREPARE상태로 트랜잭션을 시작합니다. FE는TxnId를 할당하고 이를 사용자가 제공했거나 자동 생성된 Label과 연결합니다. 같은 Label로 다시 제출하면 추가 처리를 건너뛰고 원래 트랜잭션의 결과를 반환합니다. - 쓰기. BE는 데이터를 수신하고 세그먼트를 생성한 뒤 성공을 보고합니다. 대상인 모든 데이터 적재의 성공이 확인되면 트랜잭션은
PRECOMMITTED상태로 전환됩니다. - 커밋.
COMMIT(또는 두 번째 단계의txn_operation: commitHTTP 호출)은 트랜잭션을COMMITTED상태로 전환합니다. 데이터는 디스크에 저장되어 있지만 아직 읽을 수는 없습니다. - 게시. 백그라운드 데몬이 모든 복제본에
PublishVersion작업을 보냅니다. 영향을 받는 모든 tablet의 모든 복제본에서 확인 응답을 보내면 트랜잭션은VISIBLE상태에 도달합니다. - 읽기.
VISIBLE이후에 실행되는 쿼리에서는 새 행이 보입니다. 그 전에 실행된 쿼리에서는 이전 버전이 보입니다. 같은 트랜잭션에 속한 tablet에서는 torn read가 발생하지 않습니다.
진행 중 어느 단계에서든 실패하거나 클라이언트가 ROLLBACK(또는 txn_operation: abort)을 호출하면, 트랜잭션은 ABORTED 상태로 전환되고 데이터는 폐기됩니다.
빠른 시작
CREATE TABLE orders (
id INT, amount DECIMAL(10,2)
) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 4;
CREATE TABLE order_audit (
id INT, action STRING
) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 4;
BEGIN;
INSERT INTO orders VALUES (1, 99.50), (2, 149.00);
INSERT INTO order_audit VALUES (1, 'created'), (2, 'created');
COMMIT;
예상 결과
Query OK, 2 rows affected
{'label':'txn_insert_b55db21aad7451b','status':'VISIBLE','txnId':'10013'}
두 테이블은 같은 시점부터 읽을 수 있게 됩니다. 두 번째 INSERT가 실패했거나 COMMIT 전에 연결이 끊어졌다면 어느 테이블에도 새 행이 반영되지 않았을 것입니다.
Apache Doris 데이터 적재 트랜잭션은 언제 사용해야 하나요?
여러 삽입 작업을 함께 반영해야 하거나, 스트리밍 싱크에 exactly-once 처리가 필요하거나, 재시도된 데이터 적재의 중복을 애플리케이션 대신 Label을 기준으로 제거해야 할 때 Apache Doris 데이터 적재 트랜잭션을 사용하세요.
적합한 경우
- 체크포인트 간 exactly-once를 보장하기 위해 Stream Load 2PC를 사용하는 Flink 및 Spark 싱크.
- 팩트 테이블과 차원 테이블을 함께 반영해야 하는 CDC 파이프라인.
- 서로 관련된 행 배치를 하나의 단위로 추가하거나 제거하는 백필.
- 멱등 재시도가 중요하며, 클라이언트 대신 웨어하우스에서 Label을 통한 중복 제거를 보장해야 하는 워크로드.
적합하지 않은 경우
- 빈도가 높은 단일 행 삽입. 각 트랜잭션은 커밋을 위한 왕복 통신과 tablet 버전을 추가하므로, 소량 데이터 적재에서는 커밋 단계가 병목이 됩니다. 대신 Group Commit을 사용하세요.
- 두 데이터베이스에 걸친 원자성. 하나의 트랜잭션에 속한 모든 테이블은 같은 데이터베이스에 있어야 합니다.
- 클라우드 / 스토리지와 컴퓨팅이 분리된 배포 환경에서 Merge-on-Write Unique Key 테이블을 대상으로 사용하는 Stream Load 2PC. BE는 이 조합을
Status::NotSupported로 거부합니다. 온프레미스(shared-nothing) 클러스터에서는 허용됩니다. - 장기간 중복 제거. Label은 약 3일이 지나거나 데이터베이스별 항목 수가 2,000개에 도달하면 둘 중 먼저 충족된 조건에 따라 제거됩니다. 그 이후 같은 Label을 재사용해도 중복이 제거되지 않습니다. 장기간 유지되는 멱등성 키는 애플리케이션에서 추적하세요.
- 같은 트랜잭션 내에서 자신이 쓴 데이터를 읽는 경우. 각 문은 해당 문이 시작될 때 생성된 스냅샷을 기준으로 실행됩니다. 앞서 실행한
INSERT의 결과는COMMIT이후에야 보입니다.
추가 자료
- Stream Load: 2PC 방식도 지원하는 동기식 HTTP 데이터 적재 방식입니다.
- Group Commit: 명시적인
BEGIN ... COMMIT이 필요하지 않은 빈번한 소량 삽입에 적합한 도구입니다. - Kafka 및 CDC 통합: Routine Load와 Flink CDC가 이 트랜잭션 모델을 기반으로 exactly-once를 구현하는 방식을 설명합니다.
- Binlog Table Stream: 커밋된 행이 보이게 되면 생성되는 변경 피드입니다.
- 트랜잭션, 격리 및 Label 보존
- Stream Load 2PC 단계별 안내
- Flink의 Doris 실시간 쓰기가 속도와 exactly-once를 모두 보장하는 방식
- Unique Key: Merge-on-Write upsert가 동일한 데이터 적재 트랜잭션 프로토콜을 통해 커밋되는 테이블 모델입니다.