테이블 만들기
테이블에서
Distributed 테이블이 현재 서버의 테이블을 가리키는 경우 해당 테이블의 스키마(schema)를 사용할 수 있습니다:
분산 매개변수
관련 항목
- distributed_foreground_insert 설정
- 예시는 MergeTree를 참조하십시오
분산 설정
내구성 설정 (
fsync_...):- 데이터가 먼저 initiator 노드 디스크에 저장되고, 이후 백그라운드에서 세그먼트로 전송되는 백그라운드
INSERT(distributed_foreground_insert=false)에만 영향을 줍니다. INSERT성능이 크게 저하될 수 있습니다.- 분산 테이블 폴더 내부에 저장된 데이터를 삽입을 수락한 노드에 기록하는 데 영향을 줍니다. 기본 MergeTree 테이블에 대한 데이터 기록 보장이 필요하다면
system.merge_tree_settings의 내구성 설정(...fsync...)을 참조하십시오.
..._insert)에 대해서는 다음도 참조하십시오.distributed_foreground_insert설정prefer_localhost_replica설정bytes_to_throw_insert는bytes_to_delay_insert보다 먼저 처리되므로bytes_to_delay_insert보다 작은 값으로 설정하지 마십시오.
logs 클러스터의 모든 서버에 있는 default.hits 테이블에서 읽어옵니다. 데이터는 단순히 읽기만 하는 것이 아니라, 가능한 범위 내에서 원격 서버에서 부분적으로 처리되기도 합니다. 예를 들어 GROUP BY가 포함된 쿼리의 경우, 데이터는 원격 서버에서 집계되고 집계 함수의 중간 상태가 요청 서버로 전송됩니다. 그런 다음 데이터가 추가로 집계됩니다.
데이터베이스 이름 대신 문자열을 반환하는 상수 표현식을 사용할 수 있습니다. 예시: currentDatabase().
클러스터
logs라는 이름의 클러스터를 정의하며, 2개의 세그먼트로 구성되고 각 세그먼트에는 2개의 레플리카가 포함됩니다. 세그먼트는 서로 다른 데이터 파트를 포함하는 서버를 의미합니다(모든 데이터를 읽으려면 모든 세그먼트에 접근해야 합니다). 레플리카는 데이터를 복제하는 서버입니다(모든 데이터를 읽으려면 레플리카 중 어느 하나에 접근하면 됩니다).
클러스터 이름에는 점을 포함할 수 없습니다.
각 서버에 대해 host, port와 선택적으로 user, password, secure, compression, bind_host 매개변수를 지정합니다:
레플리카를 지정하면 읽을 때 각 세그먼트마다 사용 가능한 레플리카 중 하나가 선택됩니다. 로드 밸런싱 알고리즘(어느 레플리카에 접근할지에 대한 우선순위)을 구성할 수 있습니다. 자세한 내용은 load_balancing 설정을 참조하십시오. 서버와의 연결이 설정되지 않으면 짧은 timeout으로 연결을 시도합니다. 연결에 실패하면 다음 레플리카가 선택되며, 이 과정이 모든 레플리카에 대해 반복됩니다. 모든 레플리카에 대한 연결 시도가 실패하면 같은 방식으로 여러 차례 다시 시도합니다. 이는 복원력 향상에 도움이 되지만 완전한 장애 허용을 제공하지는 않습니다. 원격 서버가 연결은 수락하더라도 실제로는 동작하지 않거나 성능이 저하된 상태일 수 있기 때문입니다.
세그먼트는 하나만 지정할 수도 있고(이 경우 쿼리 처리는 distributed가 아니라 remote라고 해야 합니다), 원하는 수만큼 지정할 수도 있습니다. 각 세그먼트에서는 레플리카를 하나 이상 원하는 수만큼 지정할 수 있습니다. 세그먼트마다 레플리카 수를 다르게 지정할 수 있습니다.
구성에는 원하는 만큼 많은 클러스터를 지정할 수 있습니다.
클러스터를 확인하려면
system.clusters 테이블을 사용하십시오.
Distributed 엔진을 사용하면 클러스터를 로컬 서버처럼 사용할 수 있습니다. 하지만 클러스터 구성은 동적으로 지정할 수 없으며, 서버 구성 파일에서 설정해야 합니다. 일반적으로 클러스터의 모든 서버는 동일한 클러스터 구성을 사용합니다(필수는 아닙니다). 구성 파일의 클러스터는 서버를 다시 시작하지 않고도 즉시 업데이트됩니다.
매번 알 수 없는 세트의 세그먼트와 레플리카로 쿼리를 보내야 한다면 Distributed 테이블을 만들 필요가 없습니다. 대신 remote 테이블 함수를 사용하십시오. 자세한 내용은 테이블 함수 섹션을 참조하십시오.
데이터 쓰기
Distributed 테이블이 가리키는 클러스터의 원격 테이블에 직접 INSERT SQL 문을 실행합니다. 이 방법은 가장 유연한 방식으로, 도메인 요구 사항 때문에 단순하지 않은 경우를 포함해 어떤 세그먼트 분할 방식이든 사용할 수 있습니다. 또한 데이터가 서로 다른 세그먼트에 완전히 독립적으로 기록될 수 있으므로 가장 최적의 방법이기도 합니다.
둘째, Distributed 테이블에 INSERT SQL 문을 실행할 수 있습니다. 이 경우 테이블이 삽입된 데이터를 서버 전체에 걸쳐 직접 분산합니다. Distributed 테이블에 쓰려면 sharding_key 매개변수가 구성되어 있어야 합니다(세그먼트가 하나뿐인 경우는 예외).
각 세그먼트에는 구성 파일에서 <weight>를 정의할 수 있습니다. 기본값은 1입니다. 데이터는 세그먼트 가중치에 비례하여 각 세그먼트에 분산됩니다. 모든 세그먼트의 가중치를 합산한 다음, 각 세그먼트의 가중치를 전체 합으로 나누어 각 세그먼트의 비율을 결정합니다. 예를 들어 세그먼트가 두 개이고 첫 번째 가중치가 1, 두 번째 가중치가 2이면 첫 번째에는 삽입된 행의 3분의 1(1 / 3)이, 두 번째에는 3분의 2(2 / 3)가 전송됩니다.
각 세그먼트에는 구성 파일에서 internal_replication 매개변수를 정의할 수 있습니다. 이 매개변수가 true로 설정되면 쓰기 작업은 정상 상태인 첫 번째 레플리카를 선택해 여기에 데이터를 씁니다. Distributed 테이블의 기반 테이블이 복제된 테이블인 경우(예: Replicated*MergeTree 테이블 엔진) 이 방식을 사용하십시오. 테이블 레플리카 중 하나가 쓰기를 수신하고, 다른 레플리카에는 자동으로 복제됩니다.
internal_replication이 false(기본값)로 설정되면 데이터는 모든 레플리카에 기록됩니다. 이 경우 Distributed 테이블이 자체적으로 데이터를 복제합니다. 이 방식은 복제된 테이블을 사용하는 것보다 바람직하지 않습니다. 레플리카의 일관성을 확인하지 않기 때문에 시간이 지나면 서로 약간 다른 데이터를 포함하게 됩니다.
데이터의 한 행이 전송될 세그먼트를 선택하기 위해 세그먼트 분할 표현식을 분석하고, 이를 세그먼트의 총 가중치로 나눈 나머지를 구합니다. 그러면 해당 행은 prev_weights부터 prev_weights + weight까지의 나머지 반개구간에 대응하는 세그먼트로 전송됩니다. 여기서 prev_weights는 더 작은 번호를 가진 세그먼트들의 총 가중치이고, weight는 현재 세그먼트의 가중치입니다. 예를 들어 세그먼트가 두 개이고 첫 번째 가중치가 9, 두 번째 가중치가 10이면 범위 [0, 9)의 나머지는 첫 번째 세그먼트로, 범위 [9, 19)의 나머지는 두 번째 세그먼트로 전송됩니다.
세그먼트 분할 표현식은 상수와 테이블 컬럼으로 구성된, 정수를 반환하는 어떤 표현식이든 될 수 있습니다. 예를 들어 데이터를 무작위로 분산하려면 rand() 표현식을 사용할 수 있고, 사용자 ID를 나눈 나머지에 따라 분산하려면 UserID를 사용할 수 있습니다(이 경우 한 사용자의 데이터는 하나의 세그먼트에만 저장되므로 사용자 기준 IN 및 JOIN 실행이 단순해집니다). 특정 컬럼의 분포가 충분히 고르지 않다면 intHash64(UserID)와 같은 해시 함수로 감쌀 수 있습니다.
나눗셈의 단순한 나머지를 사용하는 방식은 제한적인 세그먼트 분할 방법이며, 항상 적절한 것은 아닙니다. 이 방식은 중간 규모 및 대규모 데이터 볼륨(수십 대의 서버)에는 잘 작동하지만, 매우 큰 데이터 볼륨(수백 대 이상의 서버)에는 적합하지 않습니다. 후자의 경우 Distributed 테이블의 항목을 사용하기보다 도메인 요구 사항에 맞는 세그먼트 분할 방식을 사용하십시오.
다음과 같은 경우에는 세그먼트 분할 방식에 특히 주의를 기울여야 합니다.
- 특정 키로 데이터를 결합해야 하는(
IN또는JOIN) 쿼리를 사용하는 경우입니다. 데이터가 이 키를 기준으로 세그먼트 분할되어 있다면GLOBAL IN또는GLOBAL JOIN대신 로컬IN또는JOIN을 사용할 수 있으며, 훨씬 더 효율적입니다. - 많은 수의 서버(수백 대 이상)에서 많은 수의 작은 쿼리를 사용하는 경우입니다. 예를 들어 개별 클라이언트(예: 웹사이트, 광고주 또는 파트너)의 데이터에 대한 쿼리입니다. 작은 쿼리가 전체 클러스터에 영향을 주지 않도록 하려면 하나의 클라이언트 데이터를 하나의 세그먼트에 두는 것이 합리적입니다. 또는 2단계 세그먼트 분할을 구성할 수도 있습니다. 즉, 전체 클러스터를 “레이어”로 나누고, 각 레이어는 여러 세그먼트로 구성될 수 있습니다. 하나의 클라이언트 데이터는 하나의 레이어에 위치하지만, 필요에 따라 해당 레이어에 세그먼트를 추가할 수 있고, 그 내부에서는 데이터가 무작위로 분산됩니다. 각 레이어마다
Distributed테이블을 만들고, 전역 쿼리를 위한 단일 공유 분산 테이블을 추가로 만듭니다.
Distributed 엔진은 삽입된 데이터가 들어 있는 각 파일을 개별적으로 전송하지만, distributed_background_insert_batch 설정을 사용하면 파일을 배치로 전송할 수 있습니다. 이 설정은 로컬 서버와 네트워크 리소스를 더 효율적으로 활용해 클러스터 성능을 향상합니다. 테이블 디렉터리의 파일 목록(전송을 기다리는 데이터)을 확인하여 데이터가 성공적으로 전송되었는지 점검해야 합니다: /var/lib/clickhouse/data/database/table/. 백그라운드 작업을 수행하는 스레드 수는 background_distributed_schedule_pool_size 설정으로 지정할 수 있습니다.
Distributed 테이블에 INSERT한 후 서버가 더 이상 존재하지 않게 되었거나 비정상적으로 재시작된 경우(예: 하드웨어 장애)에는 삽입된 데이터가 손실될 수 있습니다. 테이블 디렉터리에서 손상된 데이터 파트가 감지되면 broken 하위 디렉터리로 이동되며 더 이상 사용되지 않습니다.
데이터 읽기
Distributed 테이블을 쿼리할 때 SELECT 쿼리는 모든 세그먼트로 전송되며, 데이터가 세그먼트 간에 어떻게 분산되어 있든 관계없이 동작합니다(완전히 무작위로 분산되어 있어도 됩니다). 새 세그먼트를 추가할 때 기존 데이터를 그 세그먼트로 옮길 필요는 없습니다. 대신 더 높은 가중치를 사용해 새 데이터를 해당 세그먼트에 기록할 수 있습니다. 그러면 데이터가 다소 불균등하게 분산될 수 있지만, 쿼리는 여전히 정확하고 효율적으로 동작합니다.
max_parallel_replicas 옵션이 활성화되면 단일 세그먼트 내의 모든 레플리카에서 쿼리 처리가 병렬로 수행됩니다. 자세한 내용은 max_parallel_replicas 섹션을 참조하십시오.
분산 in 및 global in 쿼리가 처리되는 방식에 관해 자세히 알아보려면 이 문서를 참조하십시오.
가상 컬럼
_Shard_num
_shard_num — 테이블 system.clusters의 shard_num 값을 포함합니다. 유형: UInt32.
remote 및 [cluster](../../../sql-reference/table-functions/cluster.md) 테이블 함수는 내부적으로 임시 분산 테이블을 생성하므로 _shard_num`도 여기에서 사용할 수 있습니다.