Afinem RHEL/CentOs per a l’NGINX+HAPROXY en entorns de producció

Per una banda, l’Nginx es un servidor WEB molt lleuger capaç de gestionar gran quantitat de connexions concurrents amb una eficaç gestió dels recursos, jo l’he utilitzat com a servidor proxy on he balancejat el tràfic de diferents aplicacions, tan en entorns productius com en entorns de desenvolupament.

D’una altra banda utilitzarem el HAPROXY com a balancejador, ja que és un dels programaris més potents, lleugers i flexibles a l’hora de balancejar tràfic, poden implementar-ho com a balancejador HTTP o TCP, en el meu cas, HTTP amb balanceig enganxós. Per a aquest dimoni només he hagut d’afinar valors com tune.bufsize i tune.maxrewrite

En un entorn productiu cal afinar la plataforma per a tindre’ls preparats per a que ens permeti un bon rendiment, l’objectiu del post es tenir ben recopilada tota la informació que he utilitzat. Per la xarxa hi han molta documentació sobre aquest propòsit, aquí únicament els recopilarem per a tenir-ho ben recol·lectat, al final del post hi llisto les fonts.

CentOs/RHEL es la plataforma on ho he muntat, on el nginx únicament fa la funció de “reverse proxy” de diferents sites, descartant les funcionalitats de balanceig i de cache, on les he implementat amb HAProxy i Varnish-cache que ja he explicat en un altre post, aquí amb vull centrar en afinar-ho i llistar els petits problemes que m’he trobat/corregit.

Per tal d’afinar-ho, segmentem 3 configuracions diferents:

  • Paràmetres del nucli del sistema operatiu
  • Límits del sistema Operatiu
  • Configuració del nginx

Paràmetres del nucli del sistema operatiu

Valor per defecte i aplicat:

sysctl -w net.ipv4.tcp_congestion_control = cubic

Algorisme de gestió dels trafic TCP, en el paràmetre net.ipv4.tcp_available_congestion_control podem saber quines opcions tenim carregades en el kernel de linux
En CentOs6 tenim aquestes opcions: cubic reno, en el següent enllaç ho explica
http://kaivanov.blogspot.com.es/2010/09/linux-tcp-tuning.html

  • reno: Traditional TCP used by almost all other OSes. (default)
  • cubic: CUBIC-TCP (NOTE: There is a cubic bug in the Linux 2.6.18 kernel used by Redhat Enterprise Linux 5.3 and Scientific Linux 5.3. Use 2.6.18.2 or higher!)
  • bic: BIC-TCP
  • htcp: Hamilton TCP
  • vegas: TCP Vegas
  • westwood: optimized for lossy networks

Valor per defecte i aplicat:

sysctl -w net.ipv4.tcp_window_scaling = 1

Auto-escalat de la mida de la finestra de recepció TCP utilitzat, la finestra més gran pot ocupar 65,535 bytes. 1 ho activem i 0 ho desactivem.

Valor per defecte:

sysctl -w net.ipv4.ip_local_port_range="32768 61000"

Valor per aplicat:

sysctl -w net.ipv4.ip_local_port_range="2000 65000"

Defineix el conjunt de ports locals que fa servir el SO per connexions les connexions TCP i UDP

Valor per defecte:

sysctl -w net.ipv4.tcp_max_syn_backlog="2048"

Valor per aplicat:

sysctl -w net.ipv4.tcp_max_syn_backlog="204800"

Numero màxim de peticions per les connexions rebudes que encara no ha rebut el ACK del emissor, per defecte és 1024 i en sistemes de menys de 128Mb li assignem 128. Si el servidor pateix sobrecàrrega intenta incrementar aquest valor.

Valor per defecte:

sysctl -w net.core.somaxconn="128""

Valor per aplicat:

sysctl -w net.core.somaxconn="12800"

Numero màxim de connexions que estan passant de LISTEN a ESTABLISHED, si es supera aquest número de connexions establertes el sistema les rebutja.

Valor per defecte:

sysctl -w net.ipv4.tcp_max_tw_buckets="262144"

Valor per aplicat:

sysctl -w net.ipv4.tcp_max_tw_buckets="524284"

Numero màxim de connexions en estat TIME_WAIT, quant el superem, el sistema elimina els sockets i envia un avís. Aquest limit només s’utilitza per AVISAR de atacs DDOS. Aquest valor no s’acostuma a baixar sinó a incrementar proporcionalment amb la memòria, si les condicions de xarxa aixi ho requereixen.

