blob: 7d80f1bc53cd645843545b30a4214aba28928335 [file] [log] [blame]
willy tarreau0174f312005-12-18 01:02:42 +01001 -------------------
Willy Tarreau94b45912006-05-31 06:40:15 +02002 HAProxy
willy tarreau0174f312005-12-18 01:02:42 +01003 Architecture Guide
4 -------------------
willy tarreau065f1c02006-01-29 22:10:07 +01005 version 1.1.34
willy tarreau0174f312005-12-18 01:02:42 +01006 willy tarreau
willy tarreau065f1c02006-01-29 22:10:07 +01007 2006/01/29
willy tarreau0174f312005-12-18 01:02:42 +01008
9
10This document provides real world examples with working configurations.
11Please note that except stated otherwise, global configuration parameters
12such as logging, chrooting, limits and time-outs are not described here.
13
14===================================================
151. Simple HTTP load-balancing with cookie insertion
16===================================================
17
18A web application often saturates the front-end server with high CPU loads,
19due to the scripting language involved. It also relies on a back-end database
20which is not much loaded. User contexts are stored on the server itself, and
21not in the database, so that simply adding another server with simple IP/TCP
22load-balancing would not work.
23
24 +-------+
25 |clients| clients and/or reverse-proxy
26 +---+---+
27 |
28 -+-----+--------+----
29 | _|_db
30 +--+--+ (___)
31 | web | (___)
32 +-----+ (___)
33 192.168.1.1 192.168.1.2
34
35
36Replacing the web server with a bigger SMP system would cost much more than
37adding low-cost pizza boxes. The solution is to buy N cheap boxes and install
38the application on them. Install haproxy on the old one which will spread the
39load across the new boxes.
40
41 192.168.1.1 192.168.1.11-192.168.1.14 192.168.1.2
42 -------+-----------+-----+-----+-----+--------+----
43 | | | | | _|_db
44 +--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
45 | LB1 | | A | | B | | C | | D | (___)
46 +-----+ +---+ +---+ +---+ +---+ (___)
47 haproxy 4 cheap web servers
48
49
50Config on haproxy (LB1) :
51-------------------------
52
willy tarreauc5f73ed2005-12-18 01:26:38 +010053 listen webfarm 192.168.1.1:80
willy tarreau0174f312005-12-18 01:02:42 +010054 mode http
55 balance roundrobin
56 cookie SERVERID insert indirect
57 option httpchk HEAD /index.html HTTP/1.0
58 server webA 192.168.1.11:80 cookie A check
59 server webB 192.168.1.12:80 cookie B check
60 server webC 192.168.1.13:80 cookie C check
61 server webD 192.168.1.14:80 cookie D check
62
63
64Description :
65-------------
66 - LB1 will receive clients requests.
67 - if a request does not contain a cookie, it will be forwarded to a valid
68 server
69 - in return, a cookie "SERVERID" will be inserted in the response holding the
70 server name (eg: "A").
71 - when the client comes again with the cookie "SERVERID=A", LB1 will know that
72 it must be forwarded to server A. The cookie will be removed so that the
73 server does not see it.
74 - if server "webA" dies, the requests will be sent to another valid server
75 and a cookie will be reassigned.
76
77
78Flows :
79-------
80
81(client) (haproxy) (server A)
82 >-- GET /URI1 HTTP/1.0 ------------> |
83 ( no cookie, haproxy forwards in load-balancing mode. )
84 | >-- GET /URI1 HTTP/1.0 ---------->
85 | <-- HTTP/1.0 200 OK -------------<
86 ( the proxy now adds the server cookie in return )
87 <-- HTTP/1.0 200 OK ---------------< |
88 Set-Cookie: SERVERID=A |
89 >-- GET /URI2 HTTP/1.0 ------------> |
90 Cookie: SERVERID=A |
91 ( the proxy sees the cookie. it forwards to server A and deletes it )
92 | >-- GET /URI2 HTTP/1.0 ---------->
93 | <-- HTTP/1.0 200 OK -------------<
94 ( the proxy does not add the cookie in return because the client knows it )
95 <-- HTTP/1.0 200 OK ---------------< |
96 >-- GET /URI3 HTTP/1.0 ------------> |
97 Cookie: SERVERID=A |
98 ( ... )
99
100
101Limits :
102--------
103 - if clients use keep-alive (HTTP/1.1), only the first response will have
104 a cookie inserted, and only the first request of each session will be
105 analyzed. This does not cause trouble in insertion mode because the cookie
106 is put immediately in the first response, and the session is maintained to
107 the same server for all subsequent requests in the same session. However,
108 the cookie will not be removed from the requests forwarded to the servers,
109 so the server must not be sensitive to unknown cookies. If this causes
110 trouble, you can disable keep-alive by adding the following option :
111
112 option httpclose
113
114 - if for some reason the clients cannot learn more than one cookie (eg: the
115 clients are indeed some home-made applications or gateways), and the
116 application already produces a cookie, you can use the "prefix" mode (see
117 below).
118
119 - LB1 becomes a very sensible server. If LB1 dies, nothing works anymore.
Willy Tarreau4fb20ff2007-03-17 21:55:50 +0100120 => you can back it up using keepalived (see below)
willy tarreau0174f312005-12-18 01:02:42 +0100121
122 - if the application needs to log the original client's IP, use the
123 "forwardfor" option which will add an "X-Forwarded-For" header with the
124 original client's IP address. You must also use "httpclose" to ensure
125 that you will rewrite every requests and not only the first one of each
126 session :
127
128 option httpclose
129 option forwardfor
130
131 The web server will have to be configured to use this header instead.
132 For example, on apache, you can use LogFormat for this :
133
134 LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b " combined
135 CustomLog /var/log/httpd/access_log combined
136
Willy Tarreau4fb20ff2007-03-17 21:55:50 +0100137Hints :
138-------
139Sometimes on the internet, you will find a few percent of the clients which
140disable cookies on their browser. Obviously they have troubles everywhere on
141the web, but you can still help them access your site by using the "source"
142balancing algorithm instead of the "roundrobin". It ensures that a given IP
143address always reaches the same server as long as the number of servers remains
144unchanged. Never use this behind a proxy or in a small network, because the
145distribution will be unfair. However, in large internal networks, and on the
146internet, it works quite well. Clients which have a dynamic address will not
147be affected as long as they accept the cookie, because the cookie always has
148precedence over load balancing :
149
150 listen webfarm 192.168.1.1:80
151 mode http
152 balance source
153 cookie SERVERID insert indirect
154 option httpchk HEAD /index.html HTTP/1.0
155 server webA 192.168.1.11:80 cookie A check
156 server webB 192.168.1.12:80 cookie B check
157 server webC 192.168.1.13:80 cookie C check
158 server webD 192.168.1.14:80 cookie D check
159
willy tarreau0174f312005-12-18 01:02:42 +0100160
161==================================================================
1622. HTTP load-balancing with cookie prefixing and high availability
163==================================================================
164
165Now you don't want to add more cookies, but rather use existing ones. The
166application already generates a "JSESSIONID" cookie which is enough to track
167sessions, so we'll prefix this cookie with the server name when we see it.
168Since the load-balancer becomes critical, it will be backed up with a second
willy tarreauc5f73ed2005-12-18 01:26:38 +0100169one in VRRP mode using keepalived under Linux.
willy tarreau0174f312005-12-18 01:02:42 +0100170
171Download the latest version of keepalived from this site and install it
172on each load-balancer LB1 and LB2 :
173
174 http://www.keepalived.org/
175
176You then have a shared IP between the two load-balancers (we will still use the
177original IP). It is active only on one of them at any moment. To allow the
willy tarreauc5f73ed2005-12-18 01:26:38 +0100178proxy to bind to the shared IP on Linux 2.4, you must enable it in /proc :
willy tarreau0174f312005-12-18 01:02:42 +0100179
180# echo 1 >/proc/sys/net/ipv4/ip_nonlocal_bind
181
182
183 shared IP=192.168.1.1
184 192.168.1.3 192.168.1.4 192.168.1.11-192.168.1.14 192.168.1.2
185 -------+------------+-----------+-----+-----+-----+--------+----
186 | | | | | | _|_db
187 +--+--+ +--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
188 | LB1 | | LB2 | | A | | B | | C | | D | (___)
189 +-----+ +-----+ +---+ +---+ +---+ +---+ (___)
190 haproxy haproxy 4 cheap web servers
191 keepalived keepalived
192
193
194Config on both proxies (LB1 and LB2) :
195--------------------------------------
196
willy tarreauc5f73ed2005-12-18 01:26:38 +0100197 listen webfarm 192.168.1.1:80
willy tarreau0174f312005-12-18 01:02:42 +0100198 mode http
199 balance roundrobin
200 cookie JSESSIONID prefix
201 option httpclose
202 option forwardfor
203 option httpchk HEAD /index.html HTTP/1.0
204 server webA 192.168.1.11:80 cookie A check
205 server webB 192.168.1.12:80 cookie B check
206 server webC 192.168.1.13:80 cookie C check
207 server webD 192.168.1.14:80 cookie D check
208
209
210Notes: the proxy will modify EVERY cookie sent by the client and the server,
211so it is important that it can access to ALL cookies in ALL requests for
212each session. This implies that there is no keep-alive (HTTP/1.1), thus the
213"httpclose" option. Only if you know for sure that the client(s) will never
willy tarreauc5f73ed2005-12-18 01:26:38 +0100214use keep-alive (eg: Apache 1.3 in reverse-proxy mode), you can remove this
215option.
willy tarreau0174f312005-12-18 01:02:42 +0100216
Willy Tarreau4fb20ff2007-03-17 21:55:50 +0100217
218Configuration for keepalived on LB1/LB2 :
219-----------------------------------------
220
221 vrrp_script chk_haproxy { # Requires keepalived-1.1.13
222 script "killall -0 haproxy" # cheaper than pidof
223 interval 2 # check every 2 seconds
224 weight 2 # add 2 points of prio if OK
225 }
226
227 vrrp_instance VI_1 {
228 interface eth0
229 state MASTER
230 virtual_router_id 51
231 priority 101 # 101 on master, 100 on backup
232 virtual_ipaddress {
233 192.168.1.1
234 }
235 track_script {
236 chk_haproxy
237 }
238 }
239
willy tarreau0174f312005-12-18 01:02:42 +0100240
241Description :
242-------------
Willy Tarreau4fb20ff2007-03-17 21:55:50 +0100243 - LB1 is VRRP master (keepalived), LB2 is backup. Both monitor the haproxy
244 process, and lower their prio if it fails, leading to a failover to the
245 other node.
willy tarreau0174f312005-12-18 01:02:42 +0100246 - LB1 will receive clients requests on IP 192.168.1.1.
247 - both load-balancers send their checks from their native IP.
248 - if a request does not contain a cookie, it will be forwarded to a valid
249 server
250 - in return, if a JESSIONID cookie is seen, the server name will be prefixed
251 into it, followed by a delimitor ('~')
252 - when the client comes again with the cookie "JSESSIONID=A~xxx", LB1 will
253 know that it must be forwarded to server A. The server name will then be
254 extracted from cookie before it is sent to the server.
255 - if server "webA" dies, the requests will be sent to another valid server
256 and a cookie will be reassigned.
257
258
259Flows :
260-------
261
262(client) (haproxy) (server A)
263 >-- GET /URI1 HTTP/1.0 ------------> |
264 ( no cookie, haproxy forwards in load-balancing mode. )
265 | >-- GET /URI1 HTTP/1.0 ---------->
266 | X-Forwarded-For: 10.1.2.3
267 | <-- HTTP/1.0 200 OK -------------<
268 ( no cookie, nothing changed )
269 <-- HTTP/1.0 200 OK ---------------< |
270 >-- GET /URI2 HTTP/1.0 ------------> |
271 ( no cookie, haproxy forwards in lb mode, possibly to another server. )
272 | >-- GET /URI2 HTTP/1.0 ---------->
273 | X-Forwarded-For: 10.1.2.3
274 | <-- HTTP/1.0 200 OK -------------<
275 | Set-Cookie: JSESSIONID=123
276 ( the cookie is identified, it will be prefixed with the server name )
277 <-- HTTP/1.0 200 OK ---------------< |
278 Set-Cookie: JSESSIONID=A~123 |
279 >-- GET /URI3 HTTP/1.0 ------------> |
280 Cookie: JSESSIONID=A~123 |
281 ( the proxy sees the cookie, removes the server name and forwards
282 to server A which sees the same cookie as it previously sent )
283 | >-- GET /URI3 HTTP/1.0 ---------->
284 | Cookie: JSESSIONID=123
285 | X-Forwarded-For: 10.1.2.3
286 | <-- HTTP/1.0 200 OK -------------<
287 ( no cookie, nothing changed )
288 <-- HTTP/1.0 200 OK ---------------< |
289 ( ... )
290
Willy Tarreau4fb20ff2007-03-17 21:55:50 +0100291Hints :
292-------
293Sometimes, there will be some powerful servers in the farm, and some smaller
294ones. In this situation, it may be desirable to tell haproxy to respect the
295difference in performance. Let's consider that WebA and WebB are two old
296P3-1.2 GHz while WebC and WebD are shiny new Opteron-2.6 GHz. If your
297application scales with CPU, you may assume a very rough 2.6/1.2 performance
298ratio between the servers. You can inform haproxy about this using the "weight"
299keyword, with values between 1 and 256. It will then spread the load the most
300smoothly possible respecting those ratios :
301
302 server webA 192.168.1.11:80 cookie A weight 12 check
303 server webB 192.168.1.12:80 cookie B weight 12 check
304 server webC 192.168.1.13:80 cookie C weight 26 check
305 server webD 192.168.1.14:80 cookie D weight 26 check
willy tarreau0174f312005-12-18 01:02:42 +0100306
307
308========================================================
3092.1 Variations involving external layer 4 load-balancers
310========================================================
311
312Instead of using a VRRP-based active/backup solution for the proxies,
313they can also be load-balanced by a layer4 load-balancer (eg: Alteon)
314which will also check that the services run fine on both proxies :
315
316 | VIP=192.168.1.1
317 +----+----+
318 | Alteon |
319 +----+----+
320 |
321 192.168.1.3 | 192.168.1.4 192.168.1.11-192.168.1.14 192.168.1.2
322 -------+-----+------+-----------+-----+-----+-----+--------+----
323 | | | | | | _|_db
324 +--+--+ +--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
325 | LB1 | | LB2 | | A | | B | | C | | D | (___)
326 +-----+ +-----+ +---+ +---+ +---+ +---+ (___)
327 haproxy haproxy 4 cheap web servers
328
329
330Config on both proxies (LB1 and LB2) :
331--------------------------------------
332
willy tarreauc5f73ed2005-12-18 01:26:38 +0100333 listen webfarm 0.0.0.0:80
willy tarreau0174f312005-12-18 01:02:42 +0100334 mode http
335 balance roundrobin
336 cookie JSESSIONID prefix
337 option httpclose
338 option forwardfor
339 option httplog
340 option dontlognull
341 option httpchk HEAD /index.html HTTP/1.0
342 server webA 192.168.1.11:80 cookie A check
343 server webB 192.168.1.12:80 cookie B check
344 server webC 192.168.1.13:80 cookie C check
345 server webD 192.168.1.14:80 cookie D check
346
347The "dontlognull" option is used to prevent the proxy from logging the health
348checks from the Alteon. If a session exchanges no data, then it will not be
349logged.
350
willy tarreauc5f73ed2005-12-18 01:26:38 +0100351Config on the Alteon :
352----------------------
353
354 /c/slb/real 11
355 ena
356 name "LB1"
357 rip 192.168.1.3
358 /c/slb/real 12
359 ena
360 name "LB2"
361 rip 192.168.1.4
362 /c/slb/group 10
363 name "LB1-2"
364 metric roundrobin
365 health tcp
366 add 11
367 add 12
368 /c/slb/virt 10
369 ena
370 vip 192.168.1.1
371 /c/slb/virt 10/service http
372 group 10
373
374
375Note: the health-check on the Alteon is set to "tcp" to prevent the proxy from
376forwarding the connections. It can also be set to "http", but for this the
377proxy must specify a "monitor-net" with the Alteons' addresses, so that the
378Alteon can really check that the proxies can talk HTTP but without forwarding
379the connections to the end servers. Check next section for an example on how to
380use monitor-net.
381
382
383============================================================
3842.2 Generic TCP relaying and external layer 4 load-balancers
385============================================================
386
387Sometimes it's useful to be able to relay generic TCP protocols (SMTP, TSE,
388VNC, etc...), for example to interconnect private networks. The problem comes
389when you use external load-balancers which need to send periodic health-checks
390to the proxies, because these health-checks get forwarded to the end servers.
391The solution is to specify a network which will be dedicated to monitoring
392systems and must not lead to a forwarding connection nor to any log, using the
393"monitor-net" keyword. Note: this feature expects a version of haproxy greater
394than or equal to 1.1.32 or 1.2.6.
395
396
397 | VIP=172.16.1.1 |
398 +----+----+ +----+----+
399 | Alteon1 | | Alteon2 |
400 +----+----+ +----+----+
401 192.168.1.252 | GW=192.168.1.254 | 192.168.1.253
402 | |
403 ------+---+------------+--+-----------------> TSE farm : 192.168.1.10
404 192.168.1.1 | | 192.168.1.2
405 +--+--+ +--+--+
406 | LB1 | | LB2 |
407 +-----+ +-----+
408 haproxy haproxy
409
410
411Config on both proxies (LB1 and LB2) :
412--------------------------------------
413
414 listen tse-proxy
415 bind :3389,:1494,:5900 # TSE, ICA and VNC at once.
416 mode tcp
417 balance roundrobin
418 server tse-farm 192.168.1.10
419 monitor-net 192.168.1.252/31
420
421The "monitor-net" option instructs the proxies that any connection coming from
422192.168.1.252 or 192.168.1.253 will not be logged nor forwarded and will be
423closed immediately. The Alteon load-balancers will then see the proxies alive
424without perturbating the service.
425
willy tarreau0174f312005-12-18 01:02:42 +0100426Config on the Alteon :
427----------------------
428
willy tarreauc5f73ed2005-12-18 01:26:38 +0100429 /c/l3/if 1
430 ena
431 addr 192.168.1.252
432 mask 255.255.255.0
433 /c/slb/real 11
434 ena
435 name "LB1"
436 rip 192.168.1.1
437 /c/slb/real 12
438 ena
439 name "LB2"
440 rip 192.168.1.2
441 /c/slb/group 10
442 name "LB1-2"
443 metric roundrobin
444 health tcp
445 add 11
446 add 12
447 /c/slb/virt 10
448 ena
449 vip 172.16.1.1
450 /c/slb/virt 10/service 1494
451 group 10
452 /c/slb/virt 10/service 3389
453 group 10
454 /c/slb/virt 10/service 5900
455 group 10
willy tarreau0174f312005-12-18 01:02:42 +0100456
457
Willy Tarreau4fb20ff2007-03-17 21:55:50 +0100458Special handling of SSL :
459-------------------------
460Sometimes, you want to send health-checks to remote systems, even in TCP mode,
461in order to be able to failover to a backup server in case the first one is
462dead. Of course, you can simply enable TCP health-checks, but it sometimes
463happens that intermediate firewalls between the proxies and the remote servers
464acknowledge the TCP connection themselves, showing an always-up server. Since
465this is generally encountered on long-distance communications, which often
466involve SSL, an SSL health-check has been implemented to workaround this issue.
467It sends SSL Hello messages to the remote server, which in turns replies with
468SSL Hello messages. Setting it up is very easy :
469
470 listen tcp-syslog-proxy
471 bind :1514 # listen to TCP syslog traffic on this port (SSL)
472 mode tcp
473 balance roundrobin
474 option ssl-hello-chk
475 server syslog-prod-site 192.168.1.10 check
476 server syslog-back-site 192.168.2.10 check backup
477
478
willy tarreau0174f312005-12-18 01:02:42 +0100479=========================================================
4803. Simple HTTP/HTTPS load-balancing with cookie insertion
481=========================================================
482
483This is the same context as in example 1 above, but the web
484server uses HTTPS.
485
486 +-------+
487 |clients| clients
488 +---+---+
489 |
490 -+-----+--------+----
491 | _|_db
492 +--+--+ (___)
493 | SSL | (___)
494 | web | (___)
495 +-----+
496 192.168.1.1 192.168.1.2
497
498
499Since haproxy does not handle SSL, this part will have to be extracted from the
500servers (freeing even more ressources) and installed on the load-balancer
501itself. Install haproxy and apache+mod_ssl on the old box which will spread the
502load between the new boxes. Apache will work in SSL reverse-proxy-cache. If the
503application is correctly developped, it might even lower its load. However,
504since there now is a cache between the clients and haproxy, some security
505measures must be taken to ensure that inserted cookies will not be cached.
506
507
508 192.168.1.1 192.168.1.11-192.168.1.14 192.168.1.2
509 -------+-----------+-----+-----+-----+--------+----
510 | | | | | _|_db
511 +--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
512 | LB1 | | A | | B | | C | | D | (___)
513 +-----+ +---+ +---+ +---+ +---+ (___)
514 apache 4 cheap web servers
515 mod_ssl
516 haproxy
517
518
519Config on haproxy (LB1) :
520-------------------------
521
522 listen 127.0.0.1:8000
523 mode http
524 balance roundrobin
525 cookie SERVERID insert indirect nocache
526 option httpchk HEAD /index.html HTTP/1.0
527 server webA 192.168.1.11:80 cookie A check
528 server webB 192.168.1.12:80 cookie B check
529 server webC 192.168.1.13:80 cookie C check
530 server webD 192.168.1.14:80 cookie D check
531
532
533Description :
534-------------
535 - apache on LB1 will receive clients requests on port 443
536 - it forwards it to haproxy bound to 127.0.0.1:8000
537 - if a request does not contain a cookie, it will be forwarded to a valid
538 server
539 - in return, a cookie "SERVERID" will be inserted in the response holding the
540 server name (eg: "A"), and a "Cache-control: private" header will be added
541 so that the apache does not cache any page containing such cookie.
542 - when the client comes again with the cookie "SERVERID=A", LB1 will know that
543 it must be forwarded to server A. The cookie will be removed so that the
544 server does not see it.
545 - if server "webA" dies, the requests will be sent to another valid server
546 and a cookie will be reassigned.
547
548Notes :
549-------
550 - if the cookie works in "prefix" mode, there is no need to add the "nocache"
551 option because it is an application cookie which will be modified, and the
552 application flags will be preserved.
553 - if apache 1.3 is used as a front-end before haproxy, it always disables
554 HTTP keep-alive on the back-end, so there is no need for the "httpclose"
555 option on haproxy.
556 - configure apache to set the X-Forwarded-For header itself, and do not do
557 it on haproxy if you need the application to know about the client's IP.
558
559
560Flows :
561-------
562
563(apache) (haproxy) (server A)
564 >-- GET /URI1 HTTP/1.0 ------------> |
565 ( no cookie, haproxy forwards in load-balancing mode. )
566 | >-- GET /URI1 HTTP/1.0 ---------->
567 | <-- HTTP/1.0 200 OK -------------<
568 ( the proxy now adds the server cookie in return )
569 <-- HTTP/1.0 200 OK ---------------< |
570 Set-Cookie: SERVERID=A |
571 Cache-Control: private |
572 >-- GET /URI2 HTTP/1.0 ------------> |
573 Cookie: SERVERID=A |
574 ( the proxy sees the cookie. it forwards to server A and deletes it )
575 | >-- GET /URI2 HTTP/1.0 ---------->
576 | <-- HTTP/1.0 200 OK -------------<
577 ( the proxy does not add the cookie in return because the client knows it )
578 <-- HTTP/1.0 200 OK ---------------< |
579 >-- GET /URI3 HTTP/1.0 ------------> |
580 Cookie: SERVERID=A |
581 ( ... )
582
583
584
585========================================
Willy Tarreau4fb20ff2007-03-17 21:55:50 +01005863.1. Alternate solution using Stunnel
587========================================
588
589When only SSL is required and cache is not needed, stunnel is a cheaper
590solution than Apache+mod_ssl. By default, stunnel does not process HTTP and
591does not add any X-Forwarded-For header, but there is a patch on the official
592haproxy site to provide this feature to recent stunnel versions.
593
594This time, stunnel will only process HTTPS and not HTTP. This means that
595haproxy will get all HTTP traffic, so haproxy will have to add the
596X-Forwarded-For header for HTTP traffic, but not for HTTPS traffic since
597stunnel will already have done it. We will use the "except" keyword to tell
598haproxy that connections from local host already have a valid header.
599
600
601 192.168.1.1 192.168.1.11-192.168.1.14 192.168.1.2
602 -------+-----------+-----+-----+-----+--------+----
603 | | | | | _|_db
604 +--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
605 | LB1 | | A | | B | | C | | D | (___)
606 +-----+ +---+ +---+ +---+ +---+ (___)
607 stunnel 4 cheap web servers
608 haproxy
609
610
611Config on stunnel (LB1) :
612-------------------------
613
614 cert=/etc/stunnel/stunnel.pem
615 setuid=stunnel
616 setgid=proxy
617
618 socket=l:TCP_NODELAY=1
619 socket=r:TCP_NODELAY=1
620
621 [https]
622 accept=192.168.1.1:443
623 connect=192.168.1.1:80
624 xforwardedfor=yes
625
626
627Config on haproxy (LB1) :
628-------------------------
629
630 listen 192.168.1.1:80
631 mode http
632 balance roundrobin
633 option forwardfor except 192.168.1.1
634 cookie SERVERID insert indirect nocache
635 option httpchk HEAD /index.html HTTP/1.0
636 server webA 192.168.1.11:80 cookie A check
637 server webB 192.168.1.12:80 cookie B check
638 server webC 192.168.1.13:80 cookie C check
639 server webD 192.168.1.14:80 cookie D check
640
641Description :
642-------------
643 - stunnel on LB1 will receive clients requests on port 443
644 - it forwards them to haproxy bound to port 80
645 - haproxy will receive HTTP client requests on port 80 and decrypted SSL
646 requests from Stunnel on the same port.
647 - stunnel will add the X-Forwarded-For header
648 - haproxy will add the X-Forwarded-For header for everyone except the local
649 address (stunnel).
650
651
652========================================
willy tarreau0174f312005-12-18 01:02:42 +01006534. Soft-stop for application maintenance
654========================================
655
willy tarreau22739ef2006-01-20 20:43:32 +0100656When an application is spread across several servers, the time to update all
willy tarreau0174f312005-12-18 01:02:42 +0100657instances increases, so the application seems jerky for a longer period.
658
659HAproxy offers several solutions for this. Although it cannot be reconfigured
willy tarreauc5f73ed2005-12-18 01:26:38 +0100660without being stopped, nor does it offer any external command, there are other
willy tarreau0174f312005-12-18 01:02:42 +0100661working solutions.
662
663
664=========================================
6654.1 Soft-stop using a file on the servers
666=========================================
667
668This trick is quite common and very simple: put a file on the server which will
669be checked by the proxy. When you want to stop the server, first remove this
670file. The proxy will see the server as failed, and will not send it any new
671session, only the old ones if the "persist" option is used. Wait a bit then
672stop the server when it does not receive anymore connections.
673
674
675 listen 192.168.1.1:80
676 mode http
677 balance roundrobin
678 cookie SERVERID insert indirect
679 option httpchk HEAD /running HTTP/1.0
680 server webA 192.168.1.11:80 cookie A check inter 2000 rise 2 fall 2
681 server webB 192.168.1.12:80 cookie B check inter 2000 rise 2 fall 2
682 server webC 192.168.1.13:80 cookie C check inter 2000 rise 2 fall 2
683 server webD 192.168.1.14:80 cookie D check inter 2000 rise 2 fall 2
684 option persist
685 redispatch
686 contimeout 5000
687
688
689Description :
690-------------
691 - every 2 seconds, haproxy will try to access the file "/running" on the
692 servers, and declare the server as down after 2 attempts (4 seconds).
693 - only the servers which respond with a 200 or 3XX response will be used.
694 - if a request does not contain a cookie, it will be forwarded to a valid
695 server
696 - if a request contains a cookie for a failed server, haproxy will insist
697 on trying to reach the server anyway, to let the user finish what he was
698 doing. ("persist" option)
699 - if the server is totally stopped, the connection will fail and the proxy
700 will rebalance the client to another server ("redispatch")
701
702Usage on the web servers :
703--------------------------
704- to start the server :
705 # /etc/init.d/httpd start
706 # touch /home/httpd/www/running
707
708- to soft-stop the server
709 # rm -f /home/httpd/www/running
710
711- to completely stop the server :
712 # /etc/init.d/httpd stop
713
714Limits
715------
716If the server is totally powered down, the proxy will still try to reach it
717for those clients who still have a cookie referencing it, and the connection
718attempt will expire after 5 seconds ("contimeout"), and only after that, the
719client will be redispatched to another server. So this mode is only useful
720for software updates where the server will suddenly refuse the connection
721because the process is stopped. The problem is the same if the server suddenly
722crashes. All of its users will be fairly perturbated.
723
724
725==================================
7264.2 Soft-stop using backup servers
727==================================
728
729A better solution which covers every situation is to use backup servers.
730Version 1.1.30 fixed a bug which prevented a backup server from sharing
731the same cookie as a standard server.
732
733
734 listen 192.168.1.1:80
735 mode http
736 balance roundrobin
737 redispatch
738 cookie SERVERID insert indirect
739 option httpchk HEAD / HTTP/1.0
740 server webA 192.168.1.11:80 cookie A check port 81 inter 2000
741 server webB 192.168.1.12:80 cookie B check port 81 inter 2000
742 server webC 192.168.1.13:80 cookie C check port 81 inter 2000
743 server webD 192.168.1.14:80 cookie D check port 81 inter 2000
744
745 server bkpA 192.168.1.11:80 cookie A check port 80 inter 2000 backup
746 server bkpB 192.168.1.12:80 cookie B check port 80 inter 2000 backup
747 server bkpC 192.168.1.13:80 cookie C check port 80 inter 2000 backup
748 server bkpD 192.168.1.14:80 cookie D check port 80 inter 2000 backup
749
750Description
751-----------
752Four servers webA..D are checked on their port 81 every 2 seconds. The same
753servers named bkpA..D are checked on the port 80, and share the exact same
754cookies. Those servers will only be used when no other server is available
755for the same cookie.
756
757When the web servers are started, only the backup servers are seen as
758available. On the web servers, you need to redirect port 81 to local
759port 80, either with a local proxy (eg: a simple haproxy tcp instance),
760or with iptables (linux) or pf (openbsd). This is because we want the
761real web server to reply on this port, and not a fake one. Eg, with
762iptables :
763
764 # /etc/init.d/httpd start
765 # iptables -t nat -A PREROUTING -p tcp --dport 81 -j REDIRECT --to-port 80
766
767A few seconds later, the standard server is seen up and haproxy starts to send
768it new requests on its real port 80 (only new users with no cookie, of course).
769
770If a server completely crashes (even if it does not respond at the IP level),
771both the standard and backup servers will fail, so clients associated to this
772server will be redispatched to other live servers and will lose their sessions.
773
774Now if you want to enter a server into maintenance, simply stop it from
775responding on port 81 so that its standard instance will be seen as failed,
776but the backup will still work. Users will not notice anything since the
777service is still operational :
778
779 # iptables -t nat -D PREROUTING -p tcp --dport 81 -j REDIRECT --to-port 80
780
781The health checks on port 81 for this server will quickly fail, and the
782standard server will be seen as failed. No new session will be sent to this
783server, and existing clients with a valid cookie will still reach it because
784the backup server will still be up.
785
786Now wait as long as you want for the old users to stop using the service, and
787once you see that the server does not receive any traffic, simply stop it :
788
789 # /etc/init.d/httpd stop
790
791The associated backup server will in turn fail, and if any client still tries
792to access this particular server, he will be redispatched to any other valid
793server because of the "redispatch" option.
794
795This method has an advantage : you never touch the proxy when doing server
796maintenance. The people managing the servers can make them disappear smoothly.
797
798
7994.2.1 Variations for operating systems without any firewall software
800--------------------------------------------------------------------
801
802The downside is that you need a redirection solution on the server just for
803the health-checks. If the server OS does not support any firewall software,
804this redirection can also be handled by a simple haproxy in tcp mode :
805
806 global
807 daemon
808 quiet
809 pidfile /var/run/haproxy-checks.pid
810 listen 0.0.0.0:81
811 mode tcp
812 dispatch 127.0.0.1:80
813 contimeout 1000
814 clitimeout 10000
815 srvtimeout 10000
816
817To start the web service :
818
819 # /etc/init.d/httpd start
820 # haproxy -f /etc/haproxy/haproxy-checks.cfg
821
822To soft-stop the service :
823
824 # kill $(</var/run/haproxy-checks.pid)
825
willy tarreauc5f73ed2005-12-18 01:26:38 +0100826The port 81 will stop responding and the load-balancer will notice the failure.
willy tarreau0174f312005-12-18 01:02:42 +0100827
828
8294.2.2 Centralizing the server management
830----------------------------------------
831
willy tarreauc5f73ed2005-12-18 01:26:38 +0100832If one finds it preferable to manage the servers from the load-balancer itself,
willy tarreau0174f312005-12-18 01:02:42 +0100833the port redirector can be installed on the load-balancer itself. See the
834example with iptables below.
835
836Make the servers appear as operational :
837 # iptables -t nat -A OUTPUT -d 192.168.1.11 -p tcp --dport 81 -j DNAT --to-dest :80
838 # iptables -t nat -A OUTPUT -d 192.168.1.12 -p tcp --dport 81 -j DNAT --to-dest :80
839 # iptables -t nat -A OUTPUT -d 192.168.1.13 -p tcp --dport 81 -j DNAT --to-dest :80
840 # iptables -t nat -A OUTPUT -d 192.168.1.14 -p tcp --dport 81 -j DNAT --to-dest :80
841
842Soft stop one server :
843 # iptables -t nat -D OUTPUT -d 192.168.1.12 -p tcp --dport 81 -j DNAT --to-dest :80
844
845Another solution is to use the "COMAFILE" patch provided by Alexander Lazic,
846which is available for download here :
847
848 http://w.ods.org/tools/haproxy/contrib/
849
850
8514.2.3 Notes :
852-------------
853 - Never, ever, start a fake service on port 81 for the health-checks, because
854 a real web service failure will not be detected as long as the fake service
855 runs. You must really forward the check port to the real application.
856
857 - health-checks will be sent twice as often, once for each standard server,
willy tarreau22739ef2006-01-20 20:43:32 +0100858 and once for each backup server. All this will be multiplicated by the
willy tarreauc5f73ed2005-12-18 01:26:38 +0100859 number of processes if you use multi-process mode. You will have to ensure
860 that all the checks sent to the server do not overload it.
willy tarreau0174f312005-12-18 01:02:42 +0100861
willy tarreau22739ef2006-01-20 20:43:32 +0100862=======================
8634.3 Hot reconfiguration
864=======================
865
866There are two types of haproxy users :
867 - those who can never do anything in production out of maintenance periods ;
868 - those who can do anything at any time provided that the consequences are
869 limited.
870
871The first ones have no problem stopping the server to change configuration
872because they got some maintenance periods during which they can break anything.
873So they will even prefer doing a clean stop/start sequence to ensure everything
874will work fine upon next reload. Since those have represented the majority of
875haproxy uses, there has been little effort trying to improve this.
876
877However, the second category is a bit different. They like to be able to fix an
878error in a configuration file without anyone noticing. This can sometimes also
879be the case for the first category because humans are not failsafe.
880
881For this reason, a new hot reconfiguration mechanism has been introduced in
882version 1.1.34. Its usage is very simple and works even in chrooted
883environments with lowered privileges. The principle is very simple : upon
884reception of a SIGTTOU signal, the proxy will stop listening to all the ports.
885This will release the ports so that a new instance can be started. Existing
886connections will not be broken at all. If the new instance fails to start,
887then sending a SIGTTIN signal back to the original processes will restore
888the listening ports. This is possible without any special privileges because
889the sockets will not have been closed, so the bind() is still valid. Otherwise,
890if the new process starts successfully, then sending a SIGUSR1 signal to the
891old one ensures that it will exit as soon as its last session ends.
892
893A hot reconfiguration script would look like this :
894
895 # save previous state
896 mv /etc/haproxy/config /etc/haproxy/config.old
897 mv /var/run/haproxy.pid /var/run/haproxy.pid.old
898
899 mv /etc/haproxy/config.new /etc/haproxy/config
900 kill -TTOU $(cat /var/run/haproxy.pid.old)
901 if haproxy -p /var/run/haproxy.pid -f /etc/haproxy/config; then
902 echo "New instance successfully loaded, stopping previous one."
903 kill -USR1 $(cat /var/run/haproxy.pid.old)
904 rm -f /var/run/haproxy.pid.old
905 exit 1
906 else
907 echo "New instance failed to start, resuming previous one."
908 kill -TTIN $(cat /var/run/haproxy.pid.old)
909 rm -f /var/run/haproxy.pid
910 mv /var/run/haproxy.pid.old /var/run/haproxy.pid
911 mv /etc/haproxy/config /etc/haproxy/config.new
912 mv /etc/haproxy/config.old /etc/haproxy/config
913 exit 0
914 fi
915
916After this, you can still force old connections to end by sending
917a SIGTERM to the old process if it still exists :
918
919 kill $(cat /var/run/haproxy.pid.old)
920 rm -f /var/run/haproxy.pid.old
921
922Be careful with this as in multi-process mode, some pids might already
923have been reallocated to completely different processes.
924
willy tarreau0174f312005-12-18 01:02:42 +0100925
926==================================================
9275. Multi-site load-balancing with local preference
928==================================================
929
9305.1 Description of the problem
931==============================
932
933Consider a world-wide company with sites on several continents. There are two
934production sites SITE1 and SITE2 which host identical applications. There are
935many offices around the world. For speed and communication cost reasons, each
936office uses the nearest site by default, but can switch to the backup site in
937the event of a site or application failure. There also are users on the
938production sites, which use their local sites by default, but can switch to the
939other site in case of a local application failure.
940
941The main constraints are :
942
943 - application persistence : although the application is the same on both
944 sites, there is no session synchronisation between the sites. A failure
945 of one server or one site can cause a user to switch to another server
946 or site, but when the server or site comes back, the user must not switch
947 again.
948
949 - communication costs : inter-site communication should be reduced to the
950 minimum. Specifically, in case of a local application failure, every
951 office should be able to switch to the other site without continuing to
952 use the default site.
953
9545.2 Solution
955============
956 - Each production site will have two haproxy load-balancers in front of its
957 application servers to balance the load across them and provide local HA.
958 We will call them "S1L1" and "S1L2" on site 1, and "S2L1" and "S2L2" on
959 site 2. These proxies will extend the application's JSESSIONID cookie to
960 put the server name as a prefix.
961
962 - Each production site will have one front-end haproxy director to provide
963 the service to local users and to remote offices. It will load-balance
964 across the two local load-balancers, and will use the other site's
965 load-balancers as backup servers. It will insert the local site identifier
966 in a SITE cookie for the local load-balancers, and the remote site
967 identifier for the remote load-balancers. These front-end directors will
968 be called "SD1" and "SD2" for "Site Director".
969
970 - Each office will have one haproxy near the border gateway which will direct
971 local users to their preference site by default, or to the backup site in
972 the event of a previous failure. It will also analyze the SITE cookie, and
973 direct the users to the site referenced in the cookie. Thus, the preferred
974 site will be declared as a normal server, and the backup site will be
975 declared as a backup server only, which will only be used when the primary
976 site is unreachable, or when the primary site's director has forwarded
977 traffic to the second site. These proxies will be called "OP1".."OPXX"
978 for "Office Proxy #XX".
979
980
9815.3 Network diagram
982===================
983
984Note : offices 1 and 2 are on the same continent as site 1, while
985 office 3 is on the same continent as site 3. Each production
986 site can reach the second one either through the WAN or through
987 a dedicated link.
988
989
990 Office1 Office2 Office3
991 users users users
992192.168 # # # 192.168 # # # # # #
993.1.0/24 | | | .2.0/24 | | | 192.168.3.0/24 | | |
994 --+----+-+-+- --+----+-+-+- ---+----+-+-+-
995 | | .1 | | .1 | | .1
996 | +-+-+ | +-+-+ | +-+-+
997 | |OP1| | |OP2| | |OP3| ...
998 ,-:-. +---+ ,-:-. +---+ ,-:-. +---+
999 ( X ) ( X ) ( X )
1000 `-:-' `-:-' ,---. `-:-'
1001 --+---------------+------+----~~~( X )~~~~-------+---------+-
1002 | `---' |
1003 | |
1004 +---+ ,-:-. +---+ ,-:-.
1005 |SD1| ( X ) |SD2| ( X )
1006 ( SITE 1 ) +-+-+ `-:-' ( SITE 2 ) +-+-+ `-:-'
1007 |.1 | |.1 |
1008 10.1.1.0/24 | | ,---. 10.2.1.0/24 | |
1009 -+-+-+-+-+-+-+-----+-+--( X )------+-+-+-+-+-+-+-----+-+--
1010 | | | | | | | `---' | | | | | | |
1011 ...# # # # # |.11 |.12 ...# # # # # |.11 |.12
1012 Site 1 +-+--+ +-+--+ Site 2 +-+--+ +-+--+
1013 Local |S1L1| |S1L2| Local |S2L1| |S2L2|
1014 users +-+--+ +--+-+ users +-+--+ +--+-+
1015 | | | |
1016 10.1.2.0/24 -+-+-+--+--++-- 10.2.2.0/24 -+-+-+--+--++--
1017 |.1 |.4 |.1 |.4
1018 +-+-+ +-+-+ +-+-+ +-+-+
1019 |W11| ~~~ |W14| |W21| ~~~ |W24|
1020 +---+ +---+ +---+ +---+
1021 4 application servers 4 application servers
1022 on site 1 on site 2
1023
1024
1025
10265.4 Description
1027===============
1028
10295.4.1 Local users
1030-----------------
1031 - Office 1 users connect to OP1 = 192.168.1.1
1032 - Office 2 users connect to OP2 = 192.168.2.1
1033 - Office 3 users connect to OP3 = 192.168.3.1
1034 - Site 1 users connect to SD1 = 10.1.1.1
1035 - Site 2 users connect to SD2 = 10.2.1.1
1036
10375.4.2 Office proxies
1038--------------------
1039 - Office 1 connects to site 1 by default and uses site 2 as a backup.
1040 - Office 2 connects to site 1 by default and uses site 2 as a backup.
1041 - Office 3 connects to site 2 by default and uses site 1 as a backup.
1042
1043The offices check the local site's SD proxy every 30 seconds, and the
1044remote one every 60 seconds.
1045
1046
1047Configuration for Office Proxy OP1
1048----------------------------------
1049
1050 listen 192.168.1.1:80
1051 mode http
1052 balance roundrobin
1053 redispatch
1054 cookie SITE
1055 option httpchk HEAD / HTTP/1.0
1056 server SD1 10.1.1.1:80 cookie SITE1 check inter 30000
1057 server SD2 10.2.1.1:80 cookie SITE2 check inter 60000 backup
1058
1059
1060Configuration for Office Proxy OP2
1061----------------------------------
1062
1063 listen 192.168.2.1:80
1064 mode http
1065 balance roundrobin
1066 redispatch
1067 cookie SITE
1068 option httpchk HEAD / HTTP/1.0
1069 server SD1 10.1.1.1:80 cookie SITE1 check inter 30000
1070 server SD2 10.2.1.1:80 cookie SITE2 check inter 60000 backup
1071
1072
1073Configuration for Office Proxy OP3
1074----------------------------------
1075
1076 listen 192.168.3.1:80
1077 mode http
1078 balance roundrobin
1079 redispatch
1080 cookie SITE
1081 option httpchk HEAD / HTTP/1.0
1082 server SD2 10.2.1.1:80 cookie SITE2 check inter 30000
1083 server SD1 10.1.1.1:80 cookie SITE1 check inter 60000 backup
1084
1085
10865.4.3 Site directors ( SD1 and SD2 )
1087------------------------------------
1088The site directors forward traffic to the local load-balancers, and set a
1089cookie to identify the site. If no local load-balancer is available, or if
1090the local application servers are all down, it will redirect traffic to the
1091remote site, and report this in the SITE cookie. In order not to uselessly
1092load each site's WAN link, each SD will check the other site at a lower
1093rate. The site directors will also insert their client's address so that
1094the application server knows which local user or remote site accesses it.
1095
1096The SITE cookie which is set by these directors will also be understood
1097by the office proxies. This is important because if SD1 decides to forward
1098traffic to site 2, it will write "SITE2" in the "SITE" cookie, and on next
1099request, the office proxy will automatically and directly talk to SITE2 if
1100it can reach it. If it cannot, it will still send the traffic to SITE1
1101where SD1 will in turn try to reach SITE2.
1102
1103The load-balancers checks are performed on port 81. As we'll see further,
1104the load-balancers provide a health monitoring port 81 which reroutes to
1105port 80 but which allows them to tell the SD that they are going down soon
1106and that the SD must not use them anymore.
1107
1108
1109Configuration for SD1
1110---------------------
1111
1112 listen 10.1.1.1:80
1113 mode http
1114 balance roundrobin
1115 redispatch
1116 cookie SITE insert indirect
1117 option httpchk HEAD / HTTP/1.0
1118 option forwardfor
1119 server S1L1 10.1.1.11:80 cookie SITE1 check port 81 inter 4000
1120 server S1L2 10.1.1.12:80 cookie SITE1 check port 81 inter 4000
1121 server S2L1 10.2.1.11:80 cookie SITE2 check port 81 inter 8000 backup
1122 server S2L2 10.2.1.12:80 cookie SITE2 check port 81 inter 8000 backup
1123
1124Configuration for SD2
1125---------------------
1126
1127 listen 10.2.1.1:80
1128 mode http
1129 balance roundrobin
1130 redispatch
1131 cookie SITE insert indirect
1132 option httpchk HEAD / HTTP/1.0
1133 option forwardfor
1134 server S2L1 10.2.1.11:80 cookie SITE2 check port 81 inter 4000
1135 server S2L2 10.2.1.12:80 cookie SITE2 check port 81 inter 4000
1136 server S1L1 10.1.1.11:80 cookie SITE1 check port 81 inter 8000 backup
1137 server S1L2 10.1.1.12:80 cookie SITE1 check port 81 inter 8000 backup
1138
1139
11405.4.4 Local load-balancers S1L1, S1L2, S2L1, S2L2
1141-------------------------------------------------
1142Please first note that because SD1 and SD2 use the same cookie for both
1143servers on a same site, the second load-balancer of each site will only
1144receive load-balanced requests, but as soon as the SITE cookie will be
1145set, only the first LB will receive the requests because it will be the
1146first one to match the cookie.
1147
1148The load-balancers will spread the load across 4 local web servers, and
1149use the JSESSIONID provided by the application to provide server persistence
1150using the new 'prefix' method. Soft-stop will also be implemented as described
1151in section 4 above. Moreover, these proxies will provide their own maintenance
1152soft-stop. Port 80 will be used for application traffic, while port 81 will
1153only be used for health-checks and locally rerouted to port 80. A grace time
1154will be specified to service on port 80, but not on port 81. This way, a soft
1155kill (kill -USR1) on the proxy will only kill the health-check forwarder so
1156that the site director knows it must not use this load-balancer anymore. But
1157the service will still work for 20 seconds and as long as there are established
1158sessions.
1159
1160These proxies will also be the only ones to disable HTTP keep-alive in the
1161chain, because it is enough to do it at one place, and it's necessary to do
1162it with 'prefix' cookies.
1163
1164Configuration for S1L1/S1L2
1165---------------------------
1166
1167 listen 10.1.1.11:80 # 10.1.1.12:80 for S1L2
1168 grace 20000 # don't kill us until 20 seconds have elapsed
1169 mode http
1170 balance roundrobin
1171 cookie JSESSIONID prefix
1172 option httpclose
1173 option forwardfor
1174 option httpchk HEAD / HTTP/1.0
1175 server W11 10.1.2.1:80 cookie W11 check port 81 inter 2000
1176 server W12 10.1.2.2:80 cookie W12 check port 81 inter 2000
1177 server W13 10.1.2.3:80 cookie W13 check port 81 inter 2000
1178 server W14 10.1.2.4:80 cookie W14 check port 81 inter 2000
1179
1180 server B11 10.1.2.1:80 cookie W11 check port 80 inter 4000 backup
1181 server B12 10.1.2.2:80 cookie W12 check port 80 inter 4000 backup
1182 server B13 10.1.2.3:80 cookie W13 check port 80 inter 4000 backup
1183 server B14 10.1.2.4:80 cookie W14 check port 80 inter 4000 backup
1184
1185 listen 10.1.1.11:81 # 10.1.1.12:81 for S1L2
1186 mode tcp
1187 dispatch 10.1.1.11:80 # 10.1.1.12:80 for S1L2
1188
1189
1190Configuration for S2L1/S2L2
1191---------------------------
1192
1193 listen 10.2.1.11:80 # 10.2.1.12:80 for S2L2
1194 grace 20000 # don't kill us until 20 seconds have elapsed
1195 mode http
1196 balance roundrobin
1197 cookie JSESSIONID prefix
1198 option httpclose
1199 option forwardfor
1200 option httpchk HEAD / HTTP/1.0
1201 server W21 10.2.2.1:80 cookie W21 check port 81 inter 2000
1202 server W22 10.2.2.2:80 cookie W22 check port 81 inter 2000
1203 server W23 10.2.2.3:80 cookie W23 check port 81 inter 2000
1204 server W24 10.2.2.4:80 cookie W24 check port 81 inter 2000
1205
1206 server B21 10.2.2.1:80 cookie W21 check port 80 inter 4000 backup
1207 server B22 10.2.2.2:80 cookie W22 check port 80 inter 4000 backup
1208 server B23 10.2.2.3:80 cookie W23 check port 80 inter 4000 backup
1209 server B24 10.2.2.4:80 cookie W24 check port 80 inter 4000 backup
1210
1211 listen 10.2.1.11:81 # 10.2.1.12:81 for S2L2
1212 mode tcp
1213 dispatch 10.2.1.11:80 # 10.2.1.12:80 for S2L2
1214
1215
12165.5 Comments
1217------------
1218Since each site director sets a cookie identifying the site, remote office
1219users will have their office proxies direct them to the right site and stick
1220to this site as long as the user still uses the application and the site is
1221available. Users on production sites will be directed to the right site by the
1222site directors depending on the SITE cookie.
1223
1224If the WAN link dies on a production site, the remote office users will not
1225see their site anymore, so they will redirect the traffic to the second site.
1226If there are dedicated inter-site links as on the diagram above, the second
1227SD will see the cookie and still be able to reach the original site. For
1228example :
1229
1230Office 1 user sends the following to OP1 :
1231 GET / HTTP/1.0
1232 Cookie: SITE=SITE1; JSESSIONID=W14~123;
1233
1234OP1 cannot reach site 1 because its external router is dead. So the SD1 server
1235is seen as dead, and OP1 will then forward the request to SD2 on site 2,
1236regardless of the SITE cookie.
1237
1238SD2 on site 2 receives a SITE cookie containing "SITE1". Fortunately, it
1239can reach Site 1's load balancers S1L1 and S1L2. So it forwards the request
1240so S1L1 (the first one with the same cookie).
1241
1242S1L1 (on site 1) finds "W14" in the JSESSIONID cookie, so it can forward the
1243request to the right server, and the user session will continue to work. Once
1244the Site 1's WAN link comes back, OP1 will see SD1 again, and will not route
1245through SITE 2 anymore.
1246
1247However, when a new user on Office 1 connects to the application during a
1248site 1 failure, it does not contain any cookie. Since OP1 does not see SD1
1249because of the network failure, it will direct the request to SD2 on site 2,
1250which will by default direct the traffic to the local load-balancers, S2L1 and
1251S2L2. So only initial users will load the inter-site link, not the new ones.
1252
1253
1254===================
12556. Source balancing
1256===================
1257
1258Sometimes it may reveal useful to access servers from a pool of IP addresses
1259instead of only one or two. Some equipments (NAT firewalls, load-balancers)
1260are sensible to source address, and often need many sources to distribute the
1261load evenly amongst their internal hash buckets.
1262
1263To do this, you simply have to use several times the same server with a
1264different source. Example :
1265
1266 listen 0.0.0.0:80
1267 mode tcp
1268 balance roundrobin
1269 server from1to1 10.1.1.1:80 source 10.1.2.1
1270 server from2to1 10.1.1.1:80 source 10.1.2.2
1271 server from3to1 10.1.1.1:80 source 10.1.2.3
1272 server from4to1 10.1.1.1:80 source 10.1.2.4
1273 server from5to1 10.1.1.1:80 source 10.1.2.5
1274 server from6to1 10.1.1.1:80 source 10.1.2.6
1275 server from7to1 10.1.1.1:80 source 10.1.2.7
1276 server from8to1 10.1.1.1:80 source 10.1.2.8
1277
Willy Tarreau4fb20ff2007-03-17 21:55:50 +01001278
1279=============================================
12807. Managing high loads on application servers
1281=============================================
1282
1283One of the roles often expected from a load balancer is to mitigate the load on
1284the servers during traffic peaks. More and more often, we see heavy frameworks
1285used to deliver flexible and evolutive web designs, at the cost of high loads
1286on the servers, or very low concurrency. Sometimes, response times are also
1287rather high. People developing web sites relying on such frameworks very often
1288look for a load balancer which is able to distribute the load in the most
1289evenly fashion and which will be nice with the servers.
1290
1291There is a powerful feature in haproxy which achieves exactly this : request
1292queueing associated with concurrent connections limit.
1293
1294Let's say you have an application server which supports at most 20 concurrent
1295requests. You have 3 servers, so you can accept up to 60 concurrent HTTP
1296connections, which often means 30 concurrent users in case of keep-alive (2
1297persistent connections per user).
1298
1299Even if you disable keep-alive, if the server takes a long time to respond,
1300you still have a high risk of multiple users clicking at the same time and
1301having their requests unserved because of server saturation. To workaround
1302the problem, you increase the concurrent connection limit on the servers,
1303but their performance stalls under higher loads.
1304
1305The solution is to limit the number of connections between the clients and the
1306servers. You set haproxy to limit the number of connections on a per-server
1307basis, and you let all the users you want connect to it. It will then fill all
1308the servers up to the configured connection limit, and will put the remaining
1309connections in a queue, waiting for a connection to be released on a server.
1310
1311This ensures five essential principles :
1312
1313 - all clients can be served whatever their number without crashing the
1314 servers, the only impact it that the response time can be delayed.
1315
1316 - the servers can be used at full throttle without the risk of stalling,
1317 and fine tuning can lead to optimal performance.
1318
1319 - response times can be reduced by making the servers work below the
1320 congestion point, effectively leading to shorter response times even
1321 under moderate loads.
1322
1323 - no domino effect when a server goes down or starts up. Requests will be
1324 queued more or less, always respecting servers limits.
1325
1326 - it's easy to achieve high performance even on memory-limited hardware.
1327 Indeed, heavy frameworks often consume huge amounts of RAM and not always
1328 all the CPU available. In case of wrong sizing, reducing the number of
1329 concurrent connections will protect against memory shortages while still
1330 ensuring optimal CPU usage.
1331
1332
1333Example :
1334---------
1335
1336Haproxy is installed in front of an application servers farm. It will limit
1337the concurrent connections to 4 per server (one thread per CPU), thus ensuring
1338very fast response times.
1339
1340
1341 192.168.1.1 192.168.1.11-192.168.1.13 192.168.1.2
1342 -------+-------------+-----+-----+------------+----
1343 | | | | _|_db
1344 +--+--+ +-+-+ +-+-+ +-+-+ (___)
1345 | LB1 | | A | | B | | C | (___)
1346 +-----+ +---+ +---+ +---+ (___)
1347 haproxy 3 application servers
1348 with heavy frameworks
1349
1350
1351Config on haproxy (LB1) :
1352-------------------------
1353
1354 listen appfarm 192.168.1.1:80
1355 mode http
1356 maxconn 10000
1357 option httpclose
1358 option forwardfor
1359 balance roundrobin
1360 cookie SERVERID insert indirect
1361 option httpchk HEAD /index.html HTTP/1.0
1362 server railsA 192.168.1.11:80 cookie A maxconn 4 check
1363 server railsB 192.168.1.12:80 cookie B maxconn 4 check
1364 server railsC 192.168.1.13:80 cookie C maxconn 4 check
1365 contimeout 60000
1366
1367
1368Description :
1369-------------
1370The proxy listens on IP 192.168.1.1, port 80, and expects HTTP requests. It
1371can accept up to 10000 concurrent connections on this socket. It follows the
1372roundrobin algorithm to assign servers to connections as long as servers are
1373not saturated.
1374
1375It allows up to 4 concurrent connections per server, and will queue the
1376requests above this value. The "contimeout" parameter is used to set the
1377maximum time a connection may take to establish on a server, but here it
1378is also used to set the maximum time a connection may stay unserved in the
1379queue (1 minute here).
1380
1381If the servers can each process 4 requests in 10 ms on average, then at 3000
1382connections, response times will be delayed by at most :
1383
1384 3000 / 3 servers / 4 conns * 10 ms = 2.5 seconds
1385
1386Which is not that dramatic considering the huge number of users for such a low
1387number of servers.
1388
1389When connection queues fill up and application servers are starving, response
1390times will grow and users might abort by clicking on the "Stop" button. It is
1391very undesirable to send aborted requests to servers, because they will eat
1392CPU cycles for nothing.
1393
1394An option has been added to handle this specific case : "option abortonclose".
1395By specifying it, you tell haproxy that if an input channel is closed on the
1396client side AND the request is still waiting in the queue, then it is highly
1397likely that the user has stopped, so we remove the request from the queue
1398before it will get served.
1399
1400
1401Managing unfair response times
1402------------------------------
1403
1404Sometimes, the application server will be very slow for some requests (eg:
1405login page) and faster for other requests. This may cause excessive queueing
1406of expectedly fast requests when all threads on the server are blocked on a
1407request to the database. Then the only solution is to increase the number of
1408concurrent connections, so that the server can handle a large average number
1409of slow connections with threads left to handle faster connections.
1410
1411But as we have seen, increasing the number of connections on the servers can
1412be detrimental to performance (eg: Apache processes fighting for the accept()
1413lock). To improve this situation, the "minconn" parameter has been introduced.
1414When it is set, the maximum connection concurrency on the server will be bound
1415by this value, and the limit will increase with the number of clients waiting
1416in queue, till the clients connected to haproxy reach the proxy's maxconn, in
1417which case the connections per server will reach the server's maxconn. It means
1418that during low-to-medium loads, the minconn will be applied, and during surges
1419the maxconn will be applied. It ensures both optimal response times under
1420normal loads, and availability under very high loads.
1421
1422Example :
1423---------
1424
1425 listen appfarm 192.168.1.1:80
1426 mode http
1427 maxconn 10000
1428 option httpclose
1429 option abortonclose
1430 option forwardfor
1431 balance roundrobin
1432 # The servers will get 4 concurrent connections under low
1433 # loads, and 12 when there will be 10000 clients.
1434 server railsA 192.168.1.11:80 minconn 4 maxconn 12 check
1435 server railsB 192.168.1.12:80 minconn 4 maxconn 12 check
1436 server railsC 192.168.1.13:80 minconn 4 maxconn 12 check
1437 contimeout 60000
1438
1439