haproxy, czyli mieszania pakietami HTTP ciąg dalszy

Ostatnio pisałem o haproxy jako balanserze dla ruchu HTTP, dziś chciałbym uzupełnić poprzedni opis o coś co nazywane jest popularnie content switchingiem... czyli kierowanie ruchu HTTP na podstawie żądanego contentu/typu danych. Dla prostszego wyobrażenia sytuacji przygotowałem taki obrazek:

mamy jeden serwis w jednej domenie http://yoursite.pl/ i posiadamy tylko jeden adres IP, ale chcemy podawać content w zależności od żądanego pliku z różnych serwerów, apache sprawdzi się przy (.php .html), lighttpd lekki, szybki, zwinny, etc. doskonale poradzi sobie z obrazkami (.gif .jpg), a nginx'a chcemy użyć bo też jest modny, do podawania (.js .css), bez balancera w postaci haproxy który pracuje w 7 warstwie i potrafi analizować i wykonywać przeróżne akcje niczym ninja z filmów z dzieciństwa na nagłówkach HTTP byłoby to trochę bardziej skomplikowane. Zakładam, że mamy działające haproxy i pozostałe serwery httpd, jeśli tak to można troszkę pobawić się konfiguracją.

Zacznę od wyjaśnienia kilku pojęć:

  • frontend - zgodnie z dokumentacją, frontendem jest nasza usługa która przyjmuje połączenia od użytkowników i je proxy'uje dalej do backendów.
  • backend - to definicja serwerów które odbierają ruch od balancer'a i zwracają wyniki, w naszym przypadku backendami są serwery Apache, Lighttpd, Nginx.
  • acl - Access List, dzięki acl'kom możemy zmatchować dany request np. na podstawie src, dst, path_reg, path_end

Nasza konfiguracja haproxy będzie wyglądać następująco:

root@xen7:~# cat /etc/haproxy.cfg

global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
maxconn 4096
user haproxy
group haproxy

defaults
log global
mode http
option httplog
option dontlognull
retries 3
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
option httpclose

frontend frontend_xen
bind 192.168.1.220:80
option forwardfor

acl acl_apache path_end .php .html
acl acl_lighttpd path_end .gif .jpg
acl acl_nginx path_end .css .js

use_backend backend_xen2 if acl_apache
use_backend backend_xen3 if acl_lighttpd
use_backend backend_xen4 if acl_nginx
default_backend backend_xen2

backend backend_xen2
mode http
balance roundrobin
server xen2 192.168.1.241:80 check

backend backend_xen3
mode http
balance roundrobin
server xen3 192.168.1.242:80 check

backend backend_xen4
mode http
balance roundrobin
server xen4 192.168.1.125:80 check

Po starcie daemona przeprowadzamy mały test:

$ lwp-request -Sde http://xen7/test.php | grep Server
Server: Apache/2.2.8 (Ubuntu)

$ lwp-request -Sde http://xen7/test.css | grep Server
Server: nginx/0.5.33

$ lwp-request -Sde http://xen7/test.jpg | grep Server
Server: lighttpd/1.4.19

Kluczową rolę odegrały definicje frontendu oraz backendów, ale bez ACL nie moglibyśmy powiedzieć balancer'owi jaki ruch gdzie kierować. Definiujemy więc 3 ACLe (acl_apache, acl_lighttpd, acl_nginx) gdzie warunkiem jest rozszerzenie:

acl acl_apache path_end .php .html
acl acl_lighttpd path_end .gif .jpg
acl acl_nginx path_end .css .js

składnia:
acl nazwa_acla sposób_matchowania warunek

Kolejny bardzo ważny element konfiguracji to wskazanie balancerowi gdzie ma kierować ruch po dopasowaniu do konkretnej acl'ki:

use_backend backend_xen2 if acl_apache
use_backend backend_xen3 if acl_lighttpd
use_backend backend_xen4 if acl_nginx
default_backend backend_xen2

Jeśli request pasuje do ACL acl_apache to kieruj do backend_xen2, jeśli pasuje do acl_lighttpd to kieruj do backend_xen3, itd... jeśli nie dopasuje do żadnej acl kieruje do default'owego backendu backend_xen2.

Bardzo proste do wdrożenia i daje nam ogromne możliwości zarządzania streamem HTTP, operowanie na rozszerzeniach to ułamek możliwości tego load balancer'a, będę starał się co jakiś czas, opisywać inne/pozostałe ciekawe przykłady wykorzystania haproxy.

A jakie Wy widzicie zastosowanie dla tego mechanizmu?