...

Servidor de limites de descritores de ficheiros: Otimizar limites no alojamento

Mostro como o Limite do descritor de ficheiro no servidor limita as ligações, os ficheiros e as tomadas, determinando assim o desempenho. Tomo medidas claras para aumentar os limites, medir a procura e evitar erros de EMFILE antes que os serviços falhem sob carga.

Pontos centrais

Para que possa agir rapidamente, resumi os mais importantes Alavanca para otimizar os limites de FD:

  • CausaCada socket, cada ficheiro, cada ligação DB consome FDs.
  • SintomasHTTP 500, mensagens EMFILE, E/S bloqueadas, falhas de serviço.
  • Mediçãoulimit, /proc/limits, file-max e lsof fornecem clareza.
  • OtimizaçãoAumentar os limites em limits.conf, systemd e sysctl especificamente.
  • SegurançaLimites elevados de flanco com limitação de taxa e monitorização.

O que são descritores de ficheiros e porque é que os limites contam

Um descritor de ficheiro é um simples número inteiro Identificador, que o kernel utiliza para referenciar ficheiros abertos, sockets, pipes ou dispositivos por processo. Cada processo tem um limite suave e um limite rígido, e há também um máximo global em todo o sistema que limita todos os processos em conjunto e, assim, minimiza o número de processos que podem ser executados. Escassez deve ser evitado. Por defeito, muitas vezes existem apenas 1024 FDs disponíveis por processo, o que rapidamente se torna apertado para sítios Web de elevado tráfego, gateways API ou backends de conversação e assim por diante Picos de carga é intensificado. Se um processo atingir o seu limite, as novas ligações falham, os trabalhadores deixam de poder abrir ficheiros e os registos enchem-se de EMFILE, o que pode causar o Tempos de resposta estendido. Torna-se particularmente crítico com configurações que ocupam vários handles por pedido: PHP-FPM, backends de cache, ficheiros de registo e proxies inversos acumulam FDs até que o Limites bloco.

Reconhecer e medir os sintomas

Os primeiros sinais de um limite demasiado apertado são muitas vezes HTTP-500 sem uma causa clara, respostas lentas ou reinícios esporádicos de serviços individuais. As entradas de registo típicas, tais como „Demasiados ficheiros abertos“, indicam EMFILE e sinalizam a necessidade imediata de Necessidade de ação. Em primeiro lugar, verifico os limites relacionados com o processo e o consumo atual, a fim de distinguir entre estrangulamentos locais e problemas em todo o sistema e, assim, determinar o Causa para ser mais exato. Este guia compacto é adequado para uma introdução estruturada Guia de limites de servidor, se pretender ter uma visão geral rápida dos parafusos de regulação e Passos plano. Em seguida, utilizo o lsof para medir o número de descritores que um processo tem efetivamente, porque os valores medidos superam os pressupostos logo que os perfis de carga mudança.

# Limite suave e rígido do shell atual
ulimit -n
ulimit -Hn

# Verificar os limites de um processo
cat /proc//limits | grep "open files"

# Estado geral do sistema
cat /proc/sys/fs/file-nr # aberto | livre | máximo
cat /proc/sys/fs/file-max # máximo global

# Estimativa aproximada do consumo por processo
lsof -p  | wc -l

Controlo dos limites e interpretação dos índices

Faço uma distinção rigorosa entre os limites relacionados com o processo e os limites globais, para poder identificar os estrangulamentos de uma forma direcionada. eliminar em vez de o mover simplesmente. O hard limit define o limite superior para aumentos nas sessões, enquanto fs.file-max e fs.nr_open definem a moldura global e, portanto, o Capacidade do host. Uma regra prática testada e comprovada é permitir pelo menos 65535 FDs por processo, desde que a RAM e a carga de trabalho suportem isso e você tenha o Carga sei. Ao mesmo tempo, certifico-me de que a soma dos trabalhadores activos, dos processos filhos e das ligações de rede em cenários realistas de carga elevada no âmbito do Valores do quadro permanece. Uma visão clara destes números evita aumentos cegos sem um plano e mantém a integridade do sistema sob controlo. Pressão.

