트랜잭션

트랜잭션 (ACID) 지원 (Transactional (ACID) support)

이 페이지는 ClickHouse 분석 데이터베이스의 트랜잭션 보장을 설명합니다. 삽입 보장과 여러 문장에 걸친 트랜잭션의 실험적 지원을 다룹니다.

출처: 문서

본문

이 페이지는 ClickHouse 분석 데이터베이스의 트랜잭션 보장을 설명하며, 삽입 보장과 여러 문장에 걸친 트랜잭션의 실험적 지원을 포함합니다.

트랜잭션 워크로드(OLTP)용 데이터베이스를 찾고 계신가요? 개별 레코드에 대한 빈번한 읽기·쓰기가 필요한 애플리케이션에는 ClickHouse Managed Postgres를 애플리케이션의 시스템 오브 레코드로 사용하고, ClickPipes로 커밋된 변경 사항을 복제해 분석용 ClickHouse를 추가하세요. Postgres와 ClickHouse가 어떻게 함께 동작하는지 배워 보세요.

ClickHouse로의 삽입의 원자성, 격리성, 내구성을 확인 중이라면 아래 사례를 계속 살펴보세요.

Case 1: MergeTree* 패밀리의 한 테이블, 한 파티션으로 INSERT

삽입된 행이 단일 블록으로 묶여 삽입된다면 이것은 트랜잭션적(ACID)입니다(Notes 참고):

  • 원자적(Atomic): INSERT는 전체가 성공하거나 거부됩니다: 클라이언트에 확인이 보내지면 모든 행이 삽입된 것이고, 오류가 보내지면 행이 하나도 삽입되지 않은 것입니다.
  • 일관적(Consistent): 테이블 제약 조건이 위반되지 않으면 INSERT의 모든 행이 삽입되고 INSERT가 성공합니다. 제약 조건이 위반되면 행이 삽입되지 않습니다.
  • 격리적(Isolated): 동시 클라이언트는 테이블의 일관된 스냅샷을 관측합니다 — INSERT 시도 전의 상태이거나 성공적 INSERT 후의 상태이며, 부분 상태는 보이지 않습니다. 다른 트랜잭션 안의 클라이언트는 스냅샷 격리(snapshot isolation)를, 트랜잭션 밖의 클라이언트는 read uncommitted 격리 수준을 가집니다.
  • 내구적(Durable): 성공적 INSERT는 클라이언트에 응답하기 전에 파일시스템에 기록되며, 단일 복제본 또는 여러 복제본(insert_quorum 설정으로 제어)에서 그렇게 되고, ClickHouse는 OS에 스토리지 미디어의 파일시스템 데이터 동기화를 요청할 수 있습니다(fsync_after_insert 설정으로 제어).
  • 머티얼라이즈드 뷰가 관련되면 한 문장으로 여러 테이블에 INSERT하는 것이 가능합니다(클라이언트의 INSERT는 연관 머티얼라이즈드 뷰를 가진 테이블로).

Case 2: MergeTree* 패밀리의 한 테이블, 여러 파티션으로 INSERT

위 Case 1과 같으며, 다음 세부 사항이 있습니다:

  • 테이블에 파티션이 많고 INSERT가 많은 파티션을 덮으면, 각 파티션으로의 삽입은 그 자체로 트랜잭션적입니다.

Case 3: MergeTree* 패밀리의 한 분산 테이블로 INSERT

위 Case 1과 같으며, 다음 세부 사항이 있습니다:

  • Distributed 테이블로의 INSERT는 전체적으로 트랜잭션적이지 않지만, 각 샤드로의 삽입은 트랜잭션적입니다.

Case 4: Buffer 테이블 사용

  • Buffer 테이블로의 삽입은 원자적이지도, 격리적이지도, 일관적이지도, 내구적이지도 않습니다.

Case 5: async_insert 사용

위 Case 1과 같으며, 다음 세부 사항이 있습니다:

  • async_insert가 활성화되고 wait_for_async_insert가 1(기본값)로 설정되어도 원자성이 보장되지만, wait_for_async_insert가 0으로 설정되면 원자성이 보장되지 않습니다.

