...

Configurar o cache de threads do MariaDB de forma eficiente: maior desempenho com menos sobrecarga

Configurei especificamente a cache de threads do MariaDB para otimizar o estabelecimento de ligações e a criação de threads. Desta forma, reduzo Latência e poupar CPU‑Sobrecarga, especialmente quando há muitas sessões curtas e uma taxa de ligação elevada.

Pontos centrais

Os aspetos que se seguem constituem as orientações para uma configuração e medição eficazes da cache. Vou centrar-me em critérios claros Valores e exequíveis Passos.

  • Princípio de funcionamento: Reutilização de threads concluídas em vez da sua recriação dispendiosa
  • Relevância: Útil quando há muitas ligações curtas por segundo
  • Medição: Threads_created, Connections, Threads_cached
  • Limites: Ignorado se o conjunto de threads estiver ativo
  • Procedimento: Começar devagar, avaliar e aumentar gradualmente

É assim que funciona a cache de threads do MariaDB

Após o encerramento de uma ligação, o MariaDB coloca o thread numa cache, desde que o limite não tenha sido atingido. As novas ligações podem reutilizar esse thread, o que evita o processo dispendioso de criação e reduz o Tempo de resposta reduz. Isto tem um impacto particular quando há muitos inícios de sessão por segundo e cargas de trabalho com sessões curtas, nas quais a criação e a destruição de threads resultam num Fator de custo . A cache esvazia-se após cerca de cinco minutos de inatividade, o que evita que o servidor acumule cargas desnecessárias. Sem um conjunto de threads, o valor padrão é frequentemente de 256, o que proporciona uma pequena reserva para picos típicos. Saliento ainda que a reutilização não resolve todos os problemas: ligações de má qualidade ou estratégias de cliente incorretas continuam a ser visíveis e exigem correções específicas.

Quando vale a pena fazer o tuning

Aumento a cache quando a aplicação gera muitas ligações curtas e o contador Threads_created cresce rapidamente. Um sinal claro é um rácio elevado de Threads_created dividido por Connections, pois, nesse caso, a reutilização falha com demasiada frequência o seu objetivo. Nesta situação, os novos threads pressionam o CPU e prejudicam o tempo de resposta, enquanto o Reuse encurta o percurso. No entanto, verifico sempre se a causa não está do lado do cliente, por exemplo, devido a reconexões desnecessárias. Se uma gestão adequada das ligações estabilizar a carga, o cache muitas vezes necessita apenas de um ajuste moderado. Quem maximiza cegamente acaba rapidamente a pagar com o consumo de memória e ignora os verdadeiros pontos de ajuste na lógica da aplicação.

Valores medidos que verifico previamente

Para um diagnóstico preciso, utilizo poucos indicadores, mas significativos, com fórmulas claras. Para começar, leio Threads_created, Ligações, Threads_cached e Threads_connected e analiso as tendências. O simples rácio Threads_created/Connections mostra-me com que frequência a base de dados é recriada em vez de ser reutilizada. É também muito útil observar a proximidade do valor de Threads_cached em relação ao número habitual de picos de ligações simultâneas. Se o cache e a distância em relação ao pico continuarem elevados, eu... Recursos ou encontra a Carga Não. A tabela seguinte reúne indicadores importantes e o seu significado direto:

Índice Significado Interpretação Ação
Threads_created Threads criados desde o início Um crescimento rápido indica uma regeneração frequente Verificar a cache, reduzir as reconexões do cliente
Ligações Número total de ligações Base para a cota e a análise de tendências Acompanhar a evolução do pico de carga
Threads_cached Threads na cache Um valor baixo, apesar da frequência elevada, pode ser insuficiente Aumentar a cache aos poucos
Threads_connected Ligações atualmente ativas Orientação para determinar um tamanho adequado da cache Dimensionar a cache em função dos picos típicos

Adaptação gradual na prática

Começo por efetuar medições sob carga realista e registo os indicadores antes de cada alteração. Em seguida, verifico o valor atual com MOSTRAR VARIÁVEIS COMO 'thread_cache_size' e anota o Base para mais tarde Comparações. Em seguida, vou aumentando em pequenos incrementos e observo se o «Threads_created» aumenta mais lentamente e se os tempos de ligação se tornam mais estáveis. Uma única alteração de grande magnitude pode ocultar as causas, pelo que opto deliberadamente por passos pequenos e verificáveis. Após cada ajuste, aguardo uma fase de carga significativa para que o efeito se mantenha consistente. Só quando várias janelas de carga confirmarem o quadro é que considero o próximo passo.

Lógica de configuração recomendada e valores iniciais