Comando/Caminho Função O que ter em atenção
ulimit -n / -Hn Limite suave/duro da sessão atual Limite rígido define o limite superior para Levantamento
/proc//limites Limites por processo e ficheiros abertos Crítico para daemons como nginx/php-fpm
/proc/sys/fs/file-max Máximo global de todos os FDs Deve ser adicionado ao montante do processo e RAM apto
/proc/sys/fs/file-nr Aberto, gratuito, máximo em números Tendência nos ensaios de carga e Picos controlo
lsof Mostra as pegas abertas Por trabalhador/thread consumido Medir os FDs

Ajustar os limites de FD de forma temporária e permanente

Para testes rápidos, uso ulimit para definir um valor mais alto Limite suave, antes de definir regras permanentes e reiniciar os serviços. Em seguida, escrevo as entradas apropriadas em /etc/security/limits.conf, adiciono as substituições do systemd e verifico a alteração com um Ensaio de carga. Importante: O utilizador do serviço deve estar correto, caso contrário o aumento não terá qualquer efeito e o Problema reaparece sob carga. Também ajusto o limite global para que muitos processos de trabalho não excedam o limite do sistema em conjunto. acumular deixar. Só quando os lados do processo e do sistema se encaixam é que a configuração pode resistir a cenários reais de carga elevada e evitar EMFILE.

# Temporário (até terminar a sessão/reiniciar)
ulimit -n 65535

# Em todo o sistema (até reiniciar ou permanentemente via sysctl.conf)
sudo sysctl -w fs.file-max=2097152

# Permanente (exemplo para utilizadores do servidor web)
echo -e "www-data soft nofile 65535\nww-data hard nofile 65535\n* soft nofile 65535\n* hard nofile 65535" | sudo tee -a /etc/security/limits.conf

# serviços systemd (por exemplo, nginx)
sudo mkdir -p /etc/systemd/system/nginx.service.d
cat <<'EOF' | sudo tee /etc/systemd/system/nginx.service.d/limits.conf
[Serviço]
LimitNOFILE=65536
EOF
sudo systemctl daemon-reload && sudo systemctl restart nginx

Definir corretamente os parâmetros do kernel

Eu valido fs.file-max e fs.nr_open juntos para que o kernel tenha o suficiente Tampão para picos de carga. Se o limite por processo for aumentado, o limite global será atingido e o limite de pico será alterado. estrangulamento a nível do sistema. Faz sentido manter um intervalo entre o pico de carga típico e os valores globais, para que haja reservas para janelas de manutenção ou picos de tráfego e Picos de risco pode ser atenuado. Pode encontrar pormenores sobre a afinação de todo o sistema no artigo sobre Afinação do kernel, que gosto de utilizar como ferramenta para personalizações aprofundadas do SO. Lista de controlo uso. Depois de fazer as alterações, recarrego os parâmetros, verifico novamente o file-nr e verifico se todos os serviços foram reiniciados com os novos limites e se o Valores assumir o controlo.

# Parâmetros permanentes do kernel
sudo bash -c 'cat >> /etc/sysctl.d/99-ulimits.conf <<EOF
fs.file-max = 2097152
fs.nr_open = 2097152
EOF'
sudo sysctl --system

Controlo #
cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open || sysctl fs.nr_open

Planeamento e arquitetura da capacidade

O planeamento realista da capacidade começa com a medição Perfis por pedido: de quantos FDs necessitam o servidor Web, a camada de aplicações, a base de dados e a cache em conjunto? A partir destes valores, obtenho o número total de manipuladores abertos simultaneamente por anfitrião e planeio buffers para Picos sobre. Calcule de forma conservadora: a rotação de registos, sockets adicionais, ficheiros temporários e tarefas de cópia de segurança aumentam a procura e consomem recursos. Reservas. Presto atenção ao facto de o escalonamento horizontal com balanceadores de carga reduzir a carga FD por nó, o que reduz a tolerância a falhas e as janelas de mudança. Simplificado. Só com valores-limite claros por nível é possível definir limites específicos e afetar sensatamente a capacidade entre serviços. dividir.

Otimização do servidor Web e da base de dados

Para servidores web, sigo a regra Fios*4 mais pequeno do que o limite do FD, para que haja reservas para ligações a montante, ficheiros temporários e registos. Para o nginx e o Apache, incluo no cálculo o keep-alive, o acesso aberto e os registos de erros, bem como as tomadas a montante, assegurando-me assim Tampão. Bases de dados como MariaDB ou PostgreSQL abrem muitos sockets contra aplicações, replicação e monitorização; os seus limites devem corresponder ao conjunto de ligações e aos picos de tráfego. apto. As caches (Redis, Memcached) reduzem a carga da base de dados, mas não reduzem necessariamente o número de FDs se muitos clientes pedirem e se ligarem em paralelo. manter. Por conseguinte, estou a planear limites coordenados ao longo da cadeia: frontend, upstream, BD, cache e filas de mensagens, de modo a que o primeiro limite rígido não seja ultrapassado em lado nenhum. Barreira alcança.

