Merge branch 'haproxy-1.2.12'

This commit is contained in:
willy tarreau 2006-04-15 22:18:48 +02:00
commit a4197319b4
8 changed files with 572 additions and 141 deletions

View File

@ -1,6 +1,14 @@
ChangeLog :
===========
2006/04/15 : 1.2.12
Very few changes preparing for more important changes to support per-server
session limitations and queueing :
- ignore leading empty lines in HTTP requests as suggested by RFC2616.
- added the 'weight' parameter to the servers, limited to 1..256. It applies
to roundrobin and source hash.
- the optional '-s' option could clobber '-st' and '-sf' if compiled in.
2006/03/30 : 1.2.11.1
- under some conditions, it might have been possible that when the
last dead server became available, it would not have been used

View File

@ -2,7 +2,7 @@
# You should use it this way :
# make TARGET=os CPU=cpu
VERSION := 1.2.11.1
VERSION := 1.2.12
# Select target OS. TARGET must match a system for which COPTS and LIBS are
# correctly defined below.

5
TODO
View File

@ -77,7 +77,7 @@ ok>
- les options des serveurs ?
- les filtres et regex ?
5) implémenter "balance source" pour faire un hash sur la source.
* implémenter "balance source" pour faire un hash sur la source.
permettre de spécifier un masque sur lequel s'applique le hachage,
ainsi qu'une option pour hacher en fonction de l'adresse dans le
champ "x-forwarded-for". Problème pour le support des pannes: ce
@ -138,7 +138,7 @@ Todo for 1.2
* listen [ip6::...ip6]/port[-port]
- server xxx ipv4 | ipv4: | ipv4:port[-port] | ipv6/ | ipv6/port[-port]
* appcookie
- weighted round robin
* weighted round robin
- option to shutdown(listen_sock) when max connections reached
* epoll
- replace the event scheduler with an O(log(N)) one
@ -149,4 +149,5 @@ Todo for 1.2
activity on the buffer's pointers from touching the buffer page itself.
- make buffer size configurable in global options
* monitor number of simultaneous sessions in logs (per srv/inst/global)
* ignore leading empty lines in HTTP requests

View File

