Escalar WordPress: 10 mil utilizadores por hora 2026

Escalar WordPress: 10 mil utilizadores por hora 2026

Última verificação: 12 de outubro de 2026
14 min de leitura
Guia
Core Web Vitals

Todo dono de site sonha em tornar-se “viral”. Mas para um administrador de servidor, este momento muitas vezes torna-se um pesadelo. O site começa a carregar em 30 segundos, e os utilizadores veem apenas “Error 500” ou “503 Service Unavailable”.

Neste artigo, vou mostrar como preparar o WordPress para tráfego elevado e porque é que um plugin de cache sozinho não chega.


#Limite de PHP workers no WordPress e erro 503

A maioria das falhas do WordPress não se deve à falta de RAM ou CPU, mas ao esgotamento do limite de PHP Workers.

#O que é um PHP worker

Imagine um PHP Worker como um caixa de supermercado.

  • Se tem 10 caixas (10 workers).
  • Cada cliente precisa de 1 segundo para ser atendido (o tempo de geração da página).
  • Pode atender no máximo 10 clientes por segundo.

Se o 11º cliente chegar, tem de esperar na fila. Se a fila encher, o servidor responde com erro 503.

No PHP-FPM, este “caixa” é um processo filho do pool. A documentação do PHP descreve pm.max_children diretamente como o limite de pedidos atendidos em simultâneo (php.net, configuração do FPM). Os pedidos acima desse limite esperam na fila do socket, cujo comprimento é definido por listen.backlog (511 por omissão em Linux).

#Como calcular a capacidade dos PHP workers

Tráfego máximo (RPS) = número de workers / tempo médio de geração da página

Exemplo de cálculo com 10 workers num alojamento partilhado:

  • A página é gerada em 0,5 s, por isso aceita 20 pedidos por segundo.
  • A página é gerada em 2,0 s, por isso aceita apenas 5 pedidos por segundo.

A mesma fórmula mostra o que significam os 10 mil utilizadores por hora do título. São, em média, menos de 3 visualizações por segundo, um número que 10 workers aguentam com 0,5 s por página. O problema começa quando o tráfego não se distribui de forma uniforme e chega em poucos minutos depois de um link ser partilhado, ou quando uma única visualização dispara vários pedidos PHP (AJAX, REST API, carrinho).

Conclusão: Para escalar, tem de contratar mais caixas (VPS ou servidores dedicados mais caros) ou pôr os caixas a trabalhar mais depressa (otimização de código e cache).


#Como definir pm.max_children no PHP-FPM

O número de workers define-se no ficheiro do pool do PHP-FPM (normalmente www.conf). A diretiva pm aceita três valores (php.net):

Modo pmComo funcionaQuando faz sentido
staticnúmero fixo de processos igual a pm.max_childrenservidor dedicado com tráfego previsível
dynamico número varia entre pm.min_spare_servers e pm.max_spare_servers, nunca acima de pm.max_childrena maioria dos VPS
ondemandos processos só arrancam com um pedido e terminam após pm.process_idle_timeout (10 s por omissão)muitos pools pequenos no mesmo servidor

No modo dynamic, pm.start_servers é, por omissão, a média entre min_spare_servers e max_spare_servers.

O teto de pm.max_children é definido pela memória. Exemplo de cálculo: o servidor tem 8 GB de RAM e o MySQL, o Redis e o sistema ocupam 3 GB. Se um processo PHP-FPM com WordPress e WooCommerce ocupar cerca de 100 MB no pico (meça no seu servidor, por exemplo com a coluna RSS do ps), sobram 5 GB para o PHP, ou seja, cerca de 50 processos. Definir 200 workers nesta situação não aumenta a capacidade, só empurra o servidor para swap quando chega o pico de tráfego.