Não existe um valor ideal universal; por isso, baseio-me nos picos típicos e no histórico. Para taxas de ligação baixas ou médias, basta frequentemente uma cache pequena a média, especialmente próxima do padrão de 256. Quando a carga varia muito e há muitas ligações por segundo, um intervalo maior ajuda, desde que a reutilização aumente efetivamente. Mantenho a cache um pouco abaixo dos picos habituais de Threads_connected, para não criar Recursos ligo. Quem aumenta excessivamente a cache está a desperdiçar memória sem obter quaisquer vantagens. Além disso, analiso os processos em segundo plano associados, como o Tópicos do Page Cleaner, uma vez que também influenciam o comportamento global em situações de elevada atividade de E/S.

Necessidades de memória por thread e impacto do tamanho da cache

Tenho em conta, de forma deliberada, o efeito de armazenamento da cache. Um thread armazenado na cache mantém, principalmente, o seu thread_stack e poucos metadados de thread. Buffers por ligação, como tamanho do buffer de ordenação, tamanho_de_junção ou o buffer de rede são libertados aquando da desconexão e não sobrecarregam o cache de forma permanente. A pilha, por outro lado, permanece ligada ao thread. Como valor aproximado, parto do seguinte: Memória cache ≈ thread_cache_size × thread_stack (mais alguma margem). No caso de um thread_stack Com 256–320 KB e uma cache de 512, isso já resulta numa ordem de grandeza de 130–170 MB de memória ocupada. Quem aumentar a pilha ou utilizar caches muito grandes deve ter este efeito em conta e ponderá-lo em relação a buffers mais importantes (por exemplo, o buffer do InnoDB).

Por isso, verifico sempre:

  • SHOW VARIABLES LIKE 'thread_stack'; para saber a quantidade de memória atribuída a cada thread
  • A proximidade de Threads_cached no pico do percentil 95 de Threads_connected
  • Se o aumento da cache influencia a taxa Threads_created / Ligações efetivamente melhorado

Se não houver benefícios, volto a reduzir. Um cache demasiado grande revela-se pelo facto de Threads_cached se mantém constantemente acima do pico habitual da ligação, sem que as latências continuem a diminuir.

Funcionamento no Linux e em contentores: limites e obstáculos

Verifico os limites do sistema antes de aumentar a memória cache. A criação de threads pode falhar devido a limites do sistema operativo muito antes de a própria base de dados atingir o limite máximo de ligações. Para tal, verifico:

  • Limites de processos/threads: ulimit -u (máx. de processos/threads), /proc/sys/kernel/threads-max e /proc/sys/kernel/pid_max
  • Limite da pilha: ulimit -s influencia a pilha reservada por thread – o que, no geral, é relevante para caches de grande dimensão
  • cgroups no contentor: pids.max e limites de memória; limites de PID demasiado restritos travam os picos de tráfego
  • Impressão do agendador: Quando há um grande número de threads sem pool, a sobrecarga associada à mudança de contexto pode aumentar; neste caso, o pool de threads ou o pool de aplicações podem ser mais adequados

Em hosts multi-socket ou NUMA, verifico também se os threads saltam de um nó para outro, provocando assim acessos à memória a longa distância. Nesses ambientes, os pools estáveis são frequentemente mais eficientes do que a criação constante de novos threads, que são amplamente distribuídos pelo agendador.

Equívocos frequentes sobre a cache de threads

Vou esclarecer alguns equívocos comuns, para otimizar de forma direcionada:

  • „Mais cache = sempre mais rápido.“ Só se forem criados, de facto, muitos novos tópicos é que o cache compensa. Caso contrário, estou a ocupar memória sem qualquer utilidade.
  • „A cache acelera a autenticação.“ A cache poupa, principalmente, a criação de threads do sistema operativo. A autenticação, o handshake TLS e, se for o caso, as consultas DNS ocorrem por cada ligação e continuam a necessitar de otimização de forma independente.
  • „Os buffers por thread permanecem ocupados.“ Após a desconexão, estes buffers são libertados; no cache permanece principalmente a pilha do thread.
  • „Uma cache de grande capacidade substitui o agrupamento de aplicações.“ A cache do lado do servidor reduz os custos, mas o agrupamento de aplicações evita-os. Considero sempre o agrupamento de aplicações como a primeira medida a tomar.

Influência do TLS, do DNS e da autenticação

Avalio os tempos de ligação de forma diferenciada, uma vez que a cache não abrange todas as partes. Elevados Tempos de handshake costumo interpretar isso como um problema relacionado com o TLS (verificação do certificado, falta de reestabelecimento) ou com a resolução inversa do DNS. Com skip_name_resolve=ON Evito pesquisas inversas dispendiosas e baseio-me em autorizações baseadas em IP. A escolha e a configuração do plugin de autenticação também influenciam o percurso de início de sessão. Por outro lado, a cache de threads reduz principalmente os custos de Criação e eliminação de threads. Se, apesar de ter uma cache grande, continuar a observar latências de ligação elevadas, concentro-me nos parâmetros TLS, no DNS e na gestão das ligações do cliente.