Valor per defecte:

sysctl -w net.core.rmem_default="229376"

Valor per aplicat:

sysctl -w net.core.rmem_default="262142"

Mida de la memòria asignada per defecte en la recepció pels socket

Valor per defecte:

sysctl -w net.core.rmem_max="131071"

Valor per aplicat:

sysctl -w net.core.rmem_max="524284"

Mida màxima de memòria assignada per defecte en la recepció pels socket, aquest valor ha de ser superior al net.core.rmem_default
Alerta! En RHEL compleix aquesta ultima recomanació però en CentOS6 no ho segueix

Valor per defecte:

sysctl -w net.core.wmem_default="229376"

Valor per aplicat:

sysctl -w net.core.wmem_default="262142

Mida de memòria asignada per defecte en l’enviament pels socket

Valor per defecte:

sysctl -w net.core.wmem_max="131071"

Valor per aplicat:

sysctl -w net.core.wmem_max="524284"

Mida màxima de memòria assignada per defecte en la emissió pels socket, aquest valor ha de ser superior al net.core.rmem_default
Alerta! En RHEL compleix aquesta ultima recomanació però en CentOS6 no ho segueix

Valor per defecte i aplicat:

sysctl -w net.ipv4.tcp_rmem="4096 87380 4194304"

Paràmetres de auto configuració TCP en la recepció de dades: El primer valor es la mida mínima de memòria utilitzat per a cada connexió TCP. El segon valor especifica la mida PER DEFECTE de buffer en la recepció per a cadascun dels socket. Aquest valor sobreescriu el /proc/sys/net/core/rmem_default utilitzat en altres protocols(!=TCP). El tercer i ultim valor especifica la mida màxima de memòria per la recepció de dades per a cadascun de les connexions TCP.

Valor per defecte i aplicat:

sysctl -w net.ipv4.tcp_wmem="4096 65536 4194304"

Parametres de auto configuració TCP en la emissió: Aquests tres valors indiquen quin es l’espai de memòria assignat a cada socket en l’enviament de dades. El primer es la mida mínima, el segon la mida per defecte i el tercer la mida màxim del buffer reservat per a l’enviament de dades.

Valor per defecte:

sysctl -w net.ipv4.tcp_mem="753888 1005184 1507776"

Valor per aplicat:

sysctl -w net.ipv4.tcp_mem="753888 1005184 4194304"

Paràmetres de auto configuració TCP: Defineix com el sistema operatiu gestion l’ús de la memòria per a les connexions TCP. El primer valor especifica el umbral mínim. Per sota d’aquest valor el SO no va cap canvi de gestió de la memòria pels diferents socket TCP. El segons valor indica la mida per defecte permès per a 1a connexió TCP, el tercer valor ens indica la mida màxima de memòria utilitzat per les connexions TCP, si el SO consumeix més memòria per a les connexions TCP comença a fer DROPS de les noves connexions.

Valor per defecte i aplicat:

sysctl -w fs.file-max="793779"

Defineix el número màxim de descriptors de fitxers que gestiona el SO (Recordem que tant els sockets com els fitxers son descriptors de fitxers en entorns Linux/Unix)

Valor per defecte:

sysctl -w net.ipv4.tcp_tw_reuse="0"

Valor per aplicat:

sysctl -w net.ipv4.tcp_tw_reuse="1"

Permetre reutilitzar els sockets que estan en TIME_WAIT quant es segur des del punt de vista del protocol. Non hauria de ser modificat sense la supervisió d’un expert 😉

Valor per defecte:

sysctl -w net.ipv4.tcp_tw_recycle="0"

Valor per aplicat:

sysctl -w net.ipv4.tcp_tw_recycle="1"

Permetre la rapida reutilització de sockets en TIME_WAIT. Activant aquesta opcio no es recomenada si estas fent NAT. En canvi amb el HAPROXY es molt recomenable per baixar CONSIDERABLEMENT el numero de connexions en TIME_WAIT. Adjunto una captura de graphite on podem veure el canvi només aplicant aquesta variable.
haproxy

Valor per defecte:

sysctl -w net.ipv4.tcp_max_orphans="262144"

Valor per aplicat:

sysctl -w net.ipv4.tcp_max_orphans="30000"

