Tuning e Monitoramento
Aula 6 de 6
Performance Tuning
worker_processes e worker_connections
# /etc/nginx/nginx.conf
user www-data;
# Auto: detecta numero de CPUs
worker_processes auto;
# Fixo: 2 workers por CPU
# worker_processes 4;
# PID
pid /run/nginx.pid;
events {
# Maximo de conexoes por worker
worker_connections 2048;
# Aceitar multiplas conexoes simultaneamente
multi_accept on;
# Metodo de multiplexacao (linux: epoll)
use epoll;
}
# Calculo de capacidade maxima
# Max Clients = worker_processes * worker_connections
# Exemplo: 4 * 2048 = 8192 conexoes simultaneas
# Verificar CPU disponivel
nproc
lscpu | grep "^CPU(s)"
sendfile, tcp_nopush, tcp_nodelay
http {
# sendfile: zero-copy, envia arquivos diretamente do disco para socket
sendfile on;
# tcp_nopush: envia headers e inicio do arquivo juntos (com sendfile on)
tcp_nopush on;
# tcp_nodelay: desabilita Nagle algorithm para respostas em tempo real
tcp_nodelay on;
# Sendfile max chunk
sendfile_max_chunk 512k;
}
KeepAlive Tuning
http {
# Habilitar keepalive
keepalive_requests 1000;
keepalive_timeout 15;
# Para proxy reverso
proxy_http_version 1.1;
proxy_set_header Connection "";
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
# Keepalive connections para o upstream
keepalive 32;
keepalive_requests 100;
keepalive_timeout 60s;
}
}
Buffer Tuning
http {
# Buffers de requisição
client_body_buffer_size 128k;
client_header_buffer_size 1k;
client_max_body_size 100m;
large_client_header_buffers 4 8k;
# Buffers de resposta
output_buffers 8 32k;
postpone_output 1460;
# Proxy buffers
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_temp_file_write_size 8k;
}
Open File Cache
http {
# Cache de descritores de arquivo
open_file_cache max=2000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
Configuração Completa de Performance
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
# Basic
sendfile on;
tcp_nopush on;
tcp_nodelay on;
sendfile_max_chunk 512k;
# Timeouts
keepalive_timeout 15;
keepalive_requests 1000;
client_body_timeout 10;
client_header_timeout 10;
send_timeout 10;
# Buffers
client_body_buffer_size 128k;
client_header_buffer_size 1k;
client_max_body_size 100m;
large_client_header_buffers 4 16k;
output_buffers 4 32k;
# File cache
open_file_cache max=4000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
# Types
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# Gzip
gzip on;
gzip_comp_level 6;
gzip_vary on;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=general:10m rate=100r/s;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Logs e Formatos
Formatos Customizados
http {
# Formato padrao combined
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
# Formato com tempo de resposta
log_format timed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'$request_time $upstream_response_time';
# Formato JSON para analise estruturada
log_format json escape=json '{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_time":"$upstream_response_time",'
'"referer":"$http_referer",'
'"user_agent":"$http_user_agent",'
'"x_forwarded_for":"$http_x_forwarded_for"'
'}';
# Aplicar formatos
access_log /var/log/nginx/access.log timed;
access_log /var/log/nginx/access.json.log json;
# Log condicional (ignorar health checks)
map $request_uri $loggable {
/health 0;
/status 0;
default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;
}
Log Rotation (logrotate)
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
# Testar logrotate
sudo logrotate -d /etc/logrotate.d/nginx
sudo logrotate -f /etc/logrotate.d/nginx
Logs Separados por Site
server {
server_name site1.com;
access_log /var/log/nginx/site1-access.log timed;
error_log /var/log/nginx/site1-error.log warn;
}
server {
server_name site2.com;
# Log apenas de erros
access_log off;
error_log /var/log/nginx/site2-error.log;
# Log lento (requisicoes > 5s)
if ($request_time > 5) {
access_log /var/log/nginx/slow-requests.log timed;
}
}
Monitoramento com stub_status
# Verificar se modulo esta compilado
nginx -V 2>&1 | grep stub_status
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
# Verificar status
curl http://127.0.0.1/nginx_status
# Saida esperada:
# Active connections: 291
# server accepts handled requests
# 16630948 16630948 31070465
# Reading: 6 Writing: 179 Waiting: 106
Métricas do stub_status
| Métrica | Significado |
|---|---|
| Active connections | Conexões ativas totais |
| accepts | Total de conexões aceitas |
| handled | Conexões manipuladas com sucesso |
| requests | Total de requisições |
| Reading | Requisições sendo lidas |
| Writing | Respostas sendo escritas |
| Waiting | Conexões keepalive aguardando |
Script de Monitoramento
#!/bin/bash
# monitor.sh - Monitoramento basico do Nginx
HOST="http://127.0.0.1"
STATUS_URL="$HOST/nginx_status"
echo "=== Nginx Status ==="
curl -s $STATUS_URL
echo -e "\n=== Teste HTTP ==="
curl -s -o /dev/null -w "HTTP Code: %{http_code}\nTempo Total: %{time_total}s\n" $HOST
echo -e "\n=== Conexoes TCP ==="
ss -tlnp | grep 80
echo -e "\n=== Processos Nginx ==="
ps aux | grep nginx | grep -v grep
echo -e "\n=== Logs recentes (erros) ==="
tail -5 /var/log/nginx/error.log
# Monitoramento continuo
watch -n 5 'curl -s http://127.0.0.1/nginx_status'
# Coleta de metricas para grafana/prometheus
echo "nginx_connections_active $(curl -s http://127.0.0.1/nginx_status | awk '/Active/{print $3}')"
Nginx Amplify
# Instalar agente Nginx Amplify
sudo apt install python3 python3-pip -y
sudo pip3 install nginx-amplify-agent
# Configurar agente
sudo nginx-amplify-agent.py --setup
# Iniciar agente
sudo systemctl start amplify-agent
sudo systemctl enable amplify-agent
# Verificar logs do agente
sudo tail -f /var/log/amplify-agent/agent.log
Troubleshooting
curl e openssl
# Testar resposta basica
curl -I http://localhost
# Seguir redirects
curl -IL http://site.com
# Testar com metodo especifico
curl -X POST -d '{"key":"value"}' -H "Content-Type: application/json" http://api.local
# Testar SSL/TLS
curl -vk https://site.com
openssl s_client -connect site.com:443 -servername site.com
# Testar HTTP/2
curl --http2 -I https://site.com
# Testar gzip
curl -H "Accept-Encoding: gzip" -I http://site.com
# Verificar headers completos
curl -s -D - http://site.com -o /dev/null
# Medir tempo de resposta
curl -s -w "\nTempo: %{time_total}s\n" http://site.com
Logs de Erro
# Logs em tempo real
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
# Filtrar erros especificos
sudo tail -f /var/log/nginx/error.log | grep -E "emerg|alert|crit"
# Buscar 5xx no access log
sudo awk '$9 ~ /5[0-9][0-9]/' /var/log/nginx/access.log
# Buscar requisicoes lentas (> 5s)
sudo awk '$NF > 5' /var/log/nginx/access.log
# Top 10 IPs por requisicao
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# Top 10 URLs mais acessadas
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
Debug com Error Log
# Niveis de log: debug | info | notice | warn | error | crit | alert | emerg
error_log /var/log/nginx/error.log debug;
# Debug especifico para location
location /api/ {
error_log /var/log/nginx/api-debug.log debug;
proxy_pass http://backend;
}
Lua Scripting (OpenResty)
# Instalar OpenResty (Nginx com Lua)
sudo apt install openresty -y
# Ou compilar com modulo lua-nginx-module
# Exemplo de script Lua no Nginx
location /lua {
default_type 'text/plain';
content_by_lua_block {
local args = ngx.req.get_uri_args()
local name = args["name"] or "Mundo"
ngx.say("Ola, " .. name .. "!")
}
}
location /auth-lua {
access_by_lua_block {
local token = ngx.req.get_headers()["X-Auth-Token"]
if not token or token ~= "secret123" then
ngx.status = 401
ngx.say("Nao autorizado")
ngx.exit(401)
end
}
proxy_pass http://backend;
}
location /rate-limit-lua {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("Redis connection error")
return
end
local key = "rate:" .. ngx.var.binary_remote_addr
local count, err = red:incr(key)
if count == 1 then
red:expire(key, 60)
end
if count > 100 then
ngx.status = 429
ngx.say("Rate limit exceeded")
return
end
ngx.say("OK: " .. count)
}
}
Arquivos Lua Externos
# Carregar script de arquivo externo
location /api {
access_by_lua_file /etc/nginx/lua/auth.lua;
content_by_lua_file /etc/nginx/lua/handler.lua;
}
-- /etc/nginx/lua/auth.lua
local function validate_jwt(token)
-- Implementar validacao JWT
return true
end
local token = ngx.req.get_headers()["Authorization"]
if token then
token = token:gsub("^Bearer%s+", "")
if not validate_jwt(token) then
ngx.status = 401
ngx.exit(401)
end
else
ngx.status = 401
ngx.exit(401)
end
Lab: Nginx Otimizado com Monitoramento
Configure um servidor Nginx completo com tuning de performance e monitoramento.
# 1. Backup da configuracao original
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
# 2. Aplicar configuracao de performance otimizada
cat << 'EOF' | sudo tee /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
keepalive_requests 1000;
client_body_timeout 10;
client_header_timeout 10;
send_timeout 10;
client_body_buffer_size 128k;
client_max_body_size 100m;
open_file_cache max=4000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format timed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log timed;
error_log /var/log/nginx/error.log warn;
gzip on;
gzip_comp_level 6;
gzip_vary on;
gzip_types text/plain text/css application/javascript application/json;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
EOF
# 3. Configurar stub_status
cat << 'EOF' | sudo tee /etc/nginx/conf.d/status.conf
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
EOF
# 4. Configurar logrotate para logs JSON
cat << 'EOF' | sudo tee /etc/nginx/conf.d/json-log.conf
log_format json escape=json '{'
'"time":"$time_local",'
'"remote":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"bytes":$body_bytes_sent,'
'"rt":$request_time,'
'"upstream_rt":"$upstream_response_time"'
'}';
server {
listen 127.0.0.1:81;
server_name localhost;
access_log /var/log/nginx/access.json.log json;
location / { return 200 "OK"; }
}
EOF
# 5. Testar e recarregar
sudo nginx -t && sudo systemctl reload nginx
# 6. Testar status
echo "=== Stub Status ==="
curl http://127.0.0.1/nginx_status
echo -e "\n=== Performance Test ==="
ab -n 1000 -c 10 http://localhost/ 2>/dev/null | grep -E "Requests per second|Time per request|Failed requests"
echo -e "\n=== Log Format ==="
curl -s http://localhost/ > /dev/null
sudo tail -1 /var/log/nginx/access.log
echo -e "\n=== File Descriptors ==="
cat /proc/$(cat /var/run/nginx.pid)/limits | grep "open files"
Performance no Nginx e sobre configurar buffers adequados, escolher o metodo de multiplexacao correto (epoll), ajustar worker_processes ao numero de CPUs e monitorar constantemente com stub_status. Nenhum tuning substitui monitoramento continuo.