Lógica de decisão: cache, pool de threads ou pool de aplicações?

Tomo as minhas decisões seguindo um caminho simples:

  • O App-Pooling está disponível? Se for o caso, dimensionar corretamente. Desce Threads_created É evidente que basta uma cache de tamanho pequeno a médio como buffer.
  • O conjunto de threads está ativo? Então, entra em ação tamanho_da_cache_de_fios Não. Eu otimizo o pool e avalio os tempos de espera antes de ajustar outros parâmetros.
  • Muitas ligações curtas sem pool? Aumentar moderadamente a cache. Objetivo: redução percetível da taxa Threads_created / Ligações e horários de ligação mais tranquilos.
  • Paralelismo muito elevado e pressão do agendador? Estou a analisar a mudança para o thread pool, que pode proporcionar o «work-stealing» e quotas de trabalhadores mais restritas.

O importante é ter um plano de contingência: se uma abordagem não funcionar visivelmente melhor, volto atrás na última alteração. Assim, mantenho-me fiel aos dados e evito complexidade sem valor acrescentado.

Metodologia de medição com exemplos de questionários

Utilizo consultas reproduzíveis para comprovar os progressos. Para ter uma visão geral:

  • SHOW GLOBAL STATUS LIKE 'Threads\_%'; fornecimentos Threads_created, Threads_cached, Threads_connected
  • SHOW GLOBAL STATUS LIKE 'Connections'; para a base de cálculo da quota
  • SHOW VARIABLES LIKE 'thread\_%'; em tamanho_da_cache_de_fios e thread_stack verificar

Calculo a quota, por exemplo, da seguinte forma:

SELECT 
  ROUND(tc.variable_value+0 / NULLIF(c.variable_value+0,0), 4) AS threads_created_per_connection
FROM information_schema.GLOBAL_STATUS tc
JOIN information_schema.GLOBAL_STATUS c
  ON tc.variable_name='Threads_created' AND c.variable_name='Connections';

Para os testes de carga, recorro a intervalos de tempo. Tiro duas imagens (no início e no fim de um intervalo de 5 a 10 minutos) e calculo as diferenças. Opcionalmente, utilizo um ambiente de teste isolado ESTADO DA LIMPEZA, para reiniciar os contadores – em ambiente de produção, evito fazê-lo para não interferir noutras análises. Para além da quota, guardo os percentis 95 e 99 da duração da ligação a partir da monitorização do cliente, pois é precisamente aí que se manifestam os efeitos nos picos de latência.

Identificar: A cache é demasiado pequena

Muitas vezes, percebo que a cache é demasiado pequena pelo facto de o valor de Threads_created aumentar significativamente com uma carga constante. Ao mesmo tempo, o valor de Threads_cached permanece baixo, apesar de o sistema estar a processar muitas ligações e de a taxa de aproveitamento ser baixa. O resultado são flutuações Latências e desnecessárias CPU‑Carga causada pela criação frequente de threads. Se a cache aumentar moderadamente e os indicadores se estabilizarem, isso confirma o diagnóstico. Se os tempos ficarem mais estáveis e a taxa melhorar significativamente, significa que segui na direção certa. Se o efeito não se verificar, procuro especificamente causas relacionadas com os clientes, problemas de rede ou gargalos no armazenamento.

Identificar: A cache é demasiado grande

Um cache demasiado grande passa mais despercebido, mas pode ocupar memória que falta a outros destinos de buffer. Nesse caso, registo já um bom rácio, mas aumentar o cache quase não altera nada e apenas sobrecarrega o Recursos. Se o valor de Threads_cached se mantiver permanentemente muito acima do pico habitual, a vantagem perde-se. Vou reduzindo gradualmente e verifico se os indicadores ou os tempos de resposta se alteram. Se tudo se mantiver estável, opto pela configuração mais pequena e eficiente. Desta forma, mantenho a instância otimizada e deixo espaço para áreas de memória mais importantes, como o buffer do InnoDB e as estruturas de substituição do cache de consultas.

Característica: Pool de threads ativo

Assim que o conjunto de threads estiver em funcionamento, o MariaDB ignora completamente a variável thread_cache_size. Neste modo, um conjunto de threads controla um pequeno número de workers que atendem a muitas ligações, evitando assim tempos de espera para novas threads. Decido, com base no perfil de carga, se o agrupamento das correto A abordagem é ou o cache é maior Flexibilidade fornece. As cargas de trabalho altamente paralelizadas beneficiam frequentemente do pool, enquanto os picos clássicos de inícios de sessão funcionam bem com a reutilização da cache. Quem utiliza o pool deve concentrar-se nos seus parâmetros e ignorar o `thread_cache_size`. Um bom ponto de partida é a leitura sobre o Pool de threads do MariaDB, antes de planear mais etapas de afinação.