@ -2,9 +2,9 @@
H A - P r o x y
Reference Manual
-------------------
version 1.2.9
version 1.2.12
willy tarreau
2006/03/01
2006/04/15
============
| Abstract |
@ -42,11 +42,14 @@ There are only a few command line options :
exits with code 1 if a syntax error was found.
-p <pidfile> asks the process to write down each of its children's
pids to this file in daemon mode.
-sf specifies a list of pids to send a FINISH signal to after startup.
-st specifies a list of pids to send a TERMINATE signal to after startup.
-s shows statistics (only if compiled in)
-l shows even more statistics (implies '-s')
-de disables use of epoll()
-dp disables use of poll()
-db disables background mode (stays in foreground, useful for debugging)
-m <megs> enforces a memory usage limit to a maximum of <megs> megabytes.
The maximal number of connections per proxy is used as the default parameter for
each instance for which the 'maxconn' paramter is not set in the 'listen' section.
@ -59,9 +62,24 @@ section. When the proxy runs in this mode, it dumps every connections,
disconnections, timestamps, and HTTP headers to stdout. This should NEVER
be used in an init script since it will prevent the system from starting up.
For debugging, the '-db' option is very useful as it temporarily disables
daemon mode and multi-process mode. The service can then be stopped by simply
pressing Ctrl-C, without having to edit the config nor run full debug.
Statistics are only available if compiled in with the 'STATTIME' option. It's
only used during code optimization phases.
The '-st' and '-sf' options are used to inform previously running processes
that a configuration is being reloaded. They will receive the SIGTTOU signal to
ask them to temporarily stop listening to the ports so that the new process
can grab them. If anything wrong happens, the new process will send them a
SIGTTIN to tell them to re-listen to the ports and continue their normal
work. Otherwise, it will either ask them to finish (-sf) their work then softly
exit, or immediately terminate (-st), breaking existing sessions. A typical use
of this allows a configuration reload without service interruption :
# haproxy -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
======================
| Configuration file |
======================
@ -219,7 +237,7 @@ Example :
1.4) Startup modes
------------------
The service can start in several different :
The service can start in several different modes :
- foreground / background
- quiet / normal / debug
@ -230,6 +248,9 @@ returns immediately after forking. That's accomplished by the 'daemon' option
in the 'global' section, which is the equivalent of the '-D' command line
argument.
The '-db' command line argument overrides the 'daemon' and 'nbproc' global
options to make the process run in normal, foreground mode.
Moreover, certain alert messages are still sent to the standard output even
in 'daemon' mode. To make them disappear, simply add the 'quiet' option in the
'global' section. This option has no command-line equivalent.
@ -282,6 +303,9 @@ Example :
# to stop only those processes among others :
# kill $(</var/run/haproxy-private.pid)
# to reload a new configuration with minimal service impact and without
# breaking existing sessions :
# haproxy -f haproxy.cfg -p $(</var/run/haproxy-private.pid) -st $(</var/run/haproxy-private.pid)
1.7) Polling mechanisms
-----------------------
@ -479,7 +503,7 @@ amount of simultaneous ones. When the limit is reached, it simply stops
listening, but the system may still be accepting them because of the back log
queue. These connections will be processed later when other ones have freed
some slots. This provides a serialization effect which helps very fragile
servers resist to high loads. Se further for system limitations.
servers resist to high loads. See further for system limitations.
Example :
---------
@ -528,6 +552,8 @@ Please note that the 'grace' parameter is ignored for SIGTTOU, as well as for
SIGUSR1 when the process was in the pause mode. Please also note that it would
be useful to save the pidfile before starting a new instance.
This mechanism fully exploited since 1.2.11 with the '-st' and '-sf' options
(see above).
2.5) Connections expiration time
--------------------------------
@ -576,6 +602,9 @@ Example :
# we can retry 3 times max after a failure
retries 3
Please note that the reconnection attempt may lead to getting the connection
sent to a new server if the original one died between connection attempts.
2.7) Address of the dispatch server (deprecated)
------------------------------------------------
@ -766,9 +795,10 @@ The proxy can perform the load-balancing itself, both in TCP and in HTTP modes.
This is the most interesting mode which obsoletes the old 'dispatch' mode
described above. It has advantages such as server health monitoring, multiple
port binding and port mapping. To use this mode, the 'balance' keyword is used,
followed by the selected algorithm. As of version 1.1.23, only 'roundrobin' is
available, which is also the default value if unspecified. In this mode, there
will be no dispatch address, but the proxy needs at least one server.
followed by the selected algorithm. Up to version 1.2.11, only 'roundrobin' was
available, which is also the default value if unspecified. Starting with
version 1.2.12, a new 'source' keyword appeared. In this mode, there will be no
dispatch address, but the proxy needs at least one server.
Example : same as the last one, with internal load balancer
---------
@ -829,6 +859,42 @@ Examples :
server srv1 192.168.1.1:+1000
server srv2 192.168.1.2:+1000
As previously stated, version 1.2.12 brought the 'source' keyword. When this
keyword is used, the client's IP address is hashed and evenly distributed among
the available servers so that a same source IP will always go to the same
server as long as there are no change in the number of available servers. This
can be used for instance to bind HTTP and HTTPS to the same server. It can also
be used to improve stickyness when one part of the client population does not
accept cookies. In this case, only those ones will be perturbated should a
server fail.
NOTE: It is important to consider the fact that many clients surf the net
through proxy farms which assign different IP addresses for each
request. Others use dialup connections with a different IP at each
connection. Thus, the 'source' parameter should be used with extreme
care.
Examples :
----------
# make a same IP go to the same server whatever the service
listen http_proxy
bind :80,:443
mode http
balance source
server web1 192.168.1.1
server web2 192.168.1.2
# try to improve client-server binding by using both source IP and cookie :
listen http_proxy :80
mode http
cookie SERVERID
balance source
server web1 192.168.1.1 cookie server01
server web2 192.168.1.2 cookie server02
3.1) Server monitoring
----------------------
@ -1029,6 +1095,54 @@ option :
redispatch # send back to dispatch in case of connection failure
3.3) Assigning different weights to servers
-------------------------------------------
Sometimes you will need to bring new servers to increase your server farm's
capacity, but the new server will be either smaller (emergency use of anything
that fits) or bigger (when investing in new hardware). For this reason, it
might be wise to be able to send more clients to biggest servers. Till version
1.2.11, it was necessary to replicate the same server multiple times in the
configuration. Starting with 1.2.12, the 'weight' option is available. HAProxy
then computes the most homogenous possible map of servers based on their
weights so that the load gets distributed as smoothly as possible among
them. The weight, between 1 and 256, should reflect one server's capacity
relative to others. This way, if a server fails, the remaining capacities are
still respected.
Example :
---------
# fair distribution among two opterons and one old pentium3
listen web_appl 0.0.0.0:80
mode http
cookie SERVERID insert nocache indirect
balance roundrobin
server pentium3-800 192.168.1.1:80 cookie server01 weight 8 check
server opteron-2.0G 192.168.1.2:80 cookie server02 weight 20 check
server opteron-2.4G 192.168.1.3:80 cookie server03 weight 24 check
server web-backup1 192.168.2.1:80 cookie server04 check backup
server web-excuse 192.168.3.1:80 check backup
Notes :
-------
- if unspecified, the default weight is 1
- the weight does not impact health checks, so it is cleaner to use weights
than replicating the same server several times
- weights also work on backup servers if the 'allbackups' option is used
- the weights also apply to the source address load balancing
('balance source').
- whatever the weights, the first server will always be assigned first. This
is helpful for troubleshooting.
- for the purists, the map calculation algorithm gives precedence to first
server, so the map is the most uniform when servers are declared in
ascending order relative to their weights.
4) Additionnal features
=======================

