Recursos
- Recursos compartilhados no tempo (CPU, E/S, slots de consulta) - gerenciam solicitações de recursos enfileiradas nas folhas da hierarquia de agendamento. As solicitações são agendadas de acordo com as políticas e restrições definidas pela hierarquia. As solicitações de recursos são criadas quando uma consulta acessa o recurso correspondente. Por exemplo, quando uma consulta lê dados do disco ou usa a CPU para processamento, são criadas solicitações de recursos para cada quantum de trabalho realizado ou para a quantidade de bytes enviados ou recebidos por um socket.
- Recursos compartilhados no espaço (Memória) - gerenciam alocações de recursos nas folhas da hierarquia de agendamento. As alocações podem estar em execução ou pendentes. As alocações pendentes ficam bloqueadas até que espaço suficiente seja liberado ou que outra alocação seja interrompida. As decisões se baseiam nos limites e nas políticas definidos pela hierarquia. Há uma correspondência de um para um entre alocações e consultas (ou atividades em segundo plano). Uma alocação é criada quando uma consulta começa a ser executada e é liberada quando termina. As alocações em execução podem aumentar ou diminuir de tamanho dinamicamente.
Hierarquia de cargas de trabalho
max_* se aplicam por host. A carga de trabalho “user” subdivide seus recursos entre as cargas de trabalho “development” e “production”, sendo que “production” tem 3 vezes mais recursos que “development”:
SETTINGS workload = 'name'. Consulte Marcação de carga de trabalho para detalhes.
Para personalizar a carga de trabalho, as seguintes configurações podem ser usadas:
priority- (somente compartilhamento por tempo) cargas de trabalho irmãs são atendidas de acordo com valores de prioridade estáticos (um valor menor significa prioridade mais alta). Determina a preempção.precedence- (somente compartilhamento por espaço) cargas de trabalho irmãs são admitidas de acordo com valores estáticos (um valor menor significa precedência mais alta). Determina a evicção e a admissão.weight- cargas de trabalho irmãs com a mesma prioridade estática ou precedência compartilham recursos de acordo com os pesos, de forma justa. Afeta a preempção, a evicção e a admissão.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_memory- o limite para o total de memória reservada para esta carga de trabalho.
max_bytes_per_second = '10Mi' 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.
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.
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.
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 mutação.
- 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 suas threads principais iniciem 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. O tempo gasto nesse estado não é contabilizado pela limitação de CPU.
- Blocked: Executando operações de E/S ou outras syscalls bloqueantes (por exemplo, aguardando um mutex). O tempo gasto nesse estado 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 E/S. 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.Reservas de memória
O escalonamento de reserva de memória é experimental. Ele só entra em vigor quando existe um recurso
MEMORY RESERVATION, e sua sintaxe SQL e seu comportamento podem mudar em lançamentos futuros. Ainda não há suporte para merges e mutações, e a remoção de uma consulta em execução ocorre em regime de melhor esforço: ela entra em vigor no próximo ponto de sincronização de memória da consulta, e não instantaneamente.reserve_memory maior que zero, a alocação será criada em estado pendente. A alocação pendente reserva a quantidade de memória solicitada na hierarquia de cargas de trabalho. Se não houver memória suficiente disponível, a alocação permanecerá pendente até que memória suficiente seja liberada ou outras alocações sejam removidas (interrompidas). Quando a alocação é admitida, ela passa para o estado de execução. Uma alocação em execução pode aumentar ou diminuir de tamanho dinamicamente, de acordo com o consumo de memória da consulta. O ciclo de vida da alocação pode ser representado pelo seguinte diagrama de estados:
As alocações pendentes de uma carga de trabalho folha são aceitas de acordo com a ordem FIFO. Quando várias cargas de trabalho têm alocações pendentes, elas são aceitas de acordo com as configurações de precedência e peso. Cargas de trabalho com precedência mais alta são atendidas primeiro. Cargas de trabalho irmãs com a mesma precedência compartilham a memória de acordo com os pesos, de forma max-min justa, o que significa que a carga de trabalho com menor uso de memória normalizado (uso atual mais o aumento solicitado, dividido pelo peso) é atendida primeiro. A lógica inversa é aplicada durante a evicção. Quando é necessário liberar memória, as cargas de trabalho com menor precedência e maior uso de memória normalizado são removidas primeiro.
Observe que recursos compartilhados no tempo usam prioridade, enquanto recursos compartilhados no espaço usam precedência. São configurações independentes e podem ter valores diferentes. Prioridade mais alta implica preempção não destrutiva (atraso ou throttling), enquanto precedência mais alta pode implicar evicção destrutiva (interrupção com erro). Uma carga de trabalho pode ter alta prioridade para o scheduling de CPU, mas a mesma precedência para reserva de memória, para evitar a remoção de outras cargas de trabalho e a perda do trabalho já realizado por elas.
Toda carga de trabalho com um limite max_memory garante que a memória total alocada em sua subárvore não exceda esse limite. Se uma alocação pendente ou crescente exceder o limite, o procedimento de evicção é iniciado para liberar memória. O procedimento de evicção seleciona uma vítima a ser interrompida. A carga de trabalho ancestral comum mais baixa entre quem provoca a remoção e a vítima impede a evicção nas seguintes situações:
- Uma alocação pendente não pode remover alocações em execução na mesma carga de trabalho. (As cargas de trabalho de quem provoca a remoção e da vítima coincidem).
- Uma alocação pendente de menor precedência nunca interrompe uma carga de trabalho de maior precedência.
- Uma alocação pendente não pode interromper uma alocação da mesma precedência. Observe que alocações em execução com a mesma precedência podem remover umas às outras com base no uso de memória normalizado. Se a evicção for impedida ou não liberar memória suficiente, a nova alocação será bloqueada até que memória suficiente seja liberada. Essas regras permitem o enfileiramento de consultas em excesso com base na pressão de memória e fornecem uma maneira conveniente de evitar erros MEMORY_LIMIT_EXCEEDED.
Os limites da carga de trabalho são independentes de outras formas de limitar o consumo de memória, como a configuração de consulta max_memory_usage. Eles podem ser usados em conjunto para obter melhor controle sobre o consumo de memória. É possível definir limites de memória independentes com base em usuários (não em cargas de trabalho). Isso é menos flexível e não oferece recursos como reserva de memória e enfileiramento de consultas pendentes. Consulte Memory overcommit
max_waiting_queries limita o número de alocações pendentes da carga de trabalho. Quando o limite é atingido, o servidor retorna o erro SERVER_OVERLOADED. Observe que max_waiting_queries não é herdado por cargas de trabalho filhas e só faz sentido para cargas de trabalho folha.
O scheduling de reserva de memória ainda não é compatível com mesclagens e mutações.
Apenas consultas com a configuração reserve_memory maior que zero estão sujeitas a bloqueio enquanto aguardam a reserva de memória. No entanto, consultas com reserve_memory igual a zero também são contabilizadas no consumo de memória da respectiva carga de trabalho e podem ser removidas, se necessário, para liberar memória para outras alocações pendentes ou em crescimento. Consultas sem a marcação adequada de carga de trabalho não estão sujeitas ao agendamento da reserva de memória e não podem ser removidas pelo scheduler.
Para fornecer uma reserva de memória não elástica para uma consulta, defina as configurações de consulta reserve_memory e max_memory_usage com o mesmo valor. Nesse caso, a consulta reservará uma quantidade fixa de memória e não poderá aumentar sua alocação dinamicamente. Observe que a reserva de memória elástica pode ser aumentada acima de reserve_memory até max_memory_usage sem ser interrompida, a menos que haja pressão de memória. Porém, ela não pode ser reduzida abaixo de reserve_memory, mesmo quando o consumo real for menor.
Vamos considerar um exemplo de configuração:
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 carga de trabalho 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 carga de trabalho 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. Observe que max_waiting_queries não é herdada por cargas de trabalho filhas e faz sentido apenas para cargas de trabalho folha.
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.Hierarquia de nós de scheduling
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 o pico 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 a 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 devem especificarpriority(o padrão é 0).fifo(fila) - folha da hierarquia capaz de armazenar solicitações que excedem a capacidade de recursos.
limit- garante que a alocação total do filho nunca exceda um limite, iniciando o procedimento de evicção em uma subárvore, se necessário; deve ter um único filho.fair_allocation- aplica a evicção de acordo com a justiça max-min; alocações pendentes nunca removem alocações em execução; os nós filhos podem especificarweight(o padrão é 1).precedence_allocation- aplica a evicção de acordo com precedência estática (um valor menor significa precedência mais alta); uma alocação pendente de maior precedência remove alocações de menor precedência; os nós filhos devem especificarprecedence(o padrão é 0).queue- folha da hierarquia capaz de armazenar alocações em execução e pendentes.
Configuração XML obsoleta
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:
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