Atualmente, E/S de disco remoto e CPU podem ser escalonados usando o método descrito. Para limites flexíveis de memória, consulte memory overcommit
Configuração de disco
storage_configuration do servidor:
Para habilitar o agendamento de E/S para um disco específico, você precisa especificar read_resource e/ou write_resource na configuração de armazenamento. Isso informa ao ClickHouse qual recurso deve ser usado para cada solicitação de leitura e gravação do disco especificado. Os recursos de leitura e gravação podem se referir ao mesmo nome de recurso, o que é útil para Local SSDs ou HDDs. Vários discos diferentes também podem se referir ao mesmo recurso, o que é útil para discos remotos, caso você queira permitir uma divisão justa da largura de banda da rede entre cargas de trabalho como, por exemplo, “produção” e “desenvolvimento”.
Exemplo:
Marcação de carga de trabalho
workload para distinguir diferentes cargas de trabalho. Se workload não estiver definida, o valor “default” será usado. Observe que também é possível especificar outro valor usando perfis de configurações. Restrições de configuração podem ser usadas para tornar workload constante, caso você queira que todas as consultas do usuário sejam marcadas com um valor fixo da configuração workload.
É possível atribuir uma configuração workload a atividades em segundo plano. Merges e mutações usam as configurações do servidor merge_workload e mutation_workload, respectivamente. Esses valores também podem ser substituídos para tabelas específicas usando as configurações do MergeTree merge_workload e mutation_workload
Vamos considerar um exemplo de um sistema com duas cargas de trabalho diferentes: “production” e “development”.
Hierarquia de agendamento de recursos
inflight_limit(restrição) - bloqueia se o número de solicitações simultâneas em andamento excedermax_requestsou se o custo total delas excedermax_cost; deve ter um único filho.bandwidth_limit(restrição) - bloqueia se a largura de banda atual excedermax_speed(0 significa ilimitada) ou se a rajada excedermax_burst(por padrão, é igual amax_speed); deve ter um único filho.fair(política) - seleciona a próxima solicitação a ser atendida de um de seus nós filhos de acordo com o critério de justiça max-min; os nós filhos podem especificarweight(o padrão é 1).priority(política) - seleciona a próxima solicitação a ser atendida de um de seus nós filhos de acordo com prioridades estáticas (um valor menor significa prioridade mais alta); os nós filhos podem especificarpriority(o padrão é 0).fifo(fila) - folha da hierarquia capaz de armazenar solicitações que excedem a capacidade do recurso.
inflight_limit. Observe que um valor baixo de max_requests ou max_cost pode levar ao uso incompleto do recurso, enquanto valores altos demais podem levar a filas vazias dentro do agendador, o que, por sua vez, fará com que as políticas sejam ignoradas (falta de equidade ou desconsideração de prioridades) na subárvore. Por outro lado, se você quiser proteger os recursos contra uso excessivo, deve usar bandwidth_limit. Ele aplica limitação quando a quantidade de recurso consumida em duration segundos excede max_burst + max_speed * duration bytes. Dois nós bandwidth_limit no mesmo recurso podem ser usados para limitar a largura de banda de pico durante intervalos curtos e a largura de banda média durante intervalos mais longos.
O exemplo a seguir mostra como definir as hierarquias de agendamento de E/S mostradas na imagem:
Classificadores de carga de trabalho
workload especificado por uma consulta para as filas folha que devem ser usadas para recursos específicos. No momento, a classificação de carga de trabalho é simples: apenas o mapeamento estático está disponível.
Exemplo:
Hierarquia de cargas de trabalho
CREATE RESOURCE compartilham a mesma estrutura hierárquica, mas podem diferir em alguns aspectos. Cada carga de trabalho criada com CREATE WORKLOAD mantém alguns nós de escalonamento criados automaticamente para cada recurso. Uma carga de trabalho filha pode ser criada dentro de outra carga de trabalho pai. Veja abaixo o exemplo que define exatamente a mesma hierarquia da configuração XML acima:
SETTINGS workload = 'name'.
Para personalizar a carga de trabalho, as seguintes configurações podem ser usadas:
priority- cargas de trabalho irmãs são atendidas de acordo com valores de prioridade estáticos (um valor menor significa prioridade mais alta).weight- cargas de trabalho irmãs com a mesma prioridade estática compartilham recursos de acordo com os pesos.max_io_requests- o limite para o número de solicitações de E/S concurrentes nesta carga de trabalho.max_bytes_inflight- o limite para o total de bytes em trânsito de solicitações concurrentes nesta carga de trabalho.max_bytes_per_second- o limite da taxa de leitura ou gravação de bytes desta carga de trabalho.max_burst_bytes- o número máximo de bytes que pode ser processado pela carga de trabalho sem sofrer limitação de taxa (para cada recurso de forma independente).max_concurrent_threads- o limite para o número de threads de consultas nesta carga de trabalho.max_concurrent_threads_ratio_to_cores- o mesmo quemax_concurrent_threads, mas normalized em relação ao número de CPU cores disponíveis.max_cpus- o limite para o número de CPU cores para atender consultas nesta carga de trabalho.max_cpu_share- o mesmo quemax_cpus, mas normalized em relação ao número de CPU cores disponíveis.max_burst_cpu_seconds- o número máximo de segundos de CPU que pode ser consumido pela carga de trabalho sem sofrer limitação devido amax_cpus.
max_bytes_per_second = 10485760 terá um limite de largura de banda de 10 MB/s para cada recurso de leitura e gravação, de forma independente. Se for necessário um limite comum para leitura e gravação, considere usar o mesmo recurso para acesso READ e WRITE.
Não há como especificar hierarquias diferentes de cargas de trabalho para recursos diferentes. Mas há uma forma de especificar um valor de configuração de carga de trabalho diferente para um recurso específico:
CREATE OR REPLACE WORKLOAD.
As configurações de carga de trabalho são convertidas em um conjunto apropriado de nós de escalonamento. Para detalhes mais específicos, consulte a descrição dos tipos e opções de nós de escalonamento.
Escalonamento de CPU
- Thread principal — a primeira thread que começa a trabalhar em uma consulta ou em uma atividade em segundo plano, como um merge ou uma mutation.
- Thread de trabalho — as threads adicionais que a thread principal pode gerar para executar tarefas intensivas em CPU.
max_threads. Nesse caso, as consultas recebidas precisam ficar bloqueadas e aguardar um slot de CPU para que sua thread principal inicie a execução. Para evitar isso, a configuração a seguir pode ser usada:
cpu_slot_preemption. Se ela estiver habilitada, cada thread renova periodicamente seu slot de CPU (de acordo com a configuração de servidor cpu_slot_quantum_ns). Essa renovação pode bloquear a execução se a CPU estiver sobrecarregada. Quando a execução fica bloqueada por muito tempo (consulte a configuração de servidor cpu_slot_preemption_timeout_ms), a consulta reduz o número de threads em execução, que diminui dinamicamente. Observe que a distribuição justa de tempo de CPU é garantida entre cargas de trabalho, mas, entre consultas dentro da mesma carga de trabalho, isso pode falhar em alguns casos extremos.
Definir um recurso de CPU desabilita o efeito das configurações
concurrent_threads_soft_limit_num e concurrent_threads_soft_limit_ratio_to_cores. Em vez disso, a configuração de carga de trabalho max_concurrent_threads é usada para limitar o número de CPUs alocadas a uma carga de trabalho específica. Para obter o comportamento anterior, crie apenas o recurso WORKER THREAD, defina max_concurrent_threads para a carga de trabalho all com o mesmo valor de concurrent_threads_soft_limit_num e use a configuração de consulta workload = "all". Essa configuração corresponde à configuração concurrent_threads_scheduler definida com o valor “fair_round_robin”.Threads vs. CPUs
- Limite no número de threads:
max_concurrent_threadsemax_concurrent_threads_ratio_to_cores - Limitação de CPU:
max_cpus,max_cpu_shareemax_burst_cpu_seconds
max_threads determina. A segunda limita o consumo de CPU da carga de trabalho usando o algoritmo token bucket. Ela não afeta diretamente o número de threads, mas limita o consumo total de CPU de todas as threads na carga de trabalho.
A limitação por token bucket com max_cpus e max_burst_cpu_seconds significa o seguinte. Durante qualquer intervalo de delta segundos, o consumo total de CPU por todas as consultas na carga de trabalho não pode ser maior que max_cpus * delta + max_burst_cpu_seconds segundos de CPU. Isso limita o consumo médio a max_cpus no longo prazo, mas esse limite pode ser excedido no curto prazo. Por exemplo, com max_burst_cpu_seconds = 60 e max_cpus=0.001, é permitido executar 1 thread por 60 segundos, ou 2 threads por 30 segundos, ou 60 threads por 1 segundo sem limitação. O valor padrão de max_burst_cpu_seconds é 1 segundo. Valores menores podem levar à subutilização dos núcleos permitidos por max_cpus quando há muitas threads concorrentes.
Ao manter um slot de CPU, uma thread pode estar em um destes três estados principais:
- Running: Consumindo efetivamente recursos de CPU. O tempo gasto nesse estado é contabilizado pela limitação de CPU.
- Ready: Aguardando uma CPU ficar disponível. Não é contabilizado pela limitação de CPU.
- Blocked: Executando operações de I/O ou outras syscalls bloqueantes (por exemplo, aguardando um mutex). Não é contabilizado pela limitação de CPU.
max_cpu_share, um limite de 70% dos recursos totais de CPU. Já a ingestão fica com uma garantia de pelo menos 0.8 * 0.25 = 20%, sem limite superior.
Se você quiser maximizar a utilização de CPU no seu servidor ClickHouse, evite usar
max_cpus e max_cpu_share para a carga de trabalho raiz all. Em vez disso, defina um valor mais alto para max_concurrent_threads. Por exemplo, em um sistema com 8 CPUs, defina max_concurrent_threads = 16. Isso permite que 8 threads executem tarefas de CPU, enquanto outras 8 podem lidar com operações de I/O. Threads adicionais criarão pressão sobre a CPU, garantindo que as regras de agendamento sejam aplicadas. Em contraste, definir max_cpus = 8 nunca criará pressão sobre a CPU, porque o servidor não pode exceder as 8 CPUs disponíveis.Agendamento de slots de consulta
max_concurrent_queries limita o número de consultas concorrentes que podem ser executadas simultaneamente para uma determinada carga de trabalho. Ela é análoga à configuração de consulta max_concurrent_queries_for_all_users e à configuração do servidor max_concurrent_queries. Consultas de async insert e algumas consultas específicas, como KILL, não são contabilizadas nesse limite.
As configurações de workload max_queries_per_second e max_burst_queries limitam o número de consultas da carga de trabalho usando um throttler de token bucket. Isso garante que, durante qualquer intervalo de tempo T, não mais que max_queries_per_second * T + max_burst_queries novas consultas iniciarão a execução.
A configuração de workload max_waiting_queries limita o número de consultas em espera para a carga de trabalho. Quando o limite é atingido, o servidor retorna o erro SERVER_OVERLOADED.
As consultas bloqueadas ficarão em espera indefinidamente e não aparecerão em
SHOW PROCESSLIST até que todas as restrições sejam atendidas.Armazenamento de cargas de trabalho e recursos
CREATE WORKLOAD e CREATE RESOURCE, são armazenadas de forma persistente em disco, em workload_path, ou no ZooKeeper, em workload_zookeeper_path. Recomenda-se usar o armazenamento no ZooKeeper para garantir consistência entre os nós. Como alternativa, a cláusula ON CLUSTER pode ser usada em conjunto com o armazenamento em disco.
Cargas de trabalho e recursos baseados em configuração
Formato de configuração
CREATE WORKLOAD e CREATE RESOURCE. Todas as consultas devem ser válidas.
Recomendações de uso
- Definir a carga de trabalho raiz e os recursos de E/S de rede na configuração para estabelecer os limites da infraestrutura
- Definir
throw_on_unknown_workloadpara impor esses limites - Criar um
CREATE WORKLOAD default IN allpara aplicar automaticamente os limites a todas as consultas (já que o valor padrão da configuração de consultaworkloadé ‘default’) - Permitir que os usuários criem cargas de trabalho adicionais dentro da hierarquia configurada
Acesso restrito a recursos
throw_on_unknown_workload. Se ela estiver definida como true, toda consulta deverá usar uma configuração de consulta workload válida; caso contrário, será gerada a exceção RESOURCE_ACCESS_DENIED. Se ela estiver definida como false, essa consulta não usará o agendador de recursos, ou seja, terá acesso ilimitado a qualquer RESOURCE. A configuração de consulta ‘use_concurrency_control = 0’ permite que a consulta contorne o agendador de CPU e tenha acesso ilimitado à CPU. Para impor o agendamento de CPU, crie uma restrição de configuração para manter ‘use_concurrency_control’ como um valor constante somente leitura.
Não defina
throw_on_unknown_workload como true a menos que CREATE WORKLOAD default tenha sido executado. Isso pode causar problemas na inicialização do servidor se uma consulta sem a configuração explícita workload for executada durante a inicialização.Veja também
- system.scheduler
- system.workloads
- system.resources
- merge_workload configuração do MergeTree
- merge_workload configuração global do servidor
- mutation_workload configuração do MergeTree
- mutation_workload configuração global do servidor
- workload_path configuração global do servidor
- workload_zookeeper_path configuração global do servidor
- cpu_slot_preemption configuração global do servidor
- cpu_slot_quantum_ns configuração global do servidor
- cpu_slot_preemption_timeout_ms configuração global do servidor