В настоящее время этим способом можно планировать ввод-вывод удаленных дисков и CPU. О гибких ограничениях памяти см. в разделе Оверкоммит памяти
Настройка диска
storage_configuration сервера:
Чтобы включить планирование ввода-вывода для конкретного диска, необходимо указать read_resource и/или write_resource в конфигурации хранилища. Так ClickHouse понимает, какой ресурс использовать для всех операций чтения и записи на данном диске. Ресурсы чтения и записи могут ссылаться на одно и то же имя ресурса, что полезно для локальных SSD или HDD. Несколько разных дисков также могут ссылаться на один и тот же ресурс, что полезно для удаленных дисков, если вы хотите обеспечить справедливое распределение пропускной способности сети, например между рабочими нагрузками “production” и “development”.
Пример:
Маркировка рабочих нагрузок
workload, чтобы различать разные рабочие нагрузки. Если workload не задана, используется значение “default”. Обратите внимание, что другое значение можно указать с помощью профилей настроек. Ограничения настроек можно использовать, чтобы сделать workload неизменяемой, если вы хотите, чтобы все запросы пользователя помечались фиксированным значением настройки workload.
Настройку workload можно также назначить для фоновых операций. Для слияний и мутаций используются настройки сервера merge_workload и mutation_workload соответственно. Эти значения также можно переопределить для конкретных таблиц с помощью настроек MergeTree merge_workload и mutation_workload
Рассмотрим пример системы с двумя разными рабочими нагрузками: “production” и “development”.
Иерархия планирования ресурсов
inflight_limit(ограничение) — блокирует, если либо число одновременно выполняющихся запросов превышаетmax_requests, либо их суммарная стоимость превышаетmax_cost; должен иметь единственный дочерний узел.bandwidth_limit(ограничение) — блокирует, если текущая пропускная способность превышаетmax_speed(0 означает отсутствие ограничений) или всплеск превышаетmax_burst(по умолчанию равноmax_speed); должен иметь единственный дочерний узел.fair(политика) — выбирает следующий запрос для обслуживания из одного из дочерних узлов в соответствии с max-min fairness; дочерние узлы могут задаватьweight(по умолчанию 1).priority(политика) — выбирает следующий запрос для обслуживания из одного из дочерних узлов в соответствии со статическими приоритетами (меньшее значение означает более высокий приоритет); дочерние узлы могут задаватьpriority(по умолчанию 0).fifo(очередь) — листовой узел иерархии, способный содержать запросы, превышающие доступную емкость ресурса.
inflight_limit. Обратите внимание, что небольшие значения max_requests или max_cost могут привести к неполному использованию ресурса, тогда как слишком большие значения могут привести к пустым очередям внутри планировщика, что, в свою очередь, приведет к игнорированию политик (нарушению справедливости или игнорированию приоритетов) в поддереве. С другой стороны, если вы хотите защитить ресурсы от слишком высокой нагрузки, следует использовать bandwidth_limit. Он ограничивает скорость, когда объем ресурса, потребленного за duration секунд, превышает max_burst + max_speed * duration байт. Два узла bandwidth_limit на одном и том же ресурсе можно использовать для ограничения пиковой пропускной способности на коротких интервалах и средней пропускной способности на более длинных.
Следующий пример показывает, как определить иерархии планирования ввода-вывода, показанные на рисунке:
Классификаторы рабочих нагрузок
workload, указанного в запросе, с листовыми очередями, которые должны использоваться для определённых ресурсов. Сейчас классификация рабочих нагрузок проста: доступно только статическое сопоставление.
Пример:
Иерархия рабочих нагрузок
CREATE RESOURCE, имеют одинаковую иерархическую структуру, но в отдельных аспектах могут различаться. Для каждой рабочей нагрузки, созданной с помощью CREATE WORKLOAD, автоматически создаётся несколько узлов планировщика для каждого ресурса. Дочернюю рабочую нагрузку можно создать внутри другой, родительской рабочей нагрузки. Ниже приведён пример, который задаёт в точности ту же иерархию, что и XML-конфигурация выше:
SETTINGS workload = 'name'.
Для настройки рабочей нагрузки можно использовать следующие настройки:
priority- рабочие нагрузки одного уровня обслуживаются в соответствии со значениями статического приоритета (меньшее значение означает более высокий приоритет).weight- рабочие нагрузки одного уровня с одинаковым статическим приоритетом распределяют ресурсы в соответствии с весами.max_io_requests- ограничение на количество параллельных запросов ввода-вывода в этой рабочей нагрузке.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- максимальное количество CPU-секунд, которое рабочая нагрузка может потребить без ограничения скорости из-заmax_cpus.
max_bytes_per_second = 10485760 будет иметь ограничение пропускной способности 10 MB/s отдельно для каждого ресурса чтения и записи. Если требуется общее ограничение для чтения и записи, рассмотрите возможность использования одного и того же ресурса для доступа READ и WRITE.
Нельзя задать разные иерархии рабочих нагрузок для разных ресурсов. Однако можно задать разные значения настроек рабочей нагрузки для конкретного ресурса:
CREATE OR REPLACE WORKLOAD.
Настройки рабочей нагрузки преобразуются в соответствующий набор узлов планировщика. Подробности на более низком уровне см. в описании типов и параметров узлов планировщика.
Планирование CPU
- Master thread — первый поток, который начинает выполнять запрос или фоновую операцию, такую как merge или mutation.
- Worker thread — дополнительные потоки, которые master может порождать для выполнения ресурсоёмких задач.
max_threads. В этом случае входящие запросы будут блокироваться и ждать слот CPU, чтобы их master-поток мог начать выполнение. Чтобы этого избежать, можно использовать следующую конфигурацию:
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". Эта конфигурация соответствует значению “fair_round_robin” для настройки concurrent_threads_scheduler.Потоки и CPU
- Ограничение числа потоков:
max_concurrent_threadsиmax_concurrent_threads_ratio_to_cores - Троттлинг CPU:
max_cpus,max_cpu_shareиmax_burst_cpu_seconds
max_threads. Второй ограничивает потребление CPU рабочей нагрузкой с помощью алгоритма token bucket. Он не влияет напрямую на число потоков, но ограничивает суммарное потребление CPU всеми потоками рабочей нагрузки.
Троттлинг token bucket с 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: Выполняет операции ввода-вывода или другие блокирующие системные вызовы (например, ожидает mutex). Не учитывается при троттлинге CPU.
max_cpu_share её предел составляет 70% от общих ресурсов CPU. В то же время для ingestion гарантируется не менее 0.8 * 0.25 = 20%, при этом верхнего предела у неё нет.
Если вы хотите максимально загрузить CPU на сервере ClickHouse, не используйте
max_cpus и max_cpu_share для корневой рабочей нагрузки all. Вместо этого задайте более высокое значение max_concurrent_threads. Например, в системе с 8 CPU установите max_concurrent_threads = 16. Это позволит 8 потокам выполнять задачи CPU, а ещё 8 потокам — обрабатывать операции I/O. Дополнительные потоки создадут нагрузку на CPU, что обеспечит применение правил планирования. Напротив, значение max_cpus = 8 никогда не создаст нагрузки на CPU, потому что сервер не сможет превысить 8 доступных CPU.Планирование слотов для запросов
max_concurrent_queries ограничивает количество запросов, которые могут одновременно выполняться в рамках заданной рабочей нагрузки. Это аналог настройки запроса max_concurrent_queries_for_all_users и настройки сервера max_concurrent_queries. Запросы async insert и некоторые специальные запросы, такие как KILL, не учитываются в этом ограничении.
Настройки рабочей нагрузки max_queries_per_second и max_burst_queries ограничивают количество запросов для рабочей нагрузки с помощью throttler’а token bucket. Это гарантирует, что за любой интервал времени T начнут выполняться не более max_queries_per_second * T + max_burst_queries новых запросов.
Настройка рабочей нагрузки max_waiting_queries ограничивает количество ожидающих запросов для рабочей нагрузки. Когда лимит достигнут, сервер возвращает ошибку SERVER_OVERLOADED.
Заблокированные запросы будут ждать неограниченно долго и не будут отображаться в
SHOW PROCESSLIST, пока не будут выполнены все ограничения.Хранение рабочих нагрузок и ресурсов
CREATE WORKLOAD и CREATE RESOURCE хранятся постоянно: либо на диске в workload_path, либо в ZooKeeper по пути workload_zookeeper_path. Для обеспечения согласованности между узлами рекомендуется использовать хранилище ZooKeeper. В качестве альтернативы при хранении на диске можно использовать предложение ON CLUSTER.
Рабочие нагрузки и ресурсы, задаваемые конфигурацией
Формат конфигурации
CREATE WORKLOAD и CREATE RESOURCE. Все запросы должны быть корректными.
Рекомендации по использованию
- Определите корневую рабочую нагрузку и сетевые ресурсы ввода-вывода в конфигурации, чтобы задать ограничения инфраструктуры
- Установите
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 как неизменяемое значение только для чтения.
Не устанавливайте
throw_on_unknown_workload в true, пока не выполнен CREATE WORKLOAD default. Иначе это может привести к проблемам при запуске сервера, если во время старта будет выполнен запрос без явно заданной настройки workload.См. также
- 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 глобальная настройка сервера