Editor – Este post faz parte de uma série de 10 partes:
- Reduza a complexidade com Kubernetes pronto para produção
- Como aumentar a resiliência no Kubernetes com o gerenciamento avançado de tráfego
- Como melhorar a visibilidade no Kubernetes
- Seis maneiras de proteger o Kubernetes usando ferramentas de gerenciamento de tráfego
- Guia para escolher um controlador de Ingress, Parte 1: identifique seus requisitos
- Guia para escolher um controlador de Ingress, Parte 2: Riscos e preparação para o futuro
- Guia para escolher um controlador de Ingress, Parte 3: código aberto vs. padrão vs. comercial
- Um guia para escolher um controlador de Ingress, parte 4: opções de controladores de Ingress do NGINX
- Como escolher uma malha de serviços
- Teste de desempenho de controladores de Ingress NGINX em um ambiente de nuvem Kubernetes dinâmico (este post)
Você também pode baixar a série completa de artigos como um eBook gratuito – Levando o Kubernetes do teste à produção.
À medida que cada vez mais empresas executam aplicações em contêineres em ambientes de produção, o Kubernetes continua consolidando sua posição como a ferramenta padrão para a orquestração de contêineres. Ao mesmo tempo, a demanda por computação em nuvem foi antecipada em alguns anos, pois as iniciativas de trabalho remoto motivadas pela pandemia de COVID‑19 aceleraram o crescimento do tráfego da Internet. As empresas estão trabalhando rapidamente para modernizar sua infraestrutura, pois seus clientes estão enfrentando grandes interrupções e sobrecargas de rede.
Para alcançar o nível de desempenho necessário em ambientes de microsserviços baseados em nuvem, você precisa de um software rápido e totalmente dinâmico que aproveite a escalabilidade e o desempenho dos data centers de hiperescala de última geração. Muitas organizações que usam o Kubernetes para gerenciar contêineres dependem de um controlador Ingress baseado no NGINX para disponibilizar seus aplicativos aos usuários.
Neste blog, apresentamos os resultados dos nossos testes de desempenho em três controladores Ingress do NGINX em um ambiente multicloud realista, medindo a latência das conexões de clientes pela Internet:
- O NGINX Ingress Controller mantido pela comunidade Kubernetes e baseado no NGINX Open Source. Assim como em publicações anteriores, nós o chamamos aqui de controlador Ingress da comunidade. Testamos a versão 0.34.1 usando uma imagem obtida do Google Container Registry.
- NGINX Ingress Controller baseado no NGINX Open Source, versão 1.8.0 mantida pela NGINX.
- NGINX Ingress Controller baseado no NGINX Plus, versão 1.8.0 mantida pela NGINX.
Protocolo de testes e métricas coletadas
Usamos o programa de geração de carga wrk2 para simular um cliente, fazendo solicitações contínuas por HTTPS durante um período definido. O controlador Ingress em teste — o controlador Ingress da comunidade, o NGINX Ingress Controller baseado no NGINX Open Source ou o NGINX Ingress Controller baseado no NGINX Plus — encaminhou as solicitações para aplicações de backend implantadas em Pods do Kubernetes e retornou ao cliente a resposta gerada pelas aplicações. Geramos um fluxo constante de tráfego de clientes para submeter os controladores Ingress a testes de estresse e coletamos as seguintes métricas de desempenho:
- Latência – O intervalo de tempo entre o cliente gerar uma solicitação e receber a resposta. Apresentamos as latências em uma distribuição por percentis. Por exemplo, se houver 100 amostras de testes de latência, o valor no 99º percentil será a segunda maior latência de resposta entre as 100 execuções de teste.
- Tempos limite de conexão – Conexões TCP que são silenciosamente interrompidas ou descartadas porque o controlador de Ingress não responde às solicitações dentro de um determinado período.
- Erros de leitura – Tentativas de leitura em uma conexão que falham porque um socket do controlador de Ingress está fechado.
- Erros de conexão – Conexões TCP entre o cliente e o controlador Ingress que não são estabelecidas.
Topologia
Em todos os testes, usamos o utilitário wrk2 em execução em uma máquina cliente na AWS para gerar solicitações. O cliente da AWS se conectou ao endereço IP externo do controlador Ingress, que foi implantado como um DaemonSet do Kubernetes no GKE-node-1 em um ambiente do Google Kubernetes Engine (GKE). O controlador Ingress foi configurado para terminação SSL (com referência a um Secret do Kubernetes) e roteamento de camada 7, e exposto por meio de um Service do Kubernetes com Type LoadBalancer. A aplicação de backend foi executada como um Deployment do Kubernetes no GKE-node-2.

