소개
이 가이드에서는 먼저 ClickHouse가 분산 테이블을 통해 여러 세그먼트에 쿼리를 어떻게 분산하는지 설명하고, 이어서 쿼리 실행에 여러 레플리카를 어떻게 활용할 수 있는지 설명합니다.shared-nothing 아키텍처에서는 일반적으로 클러스터를 여러 세그먼트로 나누며, 각 세그먼트는 전체 데이터의 부분 집합을 포함합니다. 이 세그먼트들 위에는 분산 테이블이 있어 전체 데이터에 대한 단일한 뷰를 제공합니다. 읽기 요청은 로컬 테이블로 보낼 수 있습니다. 이 경우 쿼리 실행은 지정된 세그먼트에서만 발생합니다. 또는 분산 테이블로 보낼 수도 있으며, 이 경우 각 세그먼트가 해당 쿼리를 실행합니다. 분산 테이블에 쿼리가 수행된 서버는 데이터를 집계한 뒤 클라이언트에 응답합니다: 위 그림은 클라이언트가 분산 테이블에 쿼리를 실행할 때 어떤 일이 일어나는지 보여줍니다:
- SELECT 쿼리는 임의의 노드에 있는 분산 테이블로 전송됩니다 (라운드 로빈 전략을 사용하거나, 로드 밸런서가 특정 서버로 라우팅한 경우). 이 노드는 이제 코디네이터 역할을 합니다.
- 이 노드는 분산 테이블에 지정된 정보를 바탕으로 쿼리를 실행해야 하는 각 세그먼트를 찾고, 쿼리를 각 세그먼트로 전송합니다.
- 각 세그먼트는 데이터를 로컬에서 읽고, 필터링하고, 집계한 다음 머지 가능한 상태를 코디네이터에 다시 보냅니다.
- 코디네이터 역할을 하는 노드는 데이터를 머지한 다음 응답을 클라이언트에 다시 보냅니다.
세그먼트 분할이 없는 아키텍처
병렬 레플리카 소개
- 클라이언트의 쿼리는 로드 밸런서를 거쳐 하나의 노드로 전송됩니다. 이 노드는 해당 쿼리의 코디네이터가 됩니다.
- 이 노드는 각 파트의 인덱스를 분석하고 처리할 적절한 파트와 그래뉼을 선택합니다.
- 코디네이터는 워크로드를 여러 레플리카에 할당할 수 있는 그래뉼 집합으로 분할합니다.
- 각 그래뉼 집합은 해당 레플리카에서 처리되며, 처리가 끝나면 머지 가능한 상태가 코디네이터로 전송됩니다.
- 마지막으로 코디네이터가 레플리카의 모든 결과를 머지한 뒤 클라이언트에 응답을 반환합니다.
- 일부 레플리카는 사용 불가능할 수 있습니다.
- ClickHouse의 복제는 비동기식이므로 특정 시점에는 일부 레플리카가 동일한 파트를 가지고 있지 않을 수 있습니다.
- 레플리카 간 테일 지연 시간을 어떻게든 처리해야 합니다.
- 파일 시스템 캐시는 각 레플리카의 활동에 따라 달라지므로, 작업을 무작위로 할당하면 캐시 지역성 측면에서 성능이 최적이 아닐 수 있습니다.
Announcements
- 클라이언트의 쿼리는 로드 밸런서를 거쳐 하나의 노드로 전달됩니다. 이 노드는 해당 쿼리의 코디네이터가 됩니다.
- coordinating node는 클러스터의 모든 레플리카로부터 announcement를 받기 위한 요청을 보냅니다. 레플리카는 테이블의 현재 파트 집합을 서로 약간 다르게 보고 있을 수 있습니다. 따라서 잘못된 스케줄링 결정을 피하려면 이 정보를 수집해야 합니다.
- 그런 다음 coordinating node는 announcement를 바탕으로 각 레플리카에 할당할 수 있는 그래뉼 집합을 정의합니다. 예를 들어 여기서는 레플리카 2가 자신의 announcement에 파트 3을 포함하지 않았기 때문에, 파트 3의 그래뉼은 레플리카 2에 할당되지 않은 것을 볼 수 있습니다. 또한 레플리카 3은 announcement를 제공하지 않았기 때문에 어떤 작업도 할당되지 않았다는 점에 유의하십시오.
- 각 레플리카가 자신에게 할당된 그래뉼 부분 집합에 대해 쿼리를 처리하고, 머지 가능한 상태를 코디네이터로 다시 보내면 코디네이터가 결과를 머지한 후 응답이 클라이언트로 전송됩니다.
동적 조정
- 레플리카는 작업을 처리할 수 있음을 코디네이터 노드에 알리며, 처리 가능한 작업량도 지정할 수 있습니다.
- 코디네이터가 레플리카에 작업을 할당합니다.
- 레플리카 1과 2는 작업을 매우 빠르게 끝낼 수 있습니다. 이들은 코디네이터 노드에 다른 작업을 요청합니다.
- 코디네이터가 레플리카 1과 2에 새로운 작업을 할당합니다.
- 이제 모든 레플리카가 작업 처리를 마쳤습니다. 이들은 더 많은 작업을 요청합니다.
- 코디네이터는 announcement를 사용해 남아 있는 작업이 무엇인지 확인하지만, 남은 작업은 없습니다.
- 코디네이터는 모든 작업이 처리되었음을 레플리카에 알립니다. 이제 머지 가능한 모든 상태를 머지한 뒤 쿼리에 응답합니다.
캐시 지역성 관리
| 레플리카 1 | 레플리카 2 | 레플리카 3 | |
|---|---|---|---|
| 파트 1 | g1, g6, g7 | g2, g4, g5 | g3 |
| 파트 2 | g1 | g2, g4, g5 | g3 |
| 파트 3 | g1, g6 | g2, g4, g5 | g3 |
max_parallel_replicas가
레플리카 수보다 적으면, 쿼리 실행을 위해 무작위 레플리카가 선택됩니다.
작업 스틸링
제한 사항
아래에 나열된 제한 사항에 포함되지 않는 문제를 발견했고,
원인이 병렬 레플리카에 있다고 의심되면 GitHub에서
레이블
comp-parallel-replicas를 사용해 이슈를 등록하십시오.| Limitation | Description |
|---|---|
| 복잡한 쿼리 | 현재 병렬 레플리카는 단순한 쿼리에서는 비교적 잘 작동합니다. CTE, 서브쿼리, JOIN, 평탄하지 않은 쿼리 구조 등과 같은 복잡성 계층은 쿼리 성능에 부정적인 영향을 줄 수 있습니다. |
| 작은 쿼리 | 처리하는 행 수가 많지 않은 쿼리를 실행하는 경우, 레플리카 간 조정을 위한 네트워크 시간 때문에 쿼리 실행에 추가 사이클이 발생할 수 있으므로 여러 레플리카에서 실행하더라도 성능이 더 좋아지지 않을 수 있습니다. 다음 설정을 사용하면 이러한 문제를 줄일 수 있습니다: parallel_replicas_min_number_of_rows_per_replica. |
| FINAL과 함께 사용하면 병렬 레플리카가 비활성화됨 | |
| 병렬 레플리카와 함께 프로젝션은 사용되지 않음 | |
| 카디널리티가 높은 데이터와 복잡한 집계 | 많은 데이터를 전송해야 하는 카디널리티가 높은 집계는 쿼리를 크게 느리게 만들 수 있습니다. |
| 새 분석기와의 호환성 | 새 분석기는 특정 시나리오에서 쿼리 실행 속도를 크게 늦추거나 높일 수 있습니다. |
| Setting | Description |
|---|---|
enable_parallel_replicas | 0: 비활성화1: 활성화 2: 병렬 레플리카 사용을 강제하며, 사용되지 않으면 예외를 발생시킵니다. |
cluster_for_parallel_replicas | 병렬 레플리카에 사용할 클러스터 이름입니다. ClickHouse Cloud를 사용하는 경우 default를 사용합니다. |
max_parallel_replicas | 여러 레플리카에서 쿼리를 실행할 때 사용할 최대 레플리카 수입니다. 클러스터의 레플리카 수보다 작은 값을 지정하면 노드가 무작위로 선택됩니다. 이 값은 수평 스케일링을 고려해 오버커밋할 수도 있습니다. |
parallel_replicas_min_number_of_rows_per_replica | 처리해야 하는 행 수를 기준으로 사용할 레플리카 수를 제한하는 데 도움이 됩니다. 사용되는 레플리카 수는 다음과 같이 정의됩니다. estimated rows to read / min_number_of_rows_per_replica |
enable_analyzer | 병렬 레플리카를 사용한 쿼리 실행은 분석기가 활성화된 경우에만 지원됩니다 |
병렬 레플리카 문제 조사
system.query_log 테이블에서 확인할 수 있습니다. 또한
system.events
테이블을 보면 서버에서 발생한 모든 이벤트를 확인할 수 있으며,
clusterAllReplicas 테이블 함수를 사용하면 모든 레플리카의 테이블을 확인할 수 있습니다
(클라우드 사용자인 경우 default를 사용하십시오).
Query
응답
응답
Response
system.text_log 테이블에는 병렬 레플리카를 사용한 쿼리 실행에 대한 정보도 포함되어 있습니다:
Query
응답
응답
Response
EXPLAIN PIPELINE도 사용할 수 있습니다. 이는 ClickHouse가
쿼리를 어떤 방식으로 실행하는지와 쿼리
실행에 어떤 리소스가 사용되는지를 보여줍니다. 다음 쿼리를 예시로 살펴보겠습니다:
EXPLAIN PIPELINE (without parallel replica)
EXPLAIN PIPELINE (with parallel replica)