Duas diretivas ajudam com fugas de memória e scripts pendurados:

  • pm.max_requests reinicia um processo depois de um número fixo de pedidos. A documentação do PHP apresenta isto como forma de contornar fugas de memória em bibliotecas de terceiros. O valor por omissão é 0, ou seja, sem limite.
  • request_terminate_timeout mata um processo que demore mais do que o tempo definido num único pedido, quando max_execution_time por alguma razão não para o script. O valor por omissão é 0, ou seja, desligado.

#Como saber se o PHP-FPM tem workers a menos

Em vez de adivinhar, ative a página de estado do pool com pm.status_path (por exemplo /fpm-status) e exponha-a no Nginx só para endereços de administração. Os campos que a documentação da página de estado do FPM descreve respondem diretamente à pergunta sobre os workers:

  • listen queue: quantos pedidos estão neste momento à espera de um processo livre.
  • max listen queue: a maior fila desde o arranque do pool.
  • active processes e idle processes: quantos processos estão a trabalhar e quantos estão à espera.
  • max children reached: um valor de 1 ou mais significa que o pool atingiu pm.max_children pelo menos uma vez.
  • slow requests: número de pedidos que ultrapassaram request_slowlog_timeout.

Todos os contadores voltam a zero quando o FPM reinicia. Se max children reached sobe e a fila não está vazia, faltam workers ou as páginas são geradas demasiado devagar. Para perceber qual das duas, defina request_slowlog_timeout (por exemplo 5 s) e um caminho para slowlog. O PHP escreve então um backtrace de cada pedido lento, ou seja, o nome do plugin e da função que prende o worker.


#Full page cache no WordPress com Varnish e Nginx

O PHP mais rápido é aquele que não é executado.

Se a sua página é estática (ex: um artigo de blog), não faz sentido o PHP gerá-la do zero. Deve servir um ficheiro HTML pronto.

#Tipos de full page cache

  1. Plugins: WP Rocket, W3 Total Cache. Guardam ficheiros HTML no disco. Chega para sites pequenos, mas quando o pedido passa à mesma pelo PHP, o worker fica ocupado apesar da cache.
  2. Server-Side Cache (Pro):
    • Varnish: Um servidor proxy que mantém páginas prontas na RAM à frente do Apache ou do Nginx.
    • Nginx FastCGI Cache: Embutido no Nginx.
    • Cloudflare: Servir a página antes de o tráfego chegar ao seu alojamento.

Regra: O tráfego anónimo (visitantes sem sessão iniciada) não deve chegar ao PHP. Cada visualização servida pela cache é um worker livre para o carrinho, a conta do cliente e os utilizadores com sessão iniciada.


#Como configurar o Varnish para WordPress e cookies

Num WordPress acabado de configurar, o Varnish muitas vezes quase não guarda nada em cache, e isso está de acordo com a documentação. Segundo o guia do Varnish sobre taxa de acertos, a configuração predefinida não guarda respostas com o cabeçalho Set-Cookie, e quando o cliente envia um cabeçalho Cookie, o Varnish contorna a cache e vai diretamente ao backend. Num site com Google Analytics ou com um banner de consentimento, quase todos os visitantes têm algum cookie.

A solução da documentação é remover cookies em vcl_recv em todo o lado onde o backend não precisa deles. O WordPress reconhece utilizadores com sessão iniciada pelos cookies com os prefixos definidos no núcleo (wordpress_, wordpress_sec_, wordpress_logged_in_) e quem comenta por comment_author_. Estes têm de passar para o PHP, o resto pode ser removido:

sub vcl_recv {
    if (req.url ~ "^/(wp-admin|wp-login\.php|carrinho|finalizar-compra|minha-conta)") {
        return (pass);
    }
    if (req.http.Cookie !~ "(wordpress_|wp-postpass_|comment_author_|woocommerce_items_in_cart|wp_woocommerce_session_)") {
        unset req.http.Cookie;
    }
}

