Besoin d'augmenter le débit de nginx vers un socket Unix en amont - réglage du noyau Linux?

28

J'exécute un serveur nginx qui agit comme un proxy vers un socket Unix en amont, comme ceci:

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;
        }
}

Certains processus de serveur d'applications, à leur tour, retirent les demandes au /tmp/app.sockfur et à mesure qu'elles deviennent disponibles. Le serveur d'application particulier utilisé ici est Unicorn, mais je ne pense pas que cela soit pertinent pour cette question.

Le problème est, il semble juste qu'au-delà d'une certaine quantité de charge, nginx ne puisse pas recevoir les requêtes via le socket à un rythme assez rapide. Peu importe le nombre de processus de serveur d'applications que je configure.

Je reçois un flot de ces messages dans le journal des erreurs nginx:

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

De nombreuses demandes aboutissent au code d'état 502 et à celles qui ne prennent pas beaucoup de temps. La statistique de file d'attente d'écriture nginx oscille autour de 1000.

Quoi qu'il en soit, j'ai l'impression de manquer quelque chose d'évident ici, car cette configuration particulière de nginx et du serveur d'applications est assez courante, en particulier avec Unicorn (c'est la méthode recommandée en fait). Y a-t-il des options de noyau Linux qui doivent être définies, ou quelque chose dans nginx? Des idées sur la façon d'augmenter le débit vers le socket en amont? Quelque chose que je fais clairement mal?

Informations supplémentaires sur l'environnement:

$ 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

Ajustements actuels du noyau:

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

Paramètres Ulimit pour l'utilisateur 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
Ben Lee
la source
Avez-vous vérifié la sortie de ulimit, en particulier le nombre de fichiers ouverts?
Khaled
@Khaled, ulimit -ndit 65535.
Ben Lee

Réponses:

16

Il semble que le goulot d'étranglement soit l'application qui alimente le socket plutôt que Nginx lui-même. Nous voyons cela beaucoup avec PHP lorsqu'il est utilisé avec des sockets par rapport à une connexion TCP / IP. Dans notre cas, les goulots d'étranglement PHP sont beaucoup plus anciens que Nginx ne le ferait cependant.

Avez-vous vérifié la limite de suivi de connexion sysctl.conf, la limite de backlog de socket

  • net.core.somaxconn
  • net.core.netdev_max_backlog
Ben Lessani - Sonassi
la source
2
J'ai compris le problème. Voir la réponse que j'ai postée. C'était en fait le goulot d'étranglement de l'application, pas le socket, comme vous le dites. J'avais exclu cela plus tôt en raison d'un mauvais diagnostic, mais il s'avère que le problème était le débit vers un autre serveur. J'ai compris cela il y a quelques heures. Je vais vous attribuer la prime, puisque vous avez à peu près cloué la source du problème, malgré le mauvais diagnostic que j'ai posé dans la question; cependant, je vais cocher ma réponse, car ma réponse décrit les circonstances exactes et pourrait donc aider quelqu'un à l'avenir avec un problème similaire.
Ben Lee
Vous avez déplacé un nouveau serveur vers un emplacement pour fournir un débit adéquat, complètement reconstruit le système et rencontrez toujours le même problème. Il s'avère donc que mon problème n'est pas résolu après tout ... = (Je pense toujours que c'est spécifique à l'application, mais je ne pense à rien. Ce nouveau serveur est configuré exactement comme un autre serveur où il fonctionne bien. Oui, somaxconn et netdev_max_backlog sont st up correctement
Ben Lee
Votre problème n'est pas nginx, il est plus que capable - mais cela ne veut pas dire que vous ne disposez peut-être pas d'un paramètre escroc. Les sockets sont particulièrement sensibles sous forte charge lorsque les limites ne sont pas configurées correctement. Pouvez-vous essayer votre application avec TCP / IP à la place?
Ben Lessani - Sonassi
même problème avec une ampleur encore pire en utilisant tcp / ip (la file d'attente d'écriture grimpe encore plus rapidement). J'ai nginx / unicorn / kernel tous configurés exactement de la même manière (pour autant que je sache) sur une autre machine, et cette autre machine ne présente pas ce problème. (Je peux basculer le DNS entre les deux machines, pour obtenir des tests de charge en direct et avoir un DNS sur un ttl de 60 secondes)
Ben Lee
Le débit entre chaque machine et une machine db est le même maintenant, et la latence entre la nouvelle machine et la machine db est d'environ 30% de plus qu'entre l'ancienne machine et la base de données. Mais 30% de plus qu'un dixième de milliseconde n'est pas le problème.
Ben Lee
2

Vous pouvez essayer de regarder unix_dgram_qlen, voir proc docs . Bien que cela puisse aggraver le problème en pointant davantage dans la file d'attente? Vous devrez regarder (netstat -x ...)

jmw
la source
Des progrès avec ça?
jmw
1
Merci pour l'idée, mais cela ne semble pas faire de différence.
Ben Lee
0

J'ai résolu en augmentant le nombre de backlog dans le fichier config / unicorn.rb ... J'avais un backlog de 64.

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

et je recevais cette erreur:

 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"

Maintenant, j'ai augmenté à 1024 et je ne reçois pas l'erreur:

 listen "/path/tmp/sockets/manager_rails.sock", backlog: 1024
Adrian
la source
0

tl; dr

  1. Assurez-vous que le backlog Unicorn est important (utilisez socket, plus rapide que TCP) listen("/var/www/unicorn.sock", backlog: 1024)
  2. Optimiser les paramètres de performances NGINX , par exempleworker_connections 10000;

Discussion

Nous avons eu le même problème - une application Rails servie par Unicorn derrière un proxy inverse NGINX.

Nous obtenions des lignes comme celles-ci dans le journal des erreurs 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"

En lisant les autres réponses, nous avons également pensé que peut-être Unicorn était à blâmer, nous avons donc augmenté son arriéré, mais cela n'a pas résolu le problème. En surveillant les processus du serveur, il était évident qu'Unicorn ne recevait pas les demandes, NGINX semblait donc être le goulot d'étranglement.

La recherche de paramètres NGINX à modifier dans nginx.confcet article sur l' optimisation des performances a souligné plusieurs paramètres qui pourraient avoir un impact sur le nombre de demandes parallèles que NGINX peut traiter, en particulier:

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/*;
}
Epigene
la source