2012-09-02 13 views
17

Nelle ultime 3 settimane abbiamo testato Nginx come bilanciamento del carico. Attualmente non riusciamo a gestire più di 1000 req/sec e 18K connessioni attive. Quando arriviamo ai numeri precedenti, Nginx inizia a bloccarsi e restituisce i codici di timeout. L'unico modo per ottenere una risposta è ridurre drasticamente il numero di connessioni.Nginx Bilanciamento del carico del traffico ad alto volume

Devo notare che i miei server possono gestire e gestiscono questa quantità di traffico su base giornaliera e al momento utilizziamo un semplice bilanciamento del Rubin DNS.

Stiamo utilizzando un server dedicato con il seguente HW:

  • Intel Xeon E5620 CPU
  • 16 GB di RAM
  • 2T SATA HDD
  • connessione
  • 1 Gb/s
  • OS: CentOS 5.8

Abbiamo bisogno di bilanciamento del carico 7 server in esecuzione su Tomca t6 e gestione di oltre 2000 req/sec su tempi di punta, gestendo le richieste HTTP e HTTPS.

Durante l'esecuzione il consumo della CPU di Nginx è di circa il 15% e la RAM utilizzata è di circa 100 MB.

Le mie domande sono:

  1. ha uno qualsiasi cercato di caricare bilanciare questo tipo di traffico utilizzando nginx?
  2. Pensi che nginx possa gestire questo tipo di traffico?
  3. Avete idea di cosa può causare l'impiccagione?
  4. Mi manca qualcosa sulle mie configurazioni?

Qui di seguito sono i miei file di configurazione:

nginx.conf:

user nginx; 
worker_processes 10; 

worker_rlimit_nofile 200000; 

error_log /var/log/nginx/error.log warn; 
pid  /var/run/nginx.pid; 


events { 
    worker_connections 10000; 
    use epoll; 
    multi_accept on; 
} 


