Aplicații Open Source pentru HTTP Load Balancing
1Nota editorului: Articol scris de tex pe RSTCenter.com.
Împărțirea încărcării serverelor reprezintă distribuirea anumitor procese și comunicații pe mai multe servere pentru ca nici unul din ele să nu ajungă să fie supraîncărcat. În general, siturile cu foarte multă activitate folosesc mai multe servere care conțin aceeași informație. Vizitatorii sunt distribuiți pe toate serverele, pentru a evita supraîncărcarea unuia dintre ele.
În acest tutorial o să vă prezint mai multe soluții de load balancing utilizând aplicații open source. Există scule hardware care fac lucrul ăsta, însă pe mulți bani, și de multe ori o să vedeți că o combinație de genul FreeBSD+Haproxy sau nginx depășește cu mult specificațiile unui load balancer hardware care ajunge la un preț foarte mare.
Folosire nginx ca load balancer
În ciuda faptului că nu este conceput pentru asta, nginx are suport pentru load balancing. De exemplu, puteți face un server pe care să-l utilizați ca load balancer, iar în spatele acestuia se pot pune un număr nelimitat de servere web (o să le numim generic „nodes”).
În exemplul de mai jos, 10.0.0.8, 10.0.0.9, 10.0.0.10 și 10.0.0.11 reprezintă serverele web ce se află în spatele balancerului. Numărul de requesturi primite de nginx se vor distribui în mod egal către aceste servere.
user nobody; worker_processes 6; timer_resolution 200ms; worker_rlimit_nofile 240000; events { use kqueue; worker_connections 22000; } http { include mime.types; default_type application/octet-stream; reset_timedout_connection on; msie_padding off; sendfile on; keepalive_requests 100; keepalive_timeout 5; tcp_nopush off; tcp_nodelay on; server_tokens off; send_timeout 3; client_max_body_size 1024m; client_body_buffer_size 128k; client_header_buffer_size 64k; proxy_connect_timeout 120; proxy_send_timeout 120; proxy_read_timeout 120; proxy_buffer_size 16k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; gzip on; gzip_min_length 1000; gzip_buffers 4 8k; gzip_static off; gzip_comp_level 9; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain text/css text/xml application/xml text/javascript application/x-javascript; upstream backends { server 10.0.0.8; server 10.0.0.9; server 10.0.0.10; server 10.0.0.11; } server { listen 0.0.0.0:80 default rcvbuf=32000 sndbuf=46000 backlog=1000 accept_filter=httpready accept_filter=dataready; server_name _; # Main location location / { proxy_pass http://backends; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /status { stub_status on; access_log off; } } }
În cazul în care doriți să implementați și failover pe noduri (lucru recomandat), aveți la îndemână opțiunile „max_fails” și „fail_timeout”. Să spunem că dorim să nu mai fie trimise requesturi către serverul cu adresa ip 10.0.0.10 în cazul în care este nefuncțional (după ce face fail de 3 ori cu timeout de 20 de secunde).
Exemplu:
upstream backends { server 10.0.0.8; server 10.0.0.9; server 10.0.0.10 max_fails=3 fail_timeout=20; server 10.0.0.11; }
Load balancer cu haproxy
Dacă nu ați auzit până acum de haproxy sau nu ați folosit, vă recomand să citiți câte ceva despre el. Combinația FreeBSD+haproxy poate înlocui cu succes un load balancer comercial care ajunge la costuri de multe zero-uri în euro. Pentru documentație, vă invit să vizitați această pagină.
În exemplul de mai jos, am să vă arăt un fișier de configurare („haproxy.conf”), similar cu exemplul din tutorialul de mai sus, „Folosire nginx ca load balancer”. Adresele IP 10.0.0.2, 10.0.0.3, 10.0.0.4, 10.0.0.5, 10.0.0.6, 10.0.0.7, 10.0.0.8 și 10.0.0.9 sunt nodurile balancerului (serverele web) iar 10.0.0.1 este adresa ip a balancerului, cea pe care vom primi request-urile. Am „botezat” nodurile acestui balancer cu numele planetelor din sistemul solar 😉
global log 127.0.0.1 local0 maxconn 280000 user nobody group nobody nbproc 8 # Number de procesoare (fizice) pidfile /var/run/haproxy.pid daemon defaults mode http option httpclose option abortonclose option httplog option dontlognull option httpclose retries 3 maxconn 240000 monitor-uri /haproxy-ping option redispatch contimeout 5000 clitimeout 50000 srvtimeout 50000 listen HTTP_SERVERFARM 10.0.0.1:80 mode http retries 3 option redispatch maxconn 36000 contimeout 5000 clitimeout 50000 srvtimeout 50000 option httpclose option forwardfor # This sets X-Forwarded-For balance roundrobin # Load Balancing algorithm stats enable stats uri /balancer-status monitor-uri /haproxy-ping option httpchk server MERCURY 10.0.0.2:80 weight 1 maxconn 3000 check inter 160000 server VENUS 10.0.0.3:80 weight 1 maxconn 3000 check inter 160000 server EARTH 10.0.0.4:80 weight 1 maxconn 3000 check inter 160000 server MARS 10.0.0.5:80 weight 1 maxconn 3000 check inter 160000 server JUPITER 10.0.0.6:80 weight 1 maxconn 3000 check inter 160000 server SATURN 10.0.0.7:80 weight 1 maxconn 3000 check inter 160000 server URANUS 10.0.0.8:80 weight 1 maxconn 3000 check inter 160000 server NEPTUNE 10.0.0.9:80 weight 1 maxconn 3000 check inter 160000
Load balancing cu packet filter pe FreeBSD
În acest scurt tutorial nu am să scriu despre load balancing-ul unor multiple conexiuni la internet, și am să mă rezum strict la load balancing-ul serverelor web. Packet filterul suportă nativ definirea unei ferme de servere web către care pot distribui request-urile venite. De asemenea, suportă metodele „round-robin” și „sticky-address”
Round-Rubin reprezintă o tehnică de load balancing prin care cererile sunt plasate/trimise către o fermă de noduri. De exemplu, să presupunem că o companie deține un site foarte mare și dorește să-l găzduiască pe trei servere. În fata acestor servere o să vină configurat un load balancer, care va distribui cererile sosite pe port 80 către cele trei servere. În cazul „round-rubin”, când un utilizator va accesa site-ul web, requesturile acestuia vor fi trimise către primul server, al II-lea utilizator va fi trimis către al II-lea server iar al III-lea vizitator ce va accesa site-ul va fi trimis către serverul al III-lea. Restul de requesturi de la utilizatori o să fie trimise în același mod către noduri, până lista (coada de așteptare) va ajunge la capăt.
Sticky-Address reprezintă un procedeu în care request-urile venite de la aceeași sursa, vor fi trimise către aceeași destinație (same-path). Acest procedeu persistă atâta timp cat sunt „states” (sesiuni tcp) în lista de așteptare. Mai exact: Conexiunile de la o SURSA UNICĂ vor fi trimise către același server web (node).
În exemplul de mai jos, am să definesc serverele web cu adresele IP: 10.0.0.2, 10.0.0.3, 10.0.0.4, iar configurația o să vina făcută pe serverul folosit ca load balancer (server care va avea configurată o adresă IP publică, pe care va primi cererile de la vizitatori).
ext_if = "bce0" webservers = "{ 10.0.0.2, 10.0.0.3, 10.0.0.4 }" rdr on $ext_if inet proto tcp from any to $ext_if port 80 -> $webservers round-robin sticky-address
Nota: Nu se poate face failover.
Load balancing cu apache
Utilizând apache, se poate face load balancing cu ajutorul modulelor mod_proxy și mod_proxy_balancer. Algoritmii de balansare sunt: Request Counting, Weighted Traffic Counting și Pending Request Counting. Acești alogoritmi de balansare pot fi controlați prin lbmethod.
lbmethod=byrequests pentru "Request Counting Algorithm" lbmethod=bytraffic pentru "Weighted Traffic Counting Algorithm" lbmethod=bybusyness pentru "Pending Request Counting Algorithm"
O să definesc în exemplul de mai jos, nodurile cu 10.0.0.2, 10.0.0.3, 10.0.0.4.
<Proxy balancer://webcluster> BalancerMember http://10.0.0.2:80 BalancerMember http://10.0.0.3:80 BalancerMember http://10.0.0.4:80 </Proxy> ProxySet lbmethod=byrequests ProxyPreserveHost on ProxyRequests Off ProxyPass / balancer://webcluster ProxyPassReverse / balancer://webcluster
Puteți citi mai multe despre mod_proxy_balancer aici. Notă: Vă recomand apache worker pentru load balancing cu apache. Apache prefork este un mare consumator de resurse. Limitați-vă doar la modulele absolut necesare.
HAProxy e cel mai bun dupa parerea mea, merge bine si cu WebSockets.