참고사항 (Notes)

  • 클라이언트에서 어떤 데이터 포맷으로 삽입된 행은 다음 경우 단일 블록으로 묶입니다:
    • 삽입 포맷이 행 기반(CSV, TSV, Values, JSONEachRow 등)이고 데이터가 max_insert_block_size 행(기본 약 1,000,000) 미만이거나, 병렬 파싱(기본 활성)이 사용될 때 min_chunk_bytes_for_parallel_parsing 바이트(기본 10MB) 미만일 때.
    • 삽입 포맷이 컬럼 기반(Native, Parquet, ORC 등)이고 데이터가 데이터 블록 하나만 포함할 때.
  • 삽입된 블록의 크기는 일반적으로 많은 설정에 의존할 수 있습니다(예: max_block_size, max_insert_block_size, min_insert_block_size_rows, min_insert_block_size_bytes, preferred_block_size_bytes 등).
  • 클라이언트가 서버로부터 응답을 받지 못하면 트랜잭션이 성공했는지 알 수 없으며, 정확히-한 번(exactly-once) 삽입 속성을 사용해 트랜잭션을 반복할 수 있습니다.
  • ClickHouse는 동시 트랜잭션에 대해 내부적으로 스냅샷 격리와 함께 MVCC를 사용합니다.
  • 모든 ACID 속성은 서버가 죽거나 크래시되는 경우에도 유효합니다.
  • 일반적인 구성에서는 내구성 있는 삽입을 보장하기 위해 다른 AZ로의 insert_quorum 또는 fsync를 활성화해야 합니다.
  • ACID 용어의 "consistency"는 분산 시스템의 의미론을 다루지 않습니다. https://jepsen.io/consistency를 참고하세요. 이것은 다른 설정(select_sequential_consistency)으로 제어됩니다.
  • 이 설명은 여러 테이블, 머티얼라이즈드 뷰, 여러 SELECT 등에 대해 완전한 기능의 트랜잭션을 허용하는 새 트랜잭션 기능을 다루지 않습니다(다음 "Transactions, Commit, and Rollback" 섹션 참고).

트랜잭션, 커밋, 롤백 (Transactions, Commit, and Rollback)

이 문서 상단에 설명된 기능 외에도 ClickHouse는 트랜잭션, 커밋, 롤백 기능에 대한 실험적 지원을 가지고 있습니다.

애플리케이션 워크로드에는 ClickHouse Managed Postgres를 고려하세요.

요구사항

  • ClickHouse Keeper 또는 ZooKeeper를 배포해 트랜잭션을 추적합니다.
  • Atomic DB만(기본값).
  • 비복제 MergeTree 테이블 엔진만.
  • config.d/transactions.xml에 이 설정을 추가해 실험적 트랜잭션 지원을 활성화합니다:
<clickhouse>
  <allow_experimental_transactions>1</allow_experimental_transactions>
</clickhouse>

참고사항

  • 이것은 실험적 기능이며 변경이 예상됩니다.
  • 트랜잭션 중 예외가 발생하면 트랜잭션을 커밋할 수 없습니다. 여기에는 오타로 인한 UNKNOWN_FUNCTION 예외를 포함한 모든 예외가 포함됩니다.
  • 중첩 트랜잭션은 지원되지 않습니다. 현재 트랜잭션을 끝내고 새 트랜잭션을 시작하세요.

구성

이 예제들은 ClickHouse Keeper가 활성화된 단일 노드 ClickHouse 서버입니다.

실험적 트랜잭션 지원 활성화

/etc/clickhouse-server/config.d/transactions.xml

<clickhouse>
    <allow_experimental_transactions>1</allow_experimental_transactions>
</clickhouse>
ClickHouse Keeper가 활성화된 단일 ClickHouse 서버 노드의 기본 구성