# Exemplo: limite e trabalhador do nginx systemd
LimitNOFILE=65536 # systemd
worker_processes auto;
worker_connections 4096; # 4096 * Worker <= 65536

# Exemplo: PostgreSQL
max_connections = 1000 # Necessidade de FD ~ 1-2 por ligação + ficheiros/logs

Manter as pilhas de WordPress e PHP eficientes

As instâncias do WordPress com muitos plugins abrem mais ficheiros, mais ligações de rede e mais Registos. Reduzo o número de includes desnecessários com a OPCache, reduzo a carga nas bases de dados com a Redis Object Cache e subcontrato activos estáticos através de uma CDN para minimizar os acessos a ficheiros e Ligações para reduzir a carga. Ao mesmo tempo, aumento especificamente os limites do php-fpm e do servidor Web para que os picos durante os cronjobs, os crawlers ou os checkouts das lojas não sejam um problema. Interrupções gerar. Um tratamento limpo dos registos de erros e das rotações evita que os gravadores de registos se deparem com nada e não abram novos ficheiros pode. É assim que combino a redução do consumo e o aumento do limite para que a pilha se mantenha acessível sob carga e Rendimento porões.

Contentores e ambientes de nuvem

No Docker e no Kubernetes, os processos geralmente herdam os limites de FD do Nós, e é por isso que verifico primeiro os parâmetros do anfitrião e depois as definições do serviço. Aplicam-se princípios análogos ao systemd-nspawn ou ao containerd, mas a implementação é feita em ficheiros unitários, PodSpecs ou configurações de daemon com Substituições. Eu documento os limites como código (IaC) e mantenho-os consistentes através de playbooks para que os novos nós tenham limites idênticos. Limites trazer consigo. Com o Kubernetes, também verifico os SecurityContexts e defino as capacidades necessárias para que o lado do sistema Limites têm efeito. No final, a medição no cluster continua a ser importante, porque o agendamento, o escalonamento automático e as actualizações contínuas alteram a distribuição dos identificadores abertos e testam a sua Tampão.

# Exemplo: systemd em hosts de contentores
cat <<'EOF' | sudo tee /etc/systemd/system/myapp.service.d/limits.conf
[Serviço]
LimitNOFILE=65536
EOF

# Kubernetes: podSpec (a imagem do contentor deve respeitar o ulimit)
# Nota: as definições de rlimit devem ser definidas de forma diferente consoante o tempo de execução/OS

Segurança, limitação de débito e monitorização

Os limites elevados proporcionam espaço para respirar, mas aumentam a superfície de ataque para Inundações, Por isso, limito os pedidos na extremidade com limitação de taxa e defino limites de ligação no servidor Web. Uma firewall de aplicação Web e tempos limite sensatos impedem que as ligações inactivas bloqueiem permanentemente os FDs. vincular. Para testes recorrentes, utilizo perfis de carga reproduzíveis e uso o Prometheus, Netdata ou Nagios para monitorizar consistentemente as métricas relacionadas com ficheiros abertos e Soquetes. Dependendo da carga de trabalho, corrijo os valores-limite gradualmente em vez de os aumentar abruptamente, para que os efeitos permaneçam mensuráveis e Desmantelamento é fácil. Se quiser aprofundar os valores-limite do lado da ligação, este artigo compacto sobre Limites de ligação, que utilizo nos limites da rede como Guia serve.

Resolução de problemas com o ficheiro EMFILE: procedimento estruturado

Começo por dar uma vista de olhos à Jornal e nos registos de serviço para determinar a hora e a frequência dos erros. Em seguida, utilizo o lsof para verificar o consumo máximo por processo e identificar padrões como fugas de informação, aumento do registo de dados ou Soquete-tipos. Em seguida, comparo os limites estabelecidos com os picos reais e aumento-os temporariamente no início, para poder validar a causa e o efeito num teste controlado e, a partir daí, determinar Definições permanentes derivar. Se for detectada uma fuga, corrijo ou faço o rollback do componente, porque limites mais elevados apenas escondem os sintomas e adiam o problema. Problema. Por fim, documento a correção, defino alarmes e planeio um novo teste de carga para que a solução seja válida e possa ser utilizada novamente. Confiança cria.