Para obter detalhes completos sobre os tipos de máquinas em nuvem e as configurações de software, consulte o Apêndice.
Metodologia de testes
Implantação do cliente
Executamos o seguinte script wrk2 (versão 4.0.0) na máquina cliente da AWS. Ele inicia 2 threads do wrk que, juntas, estabelecem 1000 conexões com o controlador Ingress implantado no GKE. Durante cada execução de teste de 3 minutos, o script gera 30.000 solicitações por segundo (RPS), o que consideramos uma boa simulação da carga sobre um controlador Ingress em um ambiente de produção.
wrk -t2 -c1000 -d180s -L -R30000 https://app.example.com:443/onde:
-t– Define o número de threads (2)-c– Define o número de conexões TCP (1000)-d– Define a duração da execução do teste em segundos (180, ou 3 minutos)-L– Gera informações detalhadas sobre percentis de latência para exportação para ferramentas de análise-R– Define o número de RPS (30.000)
Para a criptografia TLS, usamos RSA com uma chave de 2048 bits e Perfect Forward Secrecy.
Cada resposta do aplicativo de back-end (acessado em https://app.example.com:443) contém cerca de 1 KB de metadados básicos do servidor, além do código de status HTTP 200 OK.
Implantação da aplicação de back-end
Realizamos testes com implantações estática e dinâmica da aplicação de back-end.
Na implantação estática, havia cinco réplicas de Pods, e nenhuma alteração foi aplicada usando a API do Kubernetes.
Para a implantação dinâmica, usamos o script a seguir para escalar periodicamente a implantação de backend do nginx de cinco réplicas de Pod para sete e, em seguida, reduzi-la novamente para cinco. Isso simula um ambiente Kubernetes dinâmico e testa a eficácia com que o controlador Ingress se adapta às alterações nos endpoints.
while [ 1 -eq 1 ]
do
kubectl scale deployment nginx --replicas=5
sleep 12
kubectl scale deployment nginx --replicas=7
sleep 10
doneResultados de desempenho
Resultados de latência da implantação estática
Como indicado no gráfico, os três controladores Ingress apresentaram desempenho semelhante com uma implantação estática da aplicação de back-end. Isso faz sentido, já que todos são baseados no NGINX Open Source e a implantação estática não exige reconfiguração por parte do controlador Ingress.

Resultados de latência para a implantação dinâmica
O gráfico mostra a latência gerada por cada controlador Ingress em uma implantação dinâmica na qual escalamos periodicamente a aplicação de back-end de cinco Pods de réplica para sete e depois de volta para cinco (consulte Implantação da aplicação de back-end para obter detalhes).
Está claro que apenas o controlador Ingress baseado no NGINX Plus apresenta bom desempenho nesse ambiente, praticamente sem latência até o percentil 99,99. Tanto o controlador Ingress da comunidade quanto o baseado no NGINX Open Source apresentam latência perceptível já em percentis relativamente baixos, embora seguindo padrões bastante diferentes. No controlador Ingress da comunidade, a latência aumenta de forma gradual, porém constante, até o percentil 99, quando se estabiliza em cerca de 5.000 ms (5 segundos). No controlador Ingress baseado no NGINX Open Source, a latência aumenta drasticamente para cerca de 32 segundos no percentil 99 e novamente para 60 segundos no percentil 99,99.
Como discutimos em mais detalhes em Resultados de tempo limite e erros para a implantação dinâmica, a latência observada com os controladores Ingress da comunidade e baseados no NGINX Open Source é causada por erros e tempos limite que ocorrem após a configuração do NGINX ser atualizada e recarregada em resposta às alterações nos endpoints da aplicação de back-end.

Veja uma análise mais detalhada dos resultados do controlador Ingress da comunidade e do controlador Ingress baseado no NGINX Plus, nas mesmas condições de teste do gráfico anterior. O controlador Ingress baseado no NGINX Plus praticamente não introduz latência até o percentil 99,99, quando ela começa a aumentar, chegando a 254 ms no percentil 99,9999. O padrão de latência do controlador Ingress da comunidade aumenta continuamente até atingir 5.000 ms no percentil 99, ponto em que se estabiliza.

Resultados de timeout e erros da implantação dinâmica
Esta tabela mostra com mais detalhes a causa dos resultados de latência.
NGINX Open Source Comunidade NGINX PlusErros de conexão 33365 0 0Tempos limite de conexão 309 8809 0Erros de leitura 4650 0 0
Com o controlador Ingress baseado no NGINX Open Source, a necessidade de atualizar e recarregar a configuração do NGINX a cada alteração nos endpoints da aplicação de back-end causa muitos erros de conexão, tempos limite de conexão e erros de leitura. Erros de conexão/soquete ocorrem durante o breve período necessário para o NGINX recarregar, quando os clientes tentam se conectar a um soquete que não está mais alocado ao processo do NGINX. Tempos limite de conexão ocorrem quando os clientes estabelecem uma conexão com o controlador Ingress, mas o endpoint de back-end não está mais disponível. Tanto os erros quanto os tempos limite afetam gravemente a latência, com picos de até 32 segundos no 99º percentil e novamente de até 60 segundos no 99,99º percentil.
Com o controlador Ingress da comunidade, ocorreram 8.809 tempos limite de conexão devido às alterações nos endpoints à medida que a aplicação de back-end aumentava e reduzia sua escala. O controlador Ingress da comunidade usa código Lua para evitar recarregamentos da configuração quando os endpoints são alterados. Os resultados mostram que a execução de um manipulador Lua no NGINX para detectar alterações nos endpoints soluciona algumas das limitações de desempenho da versão baseada no NGINX Open Source, decorrentes da necessidade de recarregar a configuração após cada alteração nos endpoints. Ainda assim, continuam ocorrendo tempos limite de conexão, o que resulta em latência significativa nos percentis mais altos.
Com o controlador Ingress baseado no NGINX Plus, não houve erros nem tempos limite – o ambiente dinâmico praticamente não afetou o desempenho. Isso ocorre porque ele usa a API do NGINX Plus para atualizar dinamicamente a configuração do NGINX quando os endpoints são alterados. Como mencionado, a maior latência foi de 254 ms e ocorreu apenas no percentil 99,9999.
Conclusão
Os resultados de desempenho mostram que, para eliminar completamente os tempos limite e os erros em um ambiente de nuvem Kubernetes dinâmico, o controlador Ingress deve se ajustar dinamicamente às alterações nos endpoints de back-end, sem manipuladores de eventos nem recarregamentos de configuração. Com base nos resultados, podemos afirmar que a API do NGINX Plus é a solução ideal para reconfigurar dinamicamente o NGINX em um ambiente dinâmico. Em nossos testes, somente o controlador Ingress baseado no NGINX Plus alcançou o desempenho impecável necessário em ambientes Kubernetes altamente dinâmicos para manter seus usuários satisfeitos.
Apêndice
Especificações da máquina na nuvem
Máquina Provedor de nuvem Tipo de máquinaCliente AWS m5a.4xlargeGKE-node-1 GCP e2-standard-32GKE-node-2 GCP e2-standard-32
Configuração dos controladores de Ingress NGINX Open Source e NGINX Plus
Configuração do Kubernetes
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
#annotations:
#prometheus.io/scrape: "true"
#prometheus.io/port: "9113"
spec:
serviceAccountName: nginx-ingress
nodeSelector:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
hostNetwork: true
containers:
- image: gcr.io/nginx-demos/nap-ingress:edge
imagePullPolicy: Always
name: nginx-plus-ingress
ports:
- name: http
containerPort: 80
hostPort: 80
- name: https
containerPort: 443
hostPort: 443
- name: readiness-port
containerPort: 8081
#- name: prometheus
#containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
- -nginx-plus
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secretObservações:
- Esta configuração é para o NGINX Plus. As referências a
nginx‑plusforam ajustadas conforme necessário na configuração do NGINX Open Source. - NGINX App Protect está incluído na imagem (
gcr.io/nginx-demos/nap-ingress:edge), mas foi desabilitado (o sinalizador-enable-app-protectfoi omitido).
ConfigMap
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
namespace: nginx-ingress
data:
worker-connections: "10000"
worker-rlimit-nofile: "10240"
keepalive: "100"
keepalive-requests: "100000000"Configuração do NGINX Ingress Controller da comunidade
Configuração do Kubernetes
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
helm.sh/chart: ingress-nginx-2.11.1
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 0.34.1
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
spec:
nodeSelector:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
hostNetwork: true
containers:
- name: controller
image: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1@sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
args:
- /nginx-ingress-controller
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: 101
allowPrivilegeEscalation: true
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 1
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
- name: webhook
containerPort: 8443
protocol: TCP
volumeMounts:
- name: webhook-cert
mountPath: /usr/local/certificates/
readOnly: true
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admissionConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
max-worker-connections: "10000"
max-worker-open-files: "10204"
upstream-keepalive-connections: "100"
keep-alive-requests: "100000000"Configuração do aplicativo de back-end
Configuração do Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-t2dz
containers:
- name: nginx
image: nginx
ports:
- containerPort: 8080
volumeMounts:
- name: main-config-volume
mountPath: /etc/nginx
- name: app-config-volume
mountPath: /etc/nginx/conf.d
readinessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 3
volumes:
- name: main-config-volume
configMap:
name: main-conf
- name: app-config-volume
configMap:
name: app-conf
---ConfigMaps
apiVersion: v1
kind: ConfigMap
metadata:
name: main-conf
namespace: default
data:
nginx.conf: |+
user nginx;
worker_processes 16;
worker_rlimit_nofile 102400;
worker_cpu_affinity auto 1111111111111111;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 100000;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
tcp_nodelay on;
access_log off;
include /etc/nginx/conf.d/*.conf;
}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-conf
namespace: default
data:
app.conf: "server {listen 8080;location / {default_type text/plain;expires -1;return 200 'Server address: $server_addr:$server_portnServer name:$hostnamenDate: $time_localnURI: $request_urinRequest ID: $request_idn';}location /healthz {return 200 'I am happy and healthy :)';}}"
---Serviço
apiVersion: v1
kind: Service
metadata:
name: app-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: nginx
---Sobre o autor

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.
Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.
Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.