Devi aumentare il throughput di nginx a un socket unix upstream - tuning del kernel linux?


28

Sto eseguendo un server nginx che funge da proxy per un socket unix upstream, in questo modo:

upstream app_server {
        server unix:/tmp/app.sock fail_timeout=0;
}

server {
        listen ###.###.###.###;
        server_name whatever.server;
        root /web/root;

        try_files $uri @app;
        location @app {
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                proxy_pass http://app_server;
        }
}

Alcuni processi del server delle app, a loro volta, /tmp/app.sockeseguono il pull delle richieste non appena diventano disponibili. Il particolare server di app in uso qui è Unicorn, ma non credo sia rilevante per questa domanda.

Il problema è che sembra che oltre un certo carico, nginx non riesca a ricevere richieste attraverso il socket a una velocità abbastanza veloce. Non importa quanti processi del server delle app ho impostato.

Ricevo un flusso di questi messaggi nel registro degli errori di nginx:

connect() to unix:/tmp/app.sock failed (11: Resource temporarily unavailable) while connecting to upstream

Molte richieste comportano il codice di stato 502 e quelle che non richiedono molto tempo per il completamento. La stat della coda di scrittura nginx si aggira intorno a 1000.

Ad ogni modo, mi sento come se mi sfuggisse qualcosa di ovvio qui, perché questa particolare configurazione di nginx e app server è piuttosto comune, specialmente con Unicorn (in realtà è il metodo consigliato). Ci sono opzioni del kernel di Linux che devono essere impostate o qualcosa in nginx? Qualche idea su come aumentare il throughput al socket upstream? Qualcosa che sto chiaramente sbagliando?

Ulteriori informazioni sull'ambiente:

$ uname -a
Linux servername 2.6.35-32-server #67-Ubuntu SMP Mon Mar 5 21:13:25 UTC 2012 x86_64 GNU/Linux

$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]

$ unicorn -v
unicorn v4.3.1

$ nginx -V
nginx version: nginx/1.2.1
built by gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
TLS SNI support enabled

Modifiche correnti al kernel:

net.core.rmem_default = 65536
net.core.wmem_default = 65536
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_mem = 16777216 16777216 16777216
net.ipv4.tcp_window_scaling = 1
net.ipv4.route.flush = 1
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
net.core.somaxconn = 8192
net.netfilter.nf_conntrack_max = 524288

Impostazioni di Ulimit per l'utente nginx:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Hai controllato l'output di ulimit, in particolare il numero di file aperti?
Khaled,

@Khaled, ulimit -ndice 65535.
Ben Lee,

Risposte:


16

Sembra che il collo di bottiglia sia l'app che alimenta il socket piuttosto che essere Nginx stesso. Lo vediamo molto con PHP quando utilizzato con socket rispetto a una connessione TCP / IP. Nel nostro caso, i colli di bottiglia di PHP molto prima di quanto Nginx avrebbe mai pensato.

Hai controllato il limite di tracciamento della connessione sysctl.conf, il limite del backlog del socket

  • net.core.somaxconn
  • net.core.netdev_max_backlog

2
Ho capito qual è il problema. Vedi la risposta che ho pubblicato. In realtà è stato il collo di bottiglia dell'app, non il socket, proprio come ti sembra. L'avevo escluso in precedenza a causa di una diagnosi errata, ma risulta che il problema era il throughput a un altro server. L'ho capito solo un paio d'ore fa. Ti assegnerò la generosità, dal momento che hai praticamente inchiodato la fonte del problema, nonostante la diagnosi errata che ho posto nella domanda; tuttavia, ho intenzione di dare il segno di spunta alla mia risposta, perché la mia risposta descrive le circostanze esatte, quindi potrebbe aiutare qualcuno in futuro con un problema simile.
Ben Lee,

È stato spostato un nuovo server in una posizione per fornire un throughput adeguato, ricostruito completamente il sistema e ha ancora lo stesso problema. Quindi dopo tutto il mio problema è irrisolto ... = (Penso ancora che sia specifico dell'app, ma non riesco a pensare a nulla. Questo nuovo server è impostato esattamente come un altro server in cui funziona bene. Sì, somaxconn e netdev_max_backlog sono aumentati correttamente
Ben Lee,

Il tuo problema non è nginx, è più che capace - ma questo non vuol dire che potresti non avere un'impostazione canaglia. Le prese sono particolarmente sensibili sotto carico elevato quando i limiti non sono configurati correttamente. Puoi invece provare la tua app con tcp / ip?
Ben Lessani - Sonassi,

stesso problema con una grandezza ancora peggiore usando tcp / ip (la coda di scrittura sale ancora più velocemente). Ho nginx / unicorn / kernel impostato esattamente lo stesso (per quanto posso dire) su una macchina diversa, e che l'altra macchina non presenta questo problema. (Posso passare da un DNS all'altro tra le due macchine, per ottenere il test del carico in tempo reale e avere un DNS su 60 secondi)
Ben Lee,

Il throughput tra ogni macchina e una macchina db è lo stesso adesso e la latenza tra la nuova macchina e la macchina db è circa il 30% in più rispetto a quella tra vecchia macchina e db. Ma il 30% in più rispetto a un decimo di millisecondo non è il problema.
Ben Lee,

2

Potresti provare a guardare unix_dgram_qlen, vedi proc docs . Anche se questo può aggravare il problema indicando di più nella coda? Dovrai cercare (netstat -x ...)


Qualche progresso con questo?
jmw

1
Grazie per l'idea, ma questo non sembra fare alcuna differenza.
Ben Lee,

0

Ho risolto aumentando il numero di backlog in config / unicorn.rb ... Avevo un backlog di 64.

 listen "/path/tmp/sockets/manager_rails.sock", backlog: 64

e stavo ottenendo questo errore:

 2014/11/11 15:24:09 [error] 12113#0: *400 connect() to unix:/path/tmp/sockets/manager_rails.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 192.168.101.39, server: , request: "GET /welcome HTTP/1.0", upstream: "http://unix:/path/tmp/sockets/manager_rails.sock:/welcome", host: "192.168.101.93:3000"

Ora, sono aumentato a 1024 e non ricevo l'errore:

 listen "/path/tmp/sockets/manager_rails.sock", backlog: 1024

0

tl; dr

  1. Assicurati che il backlog Unicorn sia grande (usa socket, più veloce di TCP) listen("/var/www/unicorn.sock", backlog: 1024)
  2. Ottimizza le impostazioni delle prestazioni di NGINX , ad esempioworker_connections 10000;

Discussione

Abbiamo avuto lo stesso problema: un'app Rails fornita da Unicorn dietro un proxy inverso NGINX.

Stavamo ottenendo linee come queste nel registro degli errori di Nginx:

2019/01/29 15:54:37 [error] 3999#3999: *846 connect() to unix:/../unicorn.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: xx.xx.xx.xx, request: "GET / HTTP/1.1"

Leggendo le altre risposte abbiamo anche pensato che forse la colpa fosse dell'unicorno, quindi abbiamo aumentato il suo arretrato, ma questo non ha risolto il problema. Il monitoraggio dei processi del server era ovvio che Unicorn non riusciva a far funzionare le richieste, quindi NGINX sembrava essere il collo di bottiglia.

La ricerca di impostazioni NGINX da modificare in nginx.confquesto articolo di ottimizzazione delle prestazioni ha evidenziato diverse impostazioni che potrebbero influire sul numero di richieste parallele che NGINX può elaborare, in particolare:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 400000; # important

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

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;
  keepalive_requests 100000; # important
  server_names_hash_bucket_size 256;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;
  gzip on;
  gzip_disable "msie6";
  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.