View File

@ -2,9 +2,9 @@
H A - P r o x y
Manuel de référence
-------------------
version 1.2.9
version 1.2.12
willy tarreau
2006/03/01
2006/04/15
================
| Introduction |
@ -46,10 +46,14 @@ Les options de lancement sont peu nombreuses :
détectée.
-p <fichier> indique au processus père qu'il doit écrire les PIDs de ses
fils dans ce fichier en mode démon.
-sf specifie une liste de PIDs auxquels envoyer un signal FINISH
-st specifie une liste de PIDs auxquels envoyer un signal TERMINATE
-s affiche les statistiques (si option compilée)
-l ajoute des informations aux statistiques
-de désactive l'utilisation de epoll()
-dp désactive l'utilisation de poll()
-db désactive la mise en arrière-plan (utile pour débugger)
-m <megs> applique une limitation de <megs> Mo d'utilisation mémoire
Le nombre maximal de connexion simultanées par proxy est le paramètre par
défaut pour les proxies pour lesquels ce paramètre n'est pas précisé dans le
@ -64,10 +68,27 @@ Le mode debug correspond
mode, toutes les connexions, déconnexions, et tous les échanges d'en-têtes HTTP
sont affichés.
Pour debugger, l'option '-db' est très pratique car elle désactive
temporairement le mode daemon et le mode multi-processus. Le service peut alors
être arrêté par un simple appui sur Ctrl-C, sans avoir à modifier la
configuration ni à activer le mode debug complet.
Les statistiques ne sont disponibles que si le programme a été compilé avec
l'option "STATTIME". Il s'agit principalement de données brutes n'ayant
d'utilité que lors de benchmarks par exemple.
Les paramètres '-st' et '-sf' sont utilisés pour informer des processus
existants que la configuration va être rechargée. Ils recevront le signal
SIGTTOU, leur demandant de libérer les ports en écoute afin que le nouveau
processus puisse les prendre. Si quoi que ce soit se passe mal, le nouveau
processus leur enverra un signal SIGTTIN pour leur indiquer qu'ils peuvent
se remettre en écoute et continuer leur travail. En revanche, si la
configuration se charge correctement, alors ils recevront un signal de demande
de fin de travail en douceur (-sf), ou de terminaison immédiate (-st) qui
coupera les sessions en cours. Un usage typique tel que celui-ci permet de
recharger une configuration sans interruption de service :
# haproxy -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
============================
| Fichier de configuration |
@ -247,6 +268,9 @@ initialisation. Il faut le mettre en arri
au processus appelant. C'est ce que fait l'option 'daemon' de la section
'global', et qui est l'équivalent du paramètre '-D' de la ligne de commande.
Le paramètre de ligne de commande '-db' inhibe les options globales 'daemon'
et 'nbproc' pour faire fonctionner le processus en mode normal, avant-plan.
Par ailleurs, certains messages d'alerte sont toujours envoyés sur la sortie
standard, même en mode 'daemon'. Pour ne plus les voir ailleurs que dans les
logs, il suffit de passer en mode silencieux par l'ajout de l'option 'quiet'.
@ -301,6 +325,9 @@ Exemple :
# pour stopper seulement ces processus parmi d'autres :
# kill $(</var/run/haproxy-private.pid)
# pour recharger une configuration avec un impact minimal sur le service,
# et sans casser les sessions existantes :
# haproxy -f haproxy.cfg -p $(</var/run/haproxy-private.pid) -st $(</var/run/haproxy-private.pid)
1.7) Mécanismes de traitements des événements
---------------------------------------------
@ -553,6 +580,8 @@ noter que le param
signal SIGUSR1 une fois le processus en pause. Aussi, il peut s'avérer très
utile de sauver le fichier de pid avant de démarrer une nouvelle instance.
Ce mécanisme est pleinement exploité à partir de la version 1.2.11 avec les
options '-st' et '-sf' (voir plus haut).
2.5) Temps d'expiration des connexions
--------------------------------------
@ -603,6 +632,9 @@ Exemple :
# on essaie encore trois fois maxi
retries 3
Il est à noter que la tentative de reconnexion peut amener à utiliser un autre
serveur si le premier a disparu entre deux tentatives de connexion.
2.7) Adresse du serveur
-----------------------
@ -768,9 +800,10 @@ Attention : la syntaxe a chang
Le relais peut effectuer lui-même la répartition de charge entre les différents
serveurs définis pour un service donné, en mode TCP comme en mode HTTP. Pour
cela, on précise le mot clé 'balance' dans la définition du service,
éventuellement suivi du nom d'un algorithme de répartition. En version 1.1.9,
seul 'roundrobin' est géré, et c'est aussi la valeur implicite par défaut. Il
est évident qu'en cas d'utilisation du répartiteur interne, il ne faudra pas
éventuellement suivi du nom d'un algorithme de répartition. Jusqu'à la version
1.2.11, seul 'roundrobin' était géré, et c'est aussi la valeur implicite par
défaut. Avec la version 1.2.12, le nouveau mot clé 'source' est apparu. Il est
évident qu'en cas d'utilisation du répartiteur interne, il ne faudra pas
spécifier d'adresse de dispatch, et qu'il faudra au moins un serveur.
Exemple : même que précédemment en répartition interne
@ -833,6 +866,44 @@ Exemples :
server srv1 192.168.1.1:+1000
server srv2 192.168.1.2:+1000
Comme indiqué précédemment, la version 1.2.12 apporta le nouveau mot clé
'source'. Lorsque celui-ci est utilisé, l'adresse IP du client est hachée et
distribuée de manière homogène parmi les serveurs disponibles, de sorte qu'une
même adresse IP aille toujours sur le même serveur tant qu'il n'y a aucun
changement dans le nombre de serveurs disponibles. Ceci peut être utilisé par
exemple pour attacher le HTTP et le HTTPS sur un même serveur pour un même
client. Cela peut également être utilisé pour améliorer la persistance
lorsqu'une partie de la population des clients n'accepte pas les cookies. Dans
ce cas, seuls ces derniers seront perturbés par la perte d'un serveur.
NOTE: il est important de prendre en compte le fait que beaucoup d'internautes
naviguent à travers des fermes de proxies qui assignent des adresses IP
différentes à chaque requête. D'autres internautes utilisent des liens à
la demande et obtiennent une adresse IP différente à chaque connexion. De
ce fait, le paramètre 'source' doit être utilisé avec une extrème
précaution.
Exemples :
----------
# assurer qu'une même adresse IP ira sur le même serveur pour tout service
listen http_proxy
bind :80,:443
mode http
balance source
server web1 192.168.1.1
server web2 192.168.1.2
# améliorer la persistance par l'utilisation de la source en plus du cookie :
listen http_proxy :80
mode http
cookie SERVERID
balance source
server web1 192.168.1.1 cookie server01
server web2 192.168.1.2 cookie server02
3.1) Surveillance des serveurs
------------------------------
@ -844,6 +915,7 @@ Il est possible de sp
tests du serveur par le paramètre "inter", le nombre d'échecs acceptés par le
paramètre "fall", et le nombre de succès avant reprise par le paramètre "rise".
Les paramètres non précisés prennent les valeurs suivantes par défaut :
- inter : 2000
- rise : 2
- fall : 3
@ -866,10 +938,12 @@ consid
deux tests (paramètre "inter"). Pour activer ce mode, spécifier l'option
"httpchk", éventuellement suivie d'une méthode et d'une URI. L'option "httpchk"
accepte donc 4 formes :
- option httpchk -> OPTIONS / HTTP/1.0
- option httpchk URI -> OPTIONS <URI> HTTP/1.0
- option httpchk METH URI -> <METH> <URI> HTTP/1.0
- option httpchk METH URI VER -> <METH> <URI> <VER>
Voir les exemples ci-après.
Depuis la version 1.1.17, il est possible de définir des serveurs de secours,
@ -1038,6 +1112,59 @@ tente de s'y connecter, il faut pr
redispatch # renvoyer vers dispatch si serveur HS.
3.3) Assignation de poids différents à des serveurs
---------------------------------------------------
Parfois il arrive d'ajouter de nouveaux serveurs pour accroître la capacité
d'une ferme de serveur, mais le nouveau serveur est soit beaucoup plus petit
que les autres (dans le cas d'un ajout d'urgence de matériel de récupération),
soit plus puissant (lors d'un investissement dans du matériel neuf). Pour cette
raison, il semble parfois judicieux de pouvoir envoyer plus de clients vers les
plus gros serveurs. Jusqu'à la version 1.2.11, il était nécessaire de répliquer
plusieurs fois les définitions des serveurs pour augmenter leur poids. Depuis
la version 1.2.12, l'option 'weight' est disponible. HAProxy construit alors
une vue des serveurs disponibles la plus homogène possible en se basant sur
leur poids de sorte que la charge se distribue de la manière la plus lisse
possible. Le poids compris entre 1 et 256 doit refléter la capacité d'un
serveur par rapport aux autres. De cette manière, si un serveur disparait, les
capacités restantes sont toujours respectées.
Exemple :
---------
# distribution équitable sur 2 opteron and un ancien pentium3
listen web_appl 0.0.0.0:80
mode http
cookie SERVERID insert nocache indirect
balance roundrobin
server pentium3-800 192.168.1.1:80 cookie server01 weight 8 check
server opteron-2.0G 192.168.1.2:80 cookie server02 weight 20 check
server opteron-2.4G 192.168.1.3:80 cookie server03 weight 24 check
server web-backup1 192.168.2.1:80 cookie server04 check backup
server web-excuse 192.168.3.1:80 check backup
Notes :
-------
- lorsque le poids n'est pas spécifié, la valeur par défaut est à 1
- le poids n'impacte pas les tests de fonctionnement (health checks), donc il
est plus propre d'utiliser les poids que de répliquer le même serveur
plusieurs fois.
- les poids s'appliquent également aux serveurs de backup si l'option
'allbackups' est positionnée.
- le poids s'applique aussi à la répartition selon la source
('balance source').
- quels que soient les poids, le premier serveur sera toujours assigné en
premier. Cette règle facilite les diagnostics.
- pour les puristes, l'algorithme de calculation de la vue des serveurs donne
une priorité aux premiers serveurs, donc la vue est la plus uniforme si les
serveurs sont déclarés dans l'ordre croissant de leurs poids.
4) Fonctionnalités additionnelles
=================================