Avaliar de forma realista os custos dos recursos de limites elevados de DF

Cada ficheiro ou socket aberto custa memória do kernel. Portanto, planear o Espaço de RAM Dependendo da versão e arquitetura do kernel, algumas centenas de bytes a alguns kilobytes são necessários por FD (incluindo estruturas VFS/socket). Com centenas de milhares de FDs, isso se soma. Dimensiono o file-max global de forma a que, no pior dos casos, a cache de páginas e a memória de trabalho permaneçam livres para as aplicações. Uma simples contra-verificação é realizada via vmstat, free e a tendência de FDs abertos via file-nr durante um Ensaios de carga de pico. O objetivo é uma configuração que não se transforme em swap nos picos de carga nem desencadeie uma atividade de recuperação ou OOM excessiva.

Armadilhas de distribuição e caminho de arranque (PAM, systemd, Cron)

A aplicação de limites depende do Caminho inicial de. Os logins baseados em PAM (ssh, su, login) lêem /etc/security/limits.conf, enquanto os serviços systemd usam principalmente os seus parâmetros unitários (LimitNOFILE) e não PAM obrigatório. O Cron/at pode ter os seus próprios contextos. Por isso, eu valido por serviço:

  • Como é que o processo começa? (systemctl status, ps -ef)
  • Quais limites ele realmente vê? (cat /proc//limits)
  • O PAM funciona? (Verifique os módulos PAM em /etc/pam.d/*)
  • Existem padrões para todo o sistema? (systemd: DefaultLimitNOFILE em system.conf)

Desta forma, evito que as aplicações recebam diferentes limites de FD consoante o caminho de arranque e de incoerente reagir.

Dimensionamento prático com exemplos de cálculo

Estou a contar com o Trabalhadores e perfis de ligação de trás para a frente até à capacidade FD necessária:

  • nginx com 8 trabalhadores com 4000 ligações cada: ~32000 conexões. Regra geral, o nginx reserva 1 FD por ligação ativa; mais o upstream (keep-alive) e os registos adicionam ~10-20% de buffer. Resultado: ~38000 FDs só para o nginx.
  • php-fpm com 150 filhos, tipicamente 20-40 FDs por filho (inclui, sockets, logs): conservadoramente 6000 FDs.
  • Clientes Redis/DB: 200 ligações paralelas, 1-2 FDs cada: ~400 FDs.

Total por host: ~44k FDs. Eu defino LimiteNOFILE para nginx para 65536, php-fpm analógico e plano Mundial fs.file-max para que todos os serviços mais a reserva (x1.5-x2) caibam. Para várias instâncias muito utilizadas por host, escalar globalmente para 1-2 milhões de FDs se a RAM e os caminhos de E/S forem suficientes. render-se.

Diagnóstico mais profundo: encontrar fugas e pontos de acesso

Se os FDs aumentam continuamente, utilizo ferramentas específicas para encontrar a causa:

# Identificadores abertos agrupados por tipo
lsof -p  | awk '{print $5}' | sort | uniq -c | sort -nr

# Apenas sockets de um processo
lsof -Pan -p  -i

# Quais arquivos estão crescendo (logs, temp)
lsof +L1 # Ficheiros apagados mas ainda abertos
ls -l /proc//fd

# Visão do Syscall: quem está abrindo constantemente?
strace -f -p  -e trace=open,openat,close,socket,accept,accept4 -s 0

Particularmente traiçoeiros são Registos eliminados, que ainda estão abertos: Eles ocupam espaço e FDs, mas não aparecem mais no sistema de arquivos. Reiniciar ou uma reabertura explícita (por exemplo, com o nginx via USR1) resolve esse problema de forma limpa. Observadores/exportadores configurados incorretamente também podem abrir constantemente novos sockets - limites de taxa e pooling.

Delimitar claramente Inotify, epoll e EMFILE

Nem todos os limites de recursos são chamados de limites de FD. Em ambientes de desenvolvimento e CI, as compilações falham frequentemente com ENOSPC em relação ao Inotify (limites do observador). Eu verifico e defino como um suplemento:

# Limites do Inotify (a nível do utilizador e das instâncias)
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances

Exemplo de aumento do #
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024

Embora a epoll funcione internamente com os FDs, o verdadeiro estrangulamento com os Longa duração-conexões excedem frequentemente o próprio limite do FD. Por isso, correlaciono os dados de epoll/event loop (por exemplo, identificadores activos) com o file-nr e o consumo relacionado com o processo.

Especialidades de linguagem e de tempo de execução (Java, Node.js, Go, Python)

Os tempos de execução tratam os FDs de forma diferente:

  • Java/NettyMuitos canais NOK por processo, as estruturas de registo mantêm os anexos de ficheiros abertos. Estabeleço limites generosos e faço rodar os registos com uma estratégia de reabertura em vez de fechar/substituir.
  • Nó.jsO EMFILE ocorre rapidamente com cargas de trabalho pesadas do sistema de ficheiros (por exemplo, watcher, pipelines de construção). Eu regulo as operações paralelas do fs, aumento os limites e defino estratégias de backoff/retry.
  • O elevado paralelismo através de goroutines pode abrir muitos sockets. Limito os tempos limite dos cabeçalhos de marcação e de resposta e verifico se as ligações são fechadas corretamente (IdleConnTimeout).
  • Python/uWSGI/GunicornOs modelos de trabalhadores/thread consomem FDs para registos, sockets e ficheiros temporários; eu harmonizo o número de trabalhadores, pools de threads e nenhum ficheiro-limites.

Todos eles têm uma coisa em comum: Sem uma rotação coordenada dos toros e sem uma Gestão das ligações Os FDs aumentam gradualmente.

Os contentores em termos concretos: definições do Docker e do Kubernetes

Para garantir que os contentores vêem efetivamente os limites desejados, defino-os de forma consistente ao longo da cadeia:

  • Execução do Dockeriniciar com -ulimit nofile=65535:65535 ou definido por predefinição do daemon (por exemplo, limites predefinidos).
  • ImagensOs scripts de arranque não devem repor um ulimit restritivo.
  • KubernetesDependendo do tempo de execução (containerd, cri-o), as configurações de rlimit têm efeito diferente. Eu testo no pod via cat /proc/self/limits e ajusto os padrões do node/runtime se as especificidades do pod não forem suficientes.

Especialmente em ambientes multi-tenant, asseguro a Montante total contra fs.file-max e isolar os efeitos de vizinhança ruidosa utilizando conjuntos de nós ou orçamentos de pod separados, de modo a que as implementações individuais não consumam os FDs reservados pelo anfitrião.

Clarificar as métricas e os alarmes de monitorização

Para além do file-nr e do file-max, também monitorizo os FDs por processo e as linhas de tendência:

  • Em todo o sistemaAtribuído vs. máximo, taxa de variação, rácio pico/máximo.
  • Por processoFDs por trabalhador/thread, processos Top-N, anomalias nocturnas (batch/jobs).
  • QualitativoTaxas de erro HTTP, comprimentos de fila, erros de aceitação/handshake sincronizados com a tendência FD.

Defino alertas multinívelAviso a 70-80%, Crítico a partir de 90% do limite configurado, mais Deteção de fugas através de tendências crescentes de 7 dias. Isto permite-me reagir atempadamente antes que as barreiras rígidas entrem em vigor.

Manual de instruções para situações de emergência

Quando o EMFILE ataca de forma aguda, actuo em passos claros:

  1. Identificar os principais consumidores (lsof, /proc//fd, entradas de diário).
  2. Aumentar temporariamente o limite flexível (ulimit na sessão ou substituição de LimitNOFILE) e reiniciar o serviço.
  3. Se os registos forem a razão: Parar a rotação, ativar a reabertura, reduzir o nível de registo.
  4. Tráfego de rutura no extremo acelerador (Aumentar ou reduzir os limites das taxas/limites de ligação - consoante a situação).
  5. Correção da causa principal (fuga, paralelismo demasiado agressivo, tempos limite em falta) e limites permanentes apertar.

O acompanhamento é importante: documentação, testes de carga repetidos e alarmes de afiação para que a mesma corrente seja reconhecida numa fase inicial.

Brevemente resumido

Com limites de FD aumentados, parâmetros de kernel definidos de forma clara e uma arquitetura testada, posso prestar serviços aos meus clientes. Espaço de manobra sob carga elevada. Primeiro, meço, depois defino os valores-limite adequados, verifico com testes de carga e asseguro o resultado com limitação de taxa, monitorização e limpeza Regras.

Artigos actuais