현재는 이 방법을 사용해 원격 디스크 I/O와 CPU를 스케줄링할 수 있습니다. 유연한 메모리 제한에 대해서는 Memory overcommit을 참조하십시오.
디스크 구성
storage_configuration입니다:
특정 디스크에 대해 IO 스케줄링을 활성화하려면 storage configuration에서 read_resource 및/또는 write_resource를 지정해야 합니다. 이렇게 하면 지정된 디스크의 각 읽기 및 쓰기 요청에 어떤 리소스를 사용할지 ClickHouse에 알려줄 수 있습니다. 읽기 리소스와 쓰기 리소스는 동일한 리소스 이름을 참조할 수 있으며, 이는 로컬 SSD 또는 HDD에서 유용합니다. 여러 서로 다른 디스크가 동일한 리소스를 참조할 수도 있으며, 이는 원격 디스크에서 유용합니다. 예를 들어 “production” 워크로드와 “development” 워크로드 간에 네트워크 대역폭을 공정하게 분배하려는 경우에 유용합니다.
예시:
워크로드 마킹
workload를 지정할 수 있습니다. workload가 설정되지 않으면 “default” 값이 사용됩니다. 설정 프로필을 사용하면 다른 값으로 지정할 수도 있습니다. 특정 사용자의 모든 쿼리에 workload 설정의 고정값이 적용되게 하려면 설정 제약 조건을 사용해 workload를 상수로 만들 수 있습니다.
백그라운드 작업에도 workload 설정을 할당할 수 있습니다. 머지와 뮤테이션은 각각 merge_workload 및 mutation_workload 서버 설정을 사용합니다. 이 값은 특정 테이블에 대해 merge_workload 및 mutation_workload MergeTree 설정으로 재정의할 수도 있습니다.
“production”과 “development”라는 두 가지 서로 다른 워크로드가 있는 시스템의 예시를 살펴보겠습니다.
리소스 스케줄링 계층 구조
inflight_limit(제약) - 동시에 처리 중인 요청 수가max_requests를 초과하거나 총 비용이max_cost를 초과하면 차단합니다. 단일 자식만 가질 수 있습니다.bandwidth_limit(제약) - 현재 대역폭이max_speed를 초과하거나(0은 무제한 의미), 버스트가max_burst를 초과하면 차단합니다(기본값은max_speed와 같음). 단일 자식만 가질 수 있습니다.fair(정책) - max-min 공정성에 따라 자식 노드 중 하나에서 다음에 처리할 요청을 선택합니다. 자식 노드는weight를 지정할 수 있습니다(기본값은 1).priority(정책) - 정적 우선순위에 따라 자식 노드 중 하나에서 다음에 처리할 요청을 선택합니다(값이 낮을수록 우선순위가 높음). 자식 노드는priority를 지정할 수 있습니다(기본값은 0).fifo(큐) - 리소스 용량을 초과한 요청을 보관할 수 있는 계층 구조의 리프 노드입니다.
inflight_limit를 사용해야 합니다. max_requests 또는 max_cost 값이 너무 낮으면 리소스를 충분히 활용하지 못할 수 있습니다. 반대로 값이 너무 높으면 스케줄러 내부의 큐가 비게 될 수 있고, 그 결과 하위 트리에서 정책이 무시될 수 있습니다(공정성이 깨지거나 우선순위가 무시됨). 한편 리소스를 과도한 사용으로부터 보호하려면 bandwidth_limit를 사용해야 합니다. 이 노드는 duration초 동안 소비된 리소스 양이 max_burst + max_speed * duration바이트를 초과하면 스로틀링합니다. 동일한 리소스에 두 개의 bandwidth_limit 노드를 사용하면, 짧은 인터벌의 최대 대역폭과 더 긴 인터벌의 평균 대역폭을 각각 제한할 수 있습니다.
다음 예시는 그림에 표시된 IO 스케줄링 계층을 정의하는 방법을 보여줍니다:
워크로드 분류기
workload를 특정 리소스에 사용할 리프 큐에 매핑하는 방식을 정의하는 데 사용됩니다. 현재 워크로드 분류는 단순하며, 정적 매핑만 지원됩니다.
예시:
워크로드 계층 구조
CREATE RESOURCE로 생성된 모든 리소스는 동일한 계층 구조를 공유하지만, 일부 측면에서는 서로 다를 수 있습니다. CREATE WORKLOAD로 생성된 각 워크로드에는 각 리소스마다 자동으로 생성되는 몇 개의 스케줄링 노드가 유지됩니다. 하위 워크로드는 다른 상위 워크로드 내부에 생성할 수 있습니다. 다음은 위의 XML 구성과 정확히 동일한 계층 구조를 정의하는 예시입니다:
SETTINGS workload = 'name'에서 사용할 수 있습니다.
워크로드를 사용자 지정하려면 다음 설정을 사용할 수 있습니다.
priority- 형제 워크로드는 정적 우선순위 값에 따라 처리됩니다(값이 낮을수록 우선순위가 높습니다).weight- 동일한 정적 우선순위를 가진 형제 워크로드는 가중치에 따라 리소스를 공유합니다.max_io_requests- 이 워크로드에서 동시 IO 요청 수의 한도입니다.max_bytes_inflight- 이 워크로드에서 동시 요청의 진행 중인 총 바이트 수 한도입니다.max_bytes_per_second- 이 워크로드의 바이트 읽기 또는 쓰기 속도 한도입니다.max_burst_bytes- 스로틀링되지 않고 워크로드가 처리할 수 있는 최대 바이트 수입니다(각 리소스별로 독립적입니다).max_concurrent_threads- 이 워크로드의 쿼리에 사용할 수 있는 동시 스레드 수 한도입니다.max_concurrent_threads_ratio_to_cores-max_concurrent_threads와 동일하지만, 사용 가능한 CPU 코어 수를 기준으로 정규화됩니다.max_cpus- 이 워크로드의 쿼리를 처리하는 데 사용할 수 있는 CPU 코어 수 한도입니다.max_cpu_share-max_cpus와 동일하지만, 사용 가능한 CPU 코어 수를 기준으로 정규화됩니다.max_burst_cpu_seconds-max_cpus로 인해 스로틀링되지 않고 워크로드가 소비할 수 있는 최대 CPU 초 수입니다.
max_bytes_per_second = 10485760인 워크로드는 각 읽기 및 쓰기 리소스에 대해 각각 10 MB/s의 대역폭 한도를 가집니다. 읽기와 쓰기에 공통 한도가 필요하다면 READ 및 WRITE 액세스에 동일한 리소스를 사용하는 것을 고려하십시오.
리소스별로 서로 다른 워크로드 계층 구조를 지정하는 방법은 없습니다. 하지만 특정 리소스에 대해서는 다른 워크로드 설정 값을 지정할 수 있습니다:
CREATE OR REPLACE WORKLOAD 쿼리를 사용하십시오.
워크로드 설정은 적절한 스케줄링 노드 집합으로 변환됩니다. 더 하위 수준의 세부 사항은 스케줄링 노드 타입과 옵션 설명을 참조하십시오.
CPU 스케줄링
- Master thread — 쿼리 또는 머지나 mutation과 같은 백그라운드 작업에서 가장 먼저 작업을 시작하는 첫 번째 스레드입니다.
- Worker thread — CPU 집약적인 작업을 수행하기 위해 master가 추가로 생성할 수 있는 스레드입니다.
max_threads 쿼리 설정값을 크게 사용하면 많은 수의 worker 스레드가 CPU 리소스를 쉽게 독점할 수 있습니다. 그러면 새로 들어오는 쿼리는 블록되어 master 스레드가 실행을 시작할 CPU 슬롯을 기다려야 합니다. 이를 방지하려면 다음과 같은 구성을 사용할 수 있습니다:
cpu_slot_preemption 서버 설정으로 활성화됩니다. 이 설정을 활성화하면 모든 스레드는 주기적으로 CPU 슬롯을 갱신합니다(cpu_slot_quantum_ns 서버 설정에 따름). 이러한 갱신은 CPU가 과부하 상태일 때 실행을 차단할 수 있습니다. 실행이 장시간 차단되면(cpu_slot_preemption_timeout_ms 서버 설정 참조) 쿼리가 스케일 다운되며, 동시에 실행되는 스레드 수가 동적으로 감소합니다. 워크로드 간에는 CPU 시간의 공정성이 보장되지만, 동일한 워크로드 내부의 쿼리 간에는 일부 예외적인 경우 이 공정성이 지켜지지 않을 수 있습니다.
CPU 리소스를 선언하면
concurrent_threads_soft_limit_num 및 concurrent_threads_soft_limit_ratio_to_cores 설정이 더 이상 적용되지 않습니다. 대신 특정 워크로드에 할당되는 CPU 수를 제한하는 데 워크로드 설정 max_concurrent_threads를 사용합니다. 이전 동작과 동일하게 하려면 WORKER THREAD 리소스만 생성하고, 워크로드 all의 max_concurrent_threads를 concurrent_threads_soft_limit_num과 같은 값으로 설정한 뒤, 쿼리 설정 workload = "all"을 사용하십시오. 이 구성은 concurrent_threads_scheduler 설정 값을 “fair_round_robin”으로 지정한 것과 같습니다.스레드와 CPU
- 스레드 수 제한:
max_concurrent_threads및max_concurrent_threads_ratio_to_cores - CPU 스로틀링:
max_cpus,max_cpu_share,max_burst_cpu_seconds
max_threads 쿼리 설정이 지정하는 값을 낮추는 효과가 있습니다. 두 번째 방법은 토큰 버킷 알고리즘을 사용해 워크로드의 CPU 활용을 스로틀링합니다. 이 방법은 스레드 수에 직접 영향을 주지는 않지만, 워크로드에 속한 모든 스레드의 총 CPU 활용을 스로틀링합니다.
max_cpus 및 max_burst_cpu_seconds를 사용하는 토큰 버킷 스로틀링은 다음을 의미합니다. delta초의 임의의 인터벌 동안 워크로드 내 모든 쿼리의 총 CPU 사용량은 max_cpus * delta + max_burst_cpu_seconds CPU 초를 초과할 수 없습니다. 장기적으로는 평균 활용을 max_cpus로 제한하지만, 단기적으로는 이 제한을 초과할 수 있습니다. 예를 들어 max_burst_cpu_seconds = 60 및 max_cpus=0.001인 경우, 스로틀링 없이 스레드 1개를 60초 동안 실행하거나, 스레드 2개를 30초 동안 실행하거나, 스레드 60개를 1초 동안 실행할 수 있습니다. max_burst_cpu_seconds의 기본값은 1초입니다. 동시 실행되는 스레드가 많은 경우 값이 너무 낮으면 허용된 max_cpus 코어를 충분히 활용하지 못할 수 있습니다.
CPU 슬롯을 보유하는 동안 스레드는 다음 세 가지 주요 상태 중 하나에 있을 수 있습니다.
- Running: 실제로 CPU 리소스를 소비하는 상태입니다. 이 상태에서 소요된 시간은 CPU 스로틀링에 반영됩니다.
- Ready: CPU를 사용할 수 있게 되기를 기다리는 상태입니다. CPU 스로틀링에 반영되지 않습니다.
- Blocked: IO 작업 또는 기타 블로킹 syscall(예: 뮤텍스를 기다리는 경우)을 수행하는 상태입니다. CPU 스로틀링에 반영되지 않습니다.
max_cpu_share 기준으로 전체 CPU 리소스의 70%까지로 제한됩니다. 반면 수집은 최소 0.8 * 0.25 = 20%를 보장받지만 상한은 없습니다.
ClickHouse 서버에서 CPU 활용률을 최대화하려면 루트 워크로드
all에 max_cpus와 max_cpu_share를 사용하지 마십시오. 대신 max_concurrent_threads를 더 큰 값으로 설정하십시오. 예를 들어 CPU가 8개인 시스템에서는 max_concurrent_threads = 16으로 설정하십시오. 이렇게 하면 8개의 스레드는 CPU 작업을 실행하고, 나머지 8개의 스레드는 I/O 작업을 처리할 수 있습니다. 추가 스레드는 CPU 부하를 발생시켜 스케줄링 규칙이 적용되도록 합니다. 반대로 max_cpus = 8로 설정하면 서버가 사용 가능한 8개의 CPU를 초과할 수 없으므로 CPU 부하가 발생하지 않습니다.쿼리 슬롯 스케줄링
max_concurrent_queries는 지정된 워크로드에서 동시에 실행할 수 있는 동시 쿼리 수를 제한합니다. 이는 쿼리 max_concurrent_queries_for_all_users 및 서버 max_concurrent_queries 설정에 해당합니다. async insert 쿼리와 KILL 같은 일부 특정 쿼리는 이 제한에 포함되지 않습니다.
워크로드 설정 max_queries_per_second와 max_burst_queries는 토큰 버킷 throttler를 사용해 해당 워크로드의 쿼리 수를 제한합니다. 이 설정은 임의의 시간 인터벌 T 동안 새로 실행을 시작하는 쿼리 수가 max_queries_per_second * T + max_burst_queries를 넘지 않도록 보장합니다.
워크로드 설정 max_waiting_queries는 해당 워크로드의 대기 중인 쿼리 수를 제한합니다. 이 한도에 도달하면 서버는 오류 SERVER_OVERLOADED를 반환합니다.
차단된 쿼리는 모든 제약 조건이 충족될 때까지 무기한 대기하며, 그전까지는
SHOW PROCESSLIST에 표시되지 않습니다.워크로드 및 리소스 저장
CREATE WORKLOAD 및 CREATE RESOURCE 쿼리로 정의된 모든 워크로드와 리소스는 workload_path의 디스크 또는 workload_zookeeper_path의 ZooKeeper에 영구적으로 저장됩니다. 노드 간 일관성을 확보하려면 ZooKeeper 저장소를 사용하는 것이 좋습니다. 또는 디스크 저장소와 함께 ON CLUSTER 절을 사용할 수도 있습니다.
구성 기반 워크로드와 리소스
구성 포맷
CREATE WORKLOAD 및 CREATE RESOURCE SQL 문과 동일한 구문을 사용합니다. 모든 쿼리는 유효해야 합니다.
사용 권장 사항
- 인프라 한도를 설정할 수 있도록 구성에서 루트 워크로드와 네트워크 IO 리소스를 정의합니다.
- 이러한 한도를 강제 적용하도록
throw_on_unknown_workload를 설정합니다. - 모든 쿼리에 한도가 자동으로 적용되도록
CREATE WORKLOAD default IN all을 생성합니다 (workload쿼리 설정의 기본값이 ‘default’이기 때문입니다). - 사용자가 구성된 계층 구조 안에서 추가 워크로드를 생성할 수 있도록 허용합니다.
엄격한 리소스 액세스
throw_on_unknown_workload가 있습니다. 이 값을 true로 설정하면 모든 쿼리에서 유효한 workload 쿼리 설정을 사용해야 하며, 그렇지 않으면 RESOURCE_ACCESS_DENIED 예외가 발생합니다. 이 값을 false로 설정하면 해당 쿼리는 리소스 스케줄러를 사용하지 않으며, 즉 모든 RESOURCE에 무제한으로 액세스하게 됩니다. 쿼리 설정 use_concurrency_control = 0을 사용하면 쿼리가 CPU 스케줄러를 우회하여 CPU에 무제한으로 액세스할 수 있습니다. CPU 스케줄링을 강제하려면 use_concurrency_control이 읽기 전용 상수 값으로 유지되도록 setting constraint를 생성하십시오.
CREATE WORKLOAD default를 실행하지 않았다면 throw_on_unknown_workload를 true로 설정하지 마십시오. 시작 중에 workload를 명시적으로 설정하지 않은 쿼리가 실행되면 server 시작에 문제가 발생할 수 있습니다.관련 항목
- system.scheduler
- system.workloads
- system.resources
- merge_workload MergeTree 설정
- merge_workload 서버 전역 설정
- mutation_workload MergeTree 설정
- mutation_workload 서버 전역 설정
- workload_path 서버 전역 설정
- workload_zookeeper_path 서버 전역 설정
- cpu_slot_preemption 서버 전역 설정
- cpu_slot_quantum_ns 서버 전역 설정
- cpu_slot_preemption_timeout_ms 서버 전역 설정