104
examples/haproxy-small.spec Normal file
View File

@ -0,0 +1,104 @@
Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments
Name: haproxy
Version: 1.2.12
Release: 1
License: GPL
Group: System Environment/Daemons
URL: http://w.ods.org/tools/%{name}/
Source0: http://w.ods.org/tools/%{name}/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-root
BuildRequires: pcre-devel
Requires: /sbin/chkconfig, /sbin/service
%description
HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited for high
availability environments. Indeed, it can:
- route HTTP requests depending on statically assigned cookies
- spread the load among several servers while assuring server persistence
through the use of HTTP cookies
- switch to backup servers in the event a main one fails
- accept connections to special ports dedicated to service monitoring
- stop accepting connections without breaking existing ones
- add/modify/delete HTTP headers both ways
- block requests matching a particular pattern
It needs very little resource. Its event-driven architecture allows it to easily
handle thousands of simultaneous connections on hundreds of instances without
risking the system's stability.
%prep
%setup -q
%build
%{__make} REGEX="pcre" "COPTS.pcre=-DUSE_PCRE $(pcre-config --cflags)" DEBUG="" TARGET=linux24e SMALL_OPTS="-DBUFSIZE=8030 -DMAXREWRITE=1030 -DSYSTEM_MAXCONN=1024" DEBUG="" LIBS.pcre="-L\$(PCREDIR)/lib -Wl,-Bstatic -lpcreposix -lpcre -Wl,-Bdynamic"
%install
[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
%{__install} -d %{buildroot}%{_sbindir}
%{__install} -d %{buildroot}%{_sysconfdir}/rc.d/init.d
%{__install} -d %{buildroot}%{_sysconfdir}/%{name}
%{__install} -s %{name} %{buildroot}%{_sbindir}/
%{__install} -c -m 644 examples/%{name}.cfg %{buildroot}%{_sysconfdir}/%{name}/
%{__install} -c -m 755 examples/%{name}.init %{buildroot}%{_sysconfdir}/rc.d/init.d/%{name}
%clean
[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
%post
/sbin/chkconfig --add %{name}
%preun
if [ $1 = 0 ]; then
/sbin/service %{name} stop >/dev/null 2>&1 || :
/sbin/chkconfig --del %{name}
fi
%postun
if [ "$1" -ge "1" ]; then
/sbin/service %{name} condrestart >/dev/null 2>&1 || :
fi
%files
%defattr(-,root,root)
%doc CHANGELOG TODO examples doc/haproxy-en.txt doc/haproxy-fr.txt doc/architecture.txt
%attr(0755,root,root) %{_sbindir}/%{name}
%dir %{_sysconfdir}/%{name}
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/%{name}.cfg
%attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
%changelog
* Wed Apr 15 2006 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.12
* Wed Mar 30 2006 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.11.1
* Wed Mar 19 2006 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.10
* Wed Mar 15 2006 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.9
* Sat Jan 22 2005 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.3 (1.1.30)
* Sun Nov 14 2004 Willy Tarreau <w@w.ods.org>
- updated to 1.1.29
- fixed path to config and init files
- statically linked PCRE to increase portability to non-pcre systems
* Sun Jun 6 2004 Willy Tarreau <willy@w.ods.org>
- updated to 1.1.28
- added config check support to the init script
* Tue Oct 28 2003 Simon Matter <simon.matter@invoca.ch>
- updated to 1.1.27
- added pid support to the init script
* Wed Oct 22 2003 Simon Matter <simon.matter@invoca.ch>
- updated to 1.1.26
* Thu Oct 16 2003 Simon Matter <simon.matter@invoca.ch>
- initial build

View File

@ -1,6 +1,6 @@
Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments
Name: haproxy
Version: 1.2.11.1
Version: 1.2.12
Release: 1
License: GPL
Group: System Environment/Daemons
@ -71,6 +71,9 @@ fi
%attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
%changelog
* Wed Apr 15 2006 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.12
* Wed Mar 30 2006 Willy Tarreau <willy@w.ods.org>
- updated to 1.2.11.1

322
haproxy.c
View File

@ -88,11 +88,11 @@
#include "include/appsession.h"
#ifndef HAPROXY_VERSION
#define HAPROXY_VERSION "1.2.11.1"
#define HAPROXY_VERSION "1.2.12"
#endif
#ifndef HAPROXY_DATE
#define HAPROXY_DATE "2006/03/30"
#define HAPROXY_DATE "2006/04/15"
#endif
/* this is for libc5 for example */
@ -511,6 +511,8 @@ struct server {
int inter; /* time in milliseconds */
int result; /* 0 = connect OK, -1 = connect KO */
int curfd; /* file desc used for current test, or -1 if not in test */
unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
unsigned int wscore; /* weight score, used during srv map computation */
struct proxy *proxy; /* the proxy this server belongs to */
};
@ -577,8 +579,12 @@ struct proxy {
struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
int state; /* proxy state */
struct sockaddr_in dispatch_addr; /* the default address to connect to */
struct server *srv, *cursrv; /* known servers, current server */
int srv_act, srv_bck; /* # of servers */
struct server *srv; /* known servers */
int srv_act, srv_bck; /* # of running servers */
int tot_wact, tot_wbck; /* total weights of active and backup servers */
struct server **srv_map; /* the server map used to apply weights */
int srv_map_sz; /* the size of the effective server map */
int srv_rr_idx; /* next server to be elected in round robin mode */
char *cookie_name; /* name of the cookie to look for */
int cookie_len; /* strlen(cookie_name), computed only once */
char *appsession_name; /* name of the cookie to look for */
@ -1807,77 +1813,101 @@ static inline void session_free(struct session *s) {
/*
* This function recounts the number of usable active and backup servers for
* proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
* This function also recomputes the total active and backup weights.
*/
static inline void recount_servers(struct proxy *px) {
static void recount_servers(struct proxy *px) {
struct server *srv;
px->srv_act = 0; px->srv_bck = 0;
px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
for (srv = px->srv; srv != NULL; srv = srv->next) {
if (srv->state & SRV_RUNNING) {
if (srv->state & SRV_BACKUP)
if (srv->state & SRV_BACKUP) {
px->srv_bck++;
else
px->tot_wbck += srv->eweight + 1;
} else {
px->srv_act++;
px->tot_wact += srv->eweight + 1;
}
}
}
}
/* This function recomputes the server map for proxy px. It
* relies on px->tot_wact and px->tot_wbck, so it must be
* called after recount_servers(). It also expects px->srv_map
* to be initialized to the largest value needed.
*/
static void recalc_server_map(struct proxy *px) {
int o, tot, flag;
struct server *cur, *best;
if (px->srv_act) {
flag = SRV_RUNNING;
tot = px->tot_wact;
} else if (px->srv_bck) {
flag = SRV_RUNNING | SRV_BACKUP;
if (px->options & PR_O_USE_ALL_BK)
tot = px->tot_wbck;
else
tot = 1; /* the first server is enough */
} else {
px->srv_map_sz = 0;
return;
}
/* this algorithm gives priority to the first server, which means that
* it will respect the declaration order for equivalent weights, and
* that whatever the weights, the first server called will always be
* the first declard. This is an important asumption for the backup
* case, where we want the first server only.
*/
for (cur = px->srv; cur; cur = cur->next)
cur->wscore = 0;
for (o = 0; o < tot; o++) {
int max = 0;
best = NULL;
for (cur = px->srv; cur; cur = cur->next) {
if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
int v;
/* If we are forced to return only one server, we don't want to
* go further, because we would return the wrong one due to
* divide overflow.
*/
if (tot == 1) {
best = cur;
break;
}
cur->wscore += cur->eweight + 1;
v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
if (best == NULL || v > max) {
max = v;
best = cur;
}
}
}
px->srv_map[o] = best;
best->wscore -= tot;
}
px->srv_map_sz = tot;
}
/*
* This function tries to find a running server for the proxy <px> following
* the round-robin method. Depending on the number of active/backup servers,
* it will either look for active servers, or for backup servers.
* If any server is found, it will be returned and px->cursrv will be updated
* If any server is found, it will be returned and px->srv_rr_idx will be updated
* to point to the next server. If no valid server is found, NULL is returned.
*/
static inline struct server *get_server_rr(struct proxy *px) {
struct server *srv;
struct server *end;
if (px->srv_map_sz == 0)
return NULL;
if (px->srv_act) {
srv = px->cursrv;
if (srv == NULL)
srv = px->srv;
end = srv;
do {
if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
px->cursrv = srv->next;
return srv;
}
srv = srv->next;
if (srv == NULL)
srv = px->srv;
} while (srv != end);
/* note that theorically we should not get there */
}
if (px->srv_bck) {
/* By default, we look for the first backup server if all others are
* DOWN. But in some cases, it may be desirable to load-balance across
* all backup servers.
*/
if (px->options & PR_O_USE_ALL_BK)
srv = px->cursrv;
else
srv = px->srv;
if (srv == NULL)
srv = px->srv;
end = srv;
do {
if (srv->state & SRV_RUNNING) {
px->cursrv = srv->next;
return srv;
}
srv = srv->next;
if (srv == NULL)
srv = px->srv;
} while (srv != end);
/* note that theorically we should not get there */
}
/* if we get there, it means there are no available servers at all */
return NULL;
if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
px->srv_rr_idx = 0;
return px->srv_map[px->srv_rr_idx++];
}
@ -1889,58 +1919,20 @@ static inline struct server *get_server_rr(struct proxy *px) {
* NULL is returned.
*/
static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
struct server *srv;
unsigned int h, l;
if (px->srv_act) {
unsigned int h, l;
if (px->srv_map_sz == 0)
return NULL;
l = h = 0;
if (px->srv_act > 1) {
while ((l + sizeof (int)) <= len) {
h ^= ntohl(*(unsigned int *)(&addr[l]));
l += sizeof (int);
}
h %= px->srv_act;
}
for (srv = px->srv; srv; srv = srv->next) {
if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
if (!h)
return srv;
h--;
}
l = h = 0;
if (px->srv_act > 1) {
while ((l + sizeof (int)) <= len) {
h ^= ntohl(*(unsigned int *)(&addr[l]));
l += sizeof (int);
}
/* note that theorically we should not get there */
h %= px->srv_map_sz;
}
if (px->srv_bck) {
unsigned int h, l;
/* By default, we look for the first backup server if all others are
* DOWN. But in some cases, it may be desirable to load-balance across
* all backup servers.
*/
l = h = 0;
if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
while ((l + sizeof (int)) <= len) {
h ^= ntohl(*(unsigned int *)(&addr[l]));
l += sizeof (int);
}
h %= px->srv_bck;
}
for (srv = px->srv; srv; srv = srv->next) {
if (srv->state & SRV_RUNNING) {
if (!h)
return srv;
h--;
}
}
/* note that theorically we should not get there */
}
/* if we get there, it means there are no available servers at all */
return NULL;
return px->srv_map[h];
}
@ -3311,6 +3303,32 @@ int process_cli(struct session *t) {
if (ptr == req->h) { /* empty line, end of headers */
int line, len;
/*
* first, let's check that it's not a leading empty line, in
* which case we'll ignore and remove it (according to RFC2616).
*/
if (req->h == req->data) {
/* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
if (ptr > req->r - 2) {
/* this is a partial header, let's wait for more to come */
req->lr = ptr;
break;
}
/* now we know that *ptr is either \r or \n,
* and that there are at least 1 char after it.
*/
if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
else
req->lr = ptr + 2; /* \r\n or \n\r */
/* ignore empty leading lines */
buffer_replace2(req, req->h, req->lr, NULL, 0);
req->h = req->lr;
continue;
}
/* we can only get here after an end of headers */
/* we'll have something else to do here : add new headers ... */
@ -5310,6 +5328,7 @@ int process_chk(struct task *t) {
s->state &= ~SRV_RUNNING;
if (s->health == s->rise) {
recount_servers(s->proxy);
recalc_server_map(s->proxy);
Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
s->state & SRV_BACKUP ? "Backup " : "",
s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
@ -5345,6 +5364,7 @@ int process_chk(struct task *t) {
if (s->health == s->rise) {
recount_servers(s->proxy);
recalc_server_map(s->proxy);
Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
s->state & SRV_BACKUP ? "Backup " : "",
s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
@ -5375,6 +5395,7 @@ int process_chk(struct task *t) {
if (s->health == s->rise) {
recount_servers(s->proxy);
recalc_server_map(s->proxy);
Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
s->state & SRV_BACKUP ? "Backup " : "",
s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
@ -6980,13 +7001,9 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
return -1;
}
if (curproxy->srv == NULL)
curproxy->srv = newsrv;
else
curproxy->cursrv->next = newsrv;
curproxy->cursrv = newsrv;
newsrv->next = NULL;
/* the servers are linked backwards first */
newsrv->next = curproxy->srv;
curproxy->srv = newsrv;
newsrv->proxy = curproxy;
do_check = 0;
@ -7049,6 +7066,17 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
newsrv->state |= SRV_BACKUP;
cur_arg ++;
}
else if (!strcmp(args[cur_arg], "weight")) {
int w;
w = atol(args[cur_arg + 1]);
if (w < 1 || w > 256) {
Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
file, linenum, newsrv->id, w);
return -1;
}
newsrv->uweight = w - 1;
cur_arg += 2;
}
else if (!strcmp(args[cur_arg], "check")) {
global.maxsock++;
do_check = 1;
@ -7065,7 +7093,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
cur_arg += 2;
}
else {
Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n",
Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
file, linenum, newsrv->id);
return -1;
}
@ -7789,7 +7817,6 @@ int readcfgfile(char *file) {
}
while (curproxy != NULL) {
curproxy->cursrv = NULL;
if (curproxy->state == PR_STSTOPPED) {
curproxy = curproxy->next;
continue;
@ -7846,12 +7873,59 @@ int readcfgfile(char *file) {
file, curproxy->id);
cfgerr++;
}
else {
while (newsrv != NULL) {
/* nothing to check for now */
newsrv = newsrv->next;
}
}
/* first, we will invert the servers list order */
newsrv = NULL;
while (curproxy->srv) {
struct server *next;
next = curproxy->srv->next;
curproxy->srv->next = newsrv;
newsrv = curproxy->srv;
if (!next)
break;
curproxy->srv = next;
}
/* now, newsrv == curproxy->srv */
if (newsrv) {
struct server *srv;
int pgcd;
int act, bck;
/* We will factor the weights to reduce the table,
* using Euclide's largest common divisor algorithm
*/
pgcd = newsrv->uweight + 1;
for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
int t, w;
w = srv->uweight + 1;
while (w) {
t = pgcd % w;
pgcd = w;
w = t;
}
}
act = bck = 0;
for (srv = newsrv; srv; srv = srv->next) {
srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
if (srv->state & SRV_BACKUP)
bck += srv->eweight + 1;
else
act += srv->eweight + 1;
}
/* this is the largest map we will ever need for this servers list */
if (act < bck)
act = bck;
curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
/* recounts servers and their weights */
recount_servers(curproxy);
recalc_server_map(curproxy);
}
if (curproxy->options & PR_O_LOGASAP)
@ -8048,12 +8122,6 @@ void init(int argc, char **argv) {
arg_mode |= MODE_DAEMON | MODE_QUIET;
else if (*flag == 'q')
arg_mode |= MODE_QUIET;
#if STATTIME > 0
else if (*flag == 's')
arg_mode |= MODE_STATS;
else if (*flag == 'l')
arg_mode |= MODE_LOG;
#endif
else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
/* list of pids to finish ('f') or terminate ('t') */
@ -8074,6 +8142,12 @@ void init(int argc, char **argv) {
}
}
}
#if STATTIME > 0
else if (*flag == 's')
arg_mode |= MODE_STATS;
else if (*flag == 'l')
arg_mode |= MODE_LOG;
#endif
else { /* >=2 args */
argv++; argc--;
if (argc == 0)