ClickHouse 서버와 적절한 ClickHouse Keeper 노드 쿼럼 배포에 대한 자세한 내용은 deployment 문서를 참고하세요. 여기 표시된 구성은 실험 목적입니다.

/etc/clickhouse-server/config.d/config.xml

<clickhouse replace="true">
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <display_name>node 1</display_name>
    <listen_host>0.0.0.0</listen_host>
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <zookeeper>
        <node>
            <host>clickhouse-01</host>
            <port>9181</port>
        </node>
    </zookeeper>
    <keeper_server>
        <tcp_port>9181</tcp_port>
        <server_id>1</server_id>
        <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
        <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
        <coordination_settings>
            <operation_timeout_ms>10000</operation_timeout_ms>
            <session_timeout_ms>30000</session_timeout_ms>
            <raft_logs_level>information</raft_logs_level>
        </coordination_settings>
        <raft_configuration>
            <server>
                <id>1</id>
                <hostname>clickhouse-keeper-01</hostname>
                <port>9234</port>
            </server>
        </raft_configuration>
    </keeper_server>
</clickhouse>

예제

실험적 트랜잭션이 활성화되었는지 확인

BEGIN TRANSACTION 또는 START TRANSACTION 다음에 ROLLBACK을 발행해 실험적 트랜잭션이 활성화되었고, 트랜잭션 추적에 사용되는 ClickHouse Keeper가 활성화되었는지 확인하세요.

BEGIN TRANSACTION
Ok.

다음 오류가 보이면 구성 파일을 확인해 allow_experimental_transactions1(또는 0이나 false가 아닌 값)로 설정되었는지 확인하세요.

Code: 48. DB::Exception: Received from localhost:9000.
DB::Exception: Transactions are not supported.
(NOT_IMPLEMENTED)

다음을 발행해 ClickHouse Keeper도 확인할 수 있습니다:

echo ruok | nc localhost 9181

ClickHouse Keeper는 imok으로 응답해야 합니다.

ROLLBACK
Ok.
테스트용 테이블 생성

테이블 생성은 트랜잭션적이지 않습니다. 이 DDL 쿼리를 트랜잭션 밖에서 실행하세요.

CREATE TABLE mergetree_table
(
    `n` Int64
)
ENGINE = MergeTree
ORDER BY n
Ok.
트랜잭션 시작하고 행 삽입
BEGIN TRANSACTION
Ok.
INSERT INTO mergetree_table FORMAT Values (10)
Ok.
SELECT *
FROM mergetree_table
┌──n─┐
│ 10 │
└────┘

트랜잭션 안에서 테이블을 쿼리할 수 있고, 아직 커밋되지 않았음에도 행이 삽입되었음을 볼 수 있습니다.

트랜잭션 롤백하고 다시 쿼리

트랜잭션이 롤백되었는지 확인합니다:

ROLLBACK
Ok.
SELECT *
FROM mergetree_table
Ok.

0 rows in set. Elapsed: 0.002 sec.
트랜잭션 완료하고 다시 쿼리
BEGIN TRANSACTION
Ok.
INSERT INTO mergetree_table FORMAT Values (42)
Ok.
COMMIT
Ok. Elapsed: 0.002 sec.
SELECT *
FROM mergetree_table
┌──n─┐
│ 42 │
└────┘

트랜잭션 인트로스펙션

system.transactions 테이블을 쿼리해 트랜잭션을 조사할 수 있지만, 트랜잭션 중인 세션에서는 그 테이블을 쿼리할 수 없음에 주의하세요. 두 번째 clickhouse client 세션을 열어 그 테이블을 쿼리하세요.

SELECT *
FROM system.transactions
FORMAT Vertical
Row 1:
──────
tid:         (33,61,'51e60bce-6b82-4732-9e1d-b40705ae9ab8')
tid_hash:    11240433987908122467
elapsed:     210.017820947
is_readonly: 1
state:       RUNNING

더 많은 세부 사항

이 meta issue를 참고해 훨씬 더 광범위한 테스트를 찾고 진행 상황을 최신으로 유지하세요.

더 알아보기 (Learn more)