Interação com o pool de ligações da aplicação

Prefiro um pool do lado da aplicação, porque mantém as ligações abertas e alivia a carga do servidor da base de dados. Se o valor de `Threads_created` se mantiver baixo apesar da carga elevada, isso indica um pooling eficaz e uma necessidade reduzida de cache adicional. Nesta configuração, basta frequentemente um cache pequeno, que amortece picos pontuais e não Recursos desperdiçado. Se, por outro lado, observar reconexões constantes, deve-se começar por otimizar o agrupamento de aplicações e só depois aumentar a configuração da base de dados. Analisar os tempos de inatividade e os tamanhos dos pools ajuda a encontrar o ponto ideal para uma carga equilibrada. Um guia prático sobre o tema fornece informações úteis para quem está a dar os primeiros passos em Pooling de ligações, que utilizo em paralelo com a otimização da cache.

Exemplo: Configuração e controlo

Começo por verificar a configuração atual com MOSTRAR VARIÁVEIS COMO 'thread_cache_size' e registo a carga. Depois, introduzo, a título de teste, um valor moderado, como SET GLOBAL thread_cache_size = 256; ou 512, dependendo das pontas. É importante efetuar uma alteração permanente no ficheiro de configuração, por exemplo, em my.cnf em [mysqld], para que, ao reiniciar, a configuração seja mantida. Nas seguintes janelas de carga, observo Threads_created e os Citação, até perceber uma tendência clara. Se a geração de novos dados diminuir significativamente, significa que a cache está a cumprir o seu objetivo. Se os números se mantiverem inalterados, procuro as causas na gestão da ligação antes de aumentar ainda mais o valor.

Guia prático: Dimensionamento com linhas-guia

Trabalho com valores de referência fiáveis, em vez de procurar maximizar cegamente:

  • Início: Valores máximos atuais de Threads_connected observar (ao longo de várias janelas de carga típicas).
  • Primeiro dimensionamento: Cache ≈ 70–90 % do pico habitual, além de estar sujeito a um limite máximo, como max_connections / 2 como limite de segurança.
  • Incrremento: Aumentar em pequenos incrementos de 64 a 128 e a proporção Threads_created / Ligações verificar.
  • Intervalo-alvo: Quota em nítida descida e percentil 95 mais estável nos tempos de ligação; se o efeito não se verificar, reverter a configuração da cache.
  • Persistência: A partir das versões do MariaDB com SET PERSIST guardo os valores verificados diretamente no servidor; caso contrário, em my.cnf.
  • Reversão: Antes de cada alteração, registo o valor anterior, para poder voltar rapidamente ao estado anterior em caso de dúvida.

Em ambientes com perfis diurnos e noturnos muito diferentes, recomendo um dimensionamento conservador, que suavize os picos sem ocupar desnecessariamente muita capacidade de armazenamento durante a noite. Para cargas especiais (implementações, picos de Cron), prevejo deliberadamente margens de segurança.

Lista de verificação para a resolução de problemas

Primeiro, verifico se o conjunto de threads está ativo e, consequentemente, se está a desativar a cache. Em seguida, calculo a proporção entre Threads_created e Connections em vários intervalos de tempo, em vez de me limitar a uma única imagem instantânea. Em seguida, comparo o valor de «Threads_cached» com o pico de «Threads_connected», para identificar se há sobredimensionamento ou subdimensionamento. Se o desempenho continuar fraco, analiso as reconexões da aplicação, as latências de rede e os sinais de armazenamento, como tempos de espera de E/S elevados. Por fim, analiso configurações concorrentes que influenciam os threads e apresento cenários de teste repetíveis. Só assim tiro conclusões claras e evito tomar medidas precipitadas sem uma base de dados sólida.

Versão abreviada para quem tem pressa

Utilizo a cache de threads para reutilizar threads e reduzir os custos de criação. Isto tem efeito quando a frequência de ligações é elevada, enquanto um conjunto de threads ativo ignora essa variável. O sucesso é mensurável através da diminuição da taxa de Threads_created para Ligações e tempos de ligação mais estáveis. Começo por valores baixos, faço medições consistentes e só aumento quando os números e o perfil o justificam. O pooling do lado do cliente continua a ser, muitas vezes, o fator mais determinante, por isso é aí que verifico primeiro. Assim, consigo um melhor desempenho com menos sobrecarga e mantenho a configuração simplificada.

Artigos actuais