http { 
    include  /etc/nginx/mime.types; 
    default_type application/octet-stream; 

    log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 
         '$status $body_bytes_sent "$http_referer" ' 
         '"$http_user_agent" "$http_x_forwarded_for"'; 

    #access_log /var/log/nginx/access.log main; 
    access_log off; 

    sendfile  on; 
    tcp_nopush  on; 

    keepalive_timeout 65; 
    reset_timedout_connection on; 

    gzip on; 
    gzip_comp_level 1; 
    include /etc/nginx/conf.d/*.conf; 
} 

servers.conf:

#Set the upstream (servers to load balance) 
#HTTP stream 
upstream adsbar { 
    least_conn; 
    server xx.xx.xx.34 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.36 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.37 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.39 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.40 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.42 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.43 max_fails=2 fail_timeout=15s; 
}  

#HTTPS stream 
upstream adsbar-ssl { 
    least_conn; 
    server xx.xx.xx.34:443 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.36:443 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.37:443 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.39:443 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.40:443 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.42:443 max_fails=2 fail_timeout=15s; 
    server xx.xx.xx.43:443 max_fails=2 fail_timeout=15s; 
} 

#HTTP 
server { 
    listen xxx.xxx.xxx.xxx:8080; 
    server_name www.mycompany.com; 
    location/{ 
     proxy_set_header Host $host; 
     # So the original HTTP Host header is preserved 
     proxy_set_header X-Real-IP $remote_addr; 
     # The IP address of the client (which might be a proxy itself) 
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
     proxy_pass http://adsbar; 
    } 
} 

#HTTPS 
server { 
    listen xxx.xxx.xxx.xxx:8443; 
    server_name www.mycompany.com; 
    ssl on; 
    ssl_certificate /etc/pki/tls/certs/mycompany.crt; 
    # Path to an SSL certificate; 
    ssl_certificate_key /etc/pki/tls/private/mycompany.key; 
    # Path to the key for the SSL certificate; 
    location/{ 
     proxy_set_header Host $host; 
     # So the original HTTP Host header is preserved 
     proxy_set_header X-Real-IP $remote_addr; 
     # The IP address of the client (which might be a proxy itself) 
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
     proxy_pass https://adsbar-ssl; 
    } 
} 

server { 
    listen xxx.xxx.xxx.xxx:61709; 
    location /nginx_status { 
     stub_status on; 
     access_log off; 
     allow 127.0.0.1; 
     deny all; 
    } 
} 

sysctl.conf:

# Kernel sysctl configuration file for Red Hat Linux 
# 
# For binary values, 

0 is disabled, 1 is enabled. See sysctl(8) and 
# sysctl.conf(5) for more details. 

# Controls IP packet forwarding 
net.ipv4.ip_forward = 0 

# Controls source route verification 
net.ipv4.conf.default.rp_filter = 1 

# Do not accept source routing 
net.ipv4.conf.default.accept_source_route = 0 

# Controls the System Request debugging functionality of the kernel 
kernel.sysrq = 1 

# Controls whether core dumps will append the PID to the core filename 
# Useful for debugging multi-threaded applications 
kernel.core_uses_pid = 1 

# Controls the use of TCP syncookies 
net.ipv4.tcp_syncookies = 1 

# Controls the maximum size of a message, in bytes 
kernel.msgmnb = 65536 

# Controls the default maxmimum size of a mesage queue 
kernel.msgmax = 65536 

# Controls the maximum shared segment size, in bytes 
kernel.shmmax = 68719476736 

# Controls the maximum number of shared memory segments, in pages 
kernel.shmall = 4294967296 

fs.file-max = 120000 
net.ipv4.ip_conntrack_max = 131072 
net.ipv4.tcp_max_syn_backlog = 8196 
net.ipv4.tcp_fin_timeout = 25 
net.ipv4.tcp_keepalive_time = 3600 
net.ipv4.ip_local_port_range = 1024 65000 
net.ipv4.tcp_rmem = 4096 25165824 25165824 
net.core.rmem_max = 25165824 
net.core.rmem_default = 25165824 
net.ipv4.tcp_wmem = 4096 65536 25165824 
net.core.wmem_max = 25165824 
net.core.wmem_default = 65536 
net.core.optmem_max = 25165824 
net.core.netdev_max_backlog = 2500 
net.ipv4.tcp_tw_recycle = 1 
net.ipv4.tcp_tw_reuse = 1 

Qualsiasi aiuto, guida, idee saranno molto apprezzate.

risposta

3

nginx dovrebbe sicuramente essere in grado di gestire più di 1000 req/s (ho circa 2800 req/s in nginx quando si gioca in giro sul mio portatile a basso costo con JMeter utilizzando uno e dimezzare i 2 core)

Stai usando epoll, che è l'opzione ottimale sul kernel di Linux corrente come ho capito.

Hai disattivato acces_log, quindi il tuo disco I/O non dovrebbe essere un collo di bottiglia (nota: puoi anche impostare il file access_log in modalità buffer con un buffer di grandi dimensioni in cui scrive solo dopo ogni x kb, che evita che il disco venga costantemente martellato, ma mantiene i registri per l'analisi)

La mia comprensione è che al fine di massimizzare le prestazioni di nginx normalmente si imposta il numero di worker_processes uguale al numero di core/CPU, e quindi aumenta il numero di worker_connections per consentire più connessioni simultanee (insieme al numero di limiti di file aperti di OS). Eppure nei dati che hai postato sopra hai una CPU quadcore con 10 processi di lavoro con connessioni 10k consentite ciascuna. Di conseguenza, sul lato nginx mi piacerebbe provare qualcosa di simile:

worker_processes 4; 
worker_rlimit_nofile 999999; 
events { 
    worker_connections 32768; 
    use epoll; 
    multi_accept on; 
} 

Sul lato kernel che avevo sintonia tcp leggere e scrivere i buffer in modo diverso, si vuole un piccolo minima, piccole e grandi di default max.

Hai già aumentato l'intervallo di porte effimere.

I file con numero aperto sono limitati di più, poiché avrete molte prese aperte.

che dà le seguenti righe per aggiungere/cambiamento nella vostra /etc/sysctl.conf

net.ipv4.tcp_rmem = 4096 4096 25165824         
net.ipv4.tcp_wmem = 4096 4096 25165824 
fs.file-max=999999 

Speranza che aiuta.

18

Ecco alcune buone referenze: colpa

http://dak1n1.com/blog/12-nginx-performance-tuning

Server: https://serverfault.com/questions/221292/tips-for-maximizing-nginx-requests-sec

Una configurazione molto ben documentato dal link dak1n1:

# This number should be, at maximum, the number of CPU cores on your system. 
# (since nginx doesn't benefit from more than one worker per CPU.) 
worker_processes 24; 

# Number of file descriptors used for Nginx. This is set in the OS with 'ulimit -n 200000' 
# or using /etc/security/limits.conf 
worker_rlimit_nofile 200000; 


# only log critical errors 
error_log /var/log/nginx/error.log crit 


# Determines how many clients will be served by each worker process. 
# (Max clients = worker_connections * worker_processes) 
# "Max clients" is also limited by the number of socket connections available on the system (~64k) 
worker_connections 4000; 


# essential for linux, optmized to serve many clients with each thread 
use epoll; 


# Accept as many connections as possible, after nginx gets notification about a new connection. 
# May flood worker_connections, if that option is set too low. 
multi_accept on; 


# Caches information about open FDs, freqently accessed files. 
# Changing this setting, in my environment, brought performance up from 560k req/sec, to 904k req/sec. 
# I recommend using some varient of these options, though not the specific values listed below. 
open_file_cache max=200000 inactive=20s; 
open_file_cache_valid 30s; 
open_file_cache_min_uses 2; 
open_file_cache_errors on; 


# Buffer log writes to speed up IO, or disable them altogether 
#access_log /var/log/nginx/access.log main buffer=16k; 
access_log off; 


# Sendfile copies data between one FD and other from within the kernel. 
# More efficient than read() + write(), since the requires transferring data to and from the user space. 
sendfile on; 


# Tcp_nopush causes nginx to attempt to send its HTTP response head in one packet, 
# instead of using partial frames. This is useful for prepending headers before calling sendfile, 
# or for throughput optimization. 
tcp_nopush on; 


# don't buffer data-sends (disable Nagle algorithm). Good for sending frequent small bursts of data in real time. 
tcp_nodelay on; 


# Timeout for keep-alive connections. Server will close connections after this time. 
keepalive_timeout 30; 


# Number of requests a client can make over the keep-alive connection. This is set high for testing. 
keepalive_requests 100000; 


# allow the server to close the connection after a client stops responding. Frees up socket-associated memory. 
reset_timedout_connection on; 


# send the client a "request timed out" if the body is not loaded by this time. Default 60. 
client_body_timeout 10; 


# If the client stops reading data, free up the stale client connection after this much time. Default 60. 
send_timeout 2; 


# Compression. Reduces the amount of data that needs to be transferred over the network 
gzip on; 
gzip_min_length 10240; 
gzip_proxied expired no-cache no-store private auth; 
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml; 
gzip_disable "MSIE [1-6]\."; 

anche ulteriori informazioni su Linux tuning del sistema per sysctl.conf:

# Increase system IP port limits to allow for more connections 

net.ipv4.ip_local_port_range = 2000 65000 


net.ipv4.tcp_window_scaling = 1 


# number of packets to keep in backlog before the kernel starts dropping them 
net.ipv4.tcp_max_syn_backlog = 3240000 


# increase socket listen backlog 
net.core.somaxconn = 3240000 
net.ipv4.tcp_max_tw_buckets = 1440000 


# Increase TCP buffer sizes 
net.core.rmem_default = 8388608 
net.core.rmem_max = 16777216 
net.core.wmem_max = 16777216 
net.ipv4.tcp_rmem = 4096 87380 16777216 
net.ipv4.tcp_wmem = 4096 65536 16777216 
net.ipv4.tcp_congestion_control = cubic 
+0

Si stanno apportando queste modifiche sia al server di bilanciamento del carico che al server di backend o uno o l'altro? –

+0

Maggiori dettagli, per favore. Ogni server nginx ottiene queste regolazioni, se ad alto volume. – chrislovecnm

+0

Suppongo che se avessi server di bilanciamento del carico del database (pgpool, non un server nginx) anch'esso dovrebbe acquisire le impostazioni considerando che la connessione al database verrebbe utilizzata per ogni singola richiesta. Al contrario, la connessione tra pgpool e postgres non assumerebbe queste impostazioni perché esiste una connessione persistente stabilita tra pgpool e postgres quindi non una nuova connessione tcp stabilita per ogni richiesta di database. Questo suono è corretto? –

2

Ho trovato che usare l'algoritmo meno connesso era problematico. Sono passato a

hash $remote_addr consistent; 

e ho trovato il servizio molto più veloce.

Problemi correlati