Número màxim de TCP sockets orfans que no estan connectats a cap proces. Quant aquest numero s’excedeix, les connexions orfanes es resetejant i es notifica amb una alerta. Aquest limit existeix nomes per prevenir atacs de denegament de servei. Decrementar aquest valor no es aconsellable. Les condicions de xarxa poden requerir que incrementis el numero de orfans permesos, cadascun dels orfans poden ocupar aproximadament 64k de memoria NO-SWAPEJABLE. El valor per defecte es igual que el parametre NR_FILE del kernel, en 262144 en RHEL6/CentOS6, ajustat a la memoria del sistema.

Valor per defecte:

sysctl -w net.ipv4.tcp_synack_retries="5"

Valor per aplicat:

sysctl -w net.ipv4.tcp_synack_retries="3"

Número màxim de vegades que un segment SYN/ACK per a una connexio TCP passiva sera retransmitit. Aquest numero no pot excedir de 255.

Límits del sistema Operatiu
Amb concordança amb el últim paràmetre explicat en l’apartat anterior, hem de ampliar el numero de descriptors de fitxers que permetem realitzar al usuari que instancia el nginx, afegint les línies següents al fitxer /etc/security/limits.conf

nginx       soft    nofile   10000
nginx       hard    nofile   30000

Configuració del nginx
No menys important que les configuracions de sistema són la configuració del nginx.

Primerament cal dimensionar la memòria i la CPU del sistema. Cal dimensionar assignant els valors correctes de worker_processes i worker_connections tenint en compte la formula: max clients = worker_processes * worker_connections/4. En el meu cas tenim més de 1200 connexions concurrents on tinc una maquina amb 8 vCPUs i 8GB de RAM, on he assignat:

worker_processes  8;
events {
    worker_connections  1024;
}

Seguidament segons el tipus d’aplicacions que estiguem balancejant amb l’nginx, tenint en compte el número i el tipus d’aplicacions, les connexions concurrents que requereixen, la mida tant de les capçaleres com del cos, tant de les peticions com de les respostes, caldrà afinar els següents paràmetres.

## Size Limits
  client_body_buffer_size     128K;
  client_header_buffer_size   8k;
  client_max_body_size          1M;
  large_client_header_buffers 8 32k;
## Timeouts
  client_body_timeout   60;
  client_header_timeout 60;
  expires               24h;
  keepalive_timeout     60 60;
  send_timeout          60;
  proxy_connect_timeout 60s; 
  proxy_read_timeout 120s;
  proxy_send_timeout 120s
## TCP options
  tcp_nodelay on;
  tcp_nopush  on;
## Proxy options
  proxy_buffering           on;
  proxy_buffers 16 16k;
  proxy_buffer_size 32k;
##Fix header too big http://forum.nginx.org/read.php?2,188352
  fastcgi_buffers 16 16k;
  fastcgi_buffer_size 32k;

Aquests paràmetres els utilitzo per a publicar aplicacions PHP i contingut estàtic on es connecten tot tipus de navegadors tan estacions de treball, ordinadors portàtils, dispositius mòbils com tabletes des de diferents proveïdors ADSL, 2G, 3G, 4G, WiMax, FTH, etc…. Remarco que no utilitzo la funció de cache del nginx.
Seguidament faig esmena de 2 problemes que m’he trobat amb les nostres aplicacions.

Per part del Nginx, si volem augmentar les mides de la capçalera que reben del frontal a més de 16kb, també s’ha de parametritzar el parametres fastcgi_buffers i fastcgi_buffer_size tal com ho reporten en el foro aquest link, no li vaig trobar logica però va ser aplicar-ho i desapareixer.

Per part del Haproxy també hi han limitacions del tamany del buffsize, en Centos/RHEL els paquets compilats del repositori yum estan tots a 16kb, en el foro de HAPROXY trobem com recompilar-ho
Molt útil per corregir aquest tipus de errors:

echo show errors | socat stdio unix-connect:<path-to-socket>

Les principals fonts que he seguit són:

http://linux.die.net/man/7/tcp
http://dak1n1.com/blog/12-nginx-performance-tuning
http://www.cyberciti.biz/faq/rhel-linux-install-nginx-as-reverse-proxy-load-balancer/
http://www.cyberciti.biz/faq/linux-unix-nginx-too-many-open-files
http://www.exceliance.fr/sites/default/files/biblio/art-2006-making_applications_scalable_with_lb.pdf
http://comments.gmane.org/gmane.comp.web.haproxy/11145

Leave a Reply

Your email address will not be published. Required fields are marked *