Os caminhos do carrinho e do checkout no exemplo são ilustrativos, ajuste-os aos slugs da sua loja. As versões mais recentes do Varnish dividem o vcl_recv incorporado em rotinas mais pequenas, e a descrição do VCL incorporado mostra que a regra dos cookies pode ser desligada isoladamente através de vcl_req_cookie. Isso só faz sentido quando o backend indica sempre, por si, o que pode ir para a cache.

#Como limpar a cache do Varnish depois de publicar

Um tempo de vida longo dos objetos aumenta a taxa de acertos, mas depois de editar um artigo o leitor tem de ver a nova versão. A documentação do Varnish sobre purge e ban descreve dois mecanismos:

acl purge {
    "localhost";
    "192.168.55.0"/24;
}

sub vcl_recv {
    if (req.method == "PURGE") {
        if (!client.ip ~ purge) {
            return (synth(405, "Not allowed."));
        }
        return (purge);
    }
}
  • Purge remove um objeto com todas as variantes resultantes do cabeçalho Vary. O plugin de cache envia um pedido PURGE para o endereço do artigo. A lista acl é obrigatória, porque sem ela qualquer pessoa na internet pode esvaziar a sua cache.
  • Ban funciona como um filtro sobre objetos que já estão na cache, por exemplo “tudo em /categoria/”. Os bans que só verificam obj.* são processados em segundo plano por uma thread chamada “ban lurker”. A documentação recomenda evitar req.* nos bans, porque o objeto do pedido não está disponível nessa thread.

#Redis object cache para WordPress e WooCommerce

E lojas WooCommerce ou áreas de cliente que não se conseguem guardar totalmente em cache como HTML? Aí o PHP tem de trabalhar.

O WordPress executa em cada carregamento dezenas das mesmas consultas SQL: obter as opções do site, obter os IDs das categorias, obter os metadados do utilizador.

Redis (Object Cache) armazena os resultados de consultas à base de dados na RAM. Em vez de perguntar ao MySQL, o PHP pergunta ao Redis.

Quantas consultas desaparecem depende do tema e dos plugins. Pode verificar isso: o Query Monitor mostra o número de consultas SQL numa página antes e depois de ligar o Redis.

Em 2026, correr WooCommerce sem Redis é procurar problemas.


#O que muda o ficheiro object-cache.php no WordPress

O WordPress tem a sua própria object cache, mas não é persistente. A documentação da classe WP_Object_Cache diz claramente que, por omissão, a cache só guarda dados em memória e apenas até ao fim do pedido atual. Cada visualização começa com a cache vazia e volta a consultar a base de dados.

A persistência vem de um drop-in. A função wp_start_object_cache() carrega o ficheiro wp-content/object-cache.php, se existir, e a partir daí wp_cache_get(), wp_cache_set() e wp_cache_delete() falam com o Redis em vez de um array na memória do processo. Plugins como o Redis Object Cache fazem, na prática, uma única coisa: copiam este ficheiro e passam-lhe os dados de ligação.

Três consequências fáceis de ignorar:

  • Os transients saem da base de dados. Com uma object cache externa, set_transient() e delete_transient() escrevem através de wp_cache_* e não na tabela wp_options (set_transient). Esvaziar o Redis apaga, portanto, todos os transients.
  • Nem tudo vai para o Redis. O núcleo marca os grupos counts, plugins e theme_json como não persistentes através de wp_cache_add_non_persistent_groups(), por isso continuam a viver só na memória de um pedido.
  • Quando o próprio WordPress sugere o Redis. Desde a versão 6.1, o Site Health recomenda uma object cache persistente em qualquer instalação multisite e também quando as opções carregadas automaticamente passam de 500 entradas ou 100 000 bytes, ou quando alguma das tabelas de comentários, opções, artigos, termos ou utilizadores tem pelo menos 1000 linhas. Os limiares podem ser alterados com o filtro site_status_persistent_object_cache_thresholds.

#Como definir maxmemory e a política de remoção no Redis

O Redis sem limite de memória cresce até a RAM acabar. Em sistemas de 64 bits, maxmemory 0, ou seja, sem limite, é o valor por omissão (redis.io, eviction). Num servidor que partilha memória com o PHP-FPM e o MySQL, defina o limite de forma explícita:

maxmemory 512mb
maxmemory-policy allkeys-lru

Os 512 MB são um exemplo, não uma recomendação, escolha o valor pelo volume de dados. Mais importante é a política. A documentação do Redis chama a allkeys-lru uma boa escolha por omissão quando uma parte das chaves é lida muito mais vezes do que as restantes, que é o retrato típico de uma cache WordPress. As políticas volatile-* só removem chaves com tempo de expiração definido e, quando não existem chaves dessas, comportam-se como noeviction: o Redis passa a devolver erros na escrita. No WordPress, wp_cache_set() tem por omissão $expire = 0, por isso uma grande parte das chaves pode não ter TTL. Uma política volatile-lru numa cache destas acaba em erros de escrita em vez de substituir dados antigos.

Para ver se a cache está a funcionar, use INFO stats: a taxa de acertos é keyspace_hits / (keyspace_hits + keyspace_misses). Um evicted_keys alto com uma taxa de acertos baixa significa que o limite de memória é pequeno demais ou que a política remove as chaves erradas.


#Como excluir o carrinho WooCommerce da cache

A documentação do WooCommerce sobre a configuração de plugins de cache indica três páginas que têm de continuar dinâmicas porque mostram dados de cada cliente: carrinho, finalizar compra e a minha conta. Indica também os cookies perante os quais a cache tem de recuar: woocommerce_cart_hash e woocommerce_items_in_cart acompanham alterações no carrinho, e wp_woocommerce_session_ identifica o carrinho do cliente. Se uma cache de base de dados no servidor abranger sessões, é preciso excluir _wc_session_.

A mesma documentação avisa que alguns alojamentos com cache do lado do servidor guardam em cache a página a minha conta, o que provoca um ciclo ao repor a palavra-passe. É o primeiro sintoma a verificar quando, depois de ligar o Varnish, os clientes dizem que não conseguem mudar a palavra-passe.


#Como configurar o Nginx FastCGI cache em vez do Varnish

Se o servidor já corre Nginx, não precisa de um Varnish separado. O módulo ngx_http_fastcgi_module guarda em cache as respostas do PHP-FPM no disco e mantém as chaves em memória partilhada. A documentação do Nginx indica que uma zona de 1 MB guarda cerca de 8 mil chaves.

fastcgi_cache_path /var/cache/nginx/wp levels=1:2 keys_zone=wp:10m inactive=60m;

server {
    set $skip_cache 0;
    if ($http_cookie ~* "wordpress_logged_in_|wp-postpass_|comment_author_|woocommerce_items_in_cart|wp_woocommerce_session_") {
        set $skip_cache 1;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php-fpm.sock;
        include fastcgi.conf;
        fastcgi_cache wp;
        fastcgi_cache_key "$scheme$request_method$host$request_uri";
        fastcgi_cache_valid 200 301 302 10m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
        fastcgi_cache_lock on;
        fastcgi_cache_use_stale updating error timeout;
        fastcgi_cache_background_update on;
    }
}

O que fazem as diretivas principais, segundo a documentação do Nginx:

  • fastcgi_cache_bypass não vai buscar a resposta à cache e fastcgi_no_cache não a guarda, quando algum dos valores não está vazio e é diferente de “0”. Por isso, no exemplo, ambas recebem a mesma variável.
  • fastcgi_cache_lock on deixa passar para o PHP apenas um pedido para preencher uma nova entrada da cache. Os outros esperam. É isto que protege os workers quando, depois de um link ser partilhado, centenas de pessoas abrem o mesmo endereço ainda sem cache.
  • fastcgi_cache_use_stale updating em conjunto com fastcgi_cache_background_update on entrega ao leitor uma cópia mais antiga e atualiza em segundo plano.
  • O parâmetro inactive remove entradas que ninguém leu durante o tempo indicado, independentemente da sua frescura. O valor por omissão é 10 minutos.

#Porque é que o WordPress caiu na Black Friday

Projeto: Portal de notícias na Black Friday. Pico repentino de tráfego, o servidor morreu em 3 minutos, CPU a 100 %.

#Causas da queda

  1. Ajax Assassino: Um plugin de “Contador de Visitas” enviava um pedido AJAX (admin-ajax.php) a cada visita, e esse pedido não estava em cache.
    • O Ajax no WordPress arranca sempre o motor PHP completo, com todos os plugins. O ficheiro admin-ajax.php carrega wp-load.php e depois ainda os ficheiros do painel de administração.
    • 10 000 visitas significaram 10 000 arranques completos do WordPress. O limite de PHP Workers esgotou-se em 10 segundos.
  2. Sem Índices na DB: A tabela de artigos tinha 500 000 registos e um plugin de “Artigos relacionados” usava ORDER BY RAND(). Isso matou o MySQL.

#Como a queda foi resolvida

  1. Ajax desativado (usado Google Analytics, ou seja, JavaScript no navegador).
  2. Redis implementado, o que reduziu a carga no MySQL em 90 %.
  3. Varnish configurado para servir a página inicial a partir da RAM.

Resultado neste caso: O servidor que sufocava com 100 utilizadores passou a atender 5000 em simultâneo com 5 % de CPU. São números de um único portal, não uma norma para todas as instalações.


#Como monitorizar o desempenho do WordPress

  1. Query Monitor: Plugin para análise SQL e consumo de memória na página atual.
  2. New Relic: Monitorização APM avançada que mostra que função PHP ou plugin consome mais tempo.
  3. Estado do PHP-FPM: pm.status_path e slowlog, como descrito acima.
  4. Redis: INFO stats e INFO memory.
  5. Logs: tail -f no SSH (veja o nosso guia de SSH).

#Checklist para WordPress com muito tráfego

  1. Alojamento: Cloud VPS com Redis e PHP Workers configuráveis.
  2. Workers: Calcular pm.max_children a partir da RAM e ativar pm.status_path.
  3. Cache: Varnish ou Nginx FastCGI, com uma lista de cookies que contornam a cache e uma ACL para PURGE.
  4. Base de Dados: Redis como object cache, com maxmemory e allkeys-lru.
  5. Loja: Excluir carrinho, finalizar compra e a minha conta da cache.
  6. Limpeza: Sem admin-ajax no frontend.
  7. CDN: Mover imagens e CSS para a Cloudflare.

Um WordPress estável não é magia, é aritmética. Reduza o tempo de geração (cache) e aumente a capacidade (workers e Redis).

Próximo passo

Transforme o artigo numa implementação real

Este bloco reforça a ligação interna e conduz o leitor para o passo seguinte mais útil dentro da arquitetura do site.

Quer implementar isto no seu site?

Se o problema está nos Core Web Vitals, no rendering lento ou no peso do WordPress, posso mapear e implementar a otimização.

Cluster relacionado

Explorar outros serviços WordPress e base de conhecimento

Reforce o seu negócio com suporte técnico profissional em áreas-chave do ecossistema WordPress.

FAQ do artigo

Perguntas frequentes

Respostas práticas para aplicar o tema na execução real.

SEO-readyGEO-readyAEO-ready1 Q&A
O que é a escalabilidade do WordPress?#
Trata-se de manter o WordPress rápido e estável sob tráfego elevado, com caching, uma configuração de servidor adequada e controlo sobre os PHP workers.

Precisa de FAQ adaptado ao setor e mercado? Criamos uma versão alinhada com os seus objetivos de negócio.

Fale connosco

Artigos Relacionados