Some applications do not have a strict persistence requirement, yet
it is still desirable for performance considerations, due to local
caches on the servers. For some reasons, there are some applications
which cannot rely on cookies, and for which the last resort is to use
a parameter passed in the URL.
The new 'url_param' balance method is there to solve this issue. It
accepts a parameter name which is looked up from the URL and which
is then hashed to select a server. If the parameter is not found,
then the round robin algorithm is used in order to provide a normal
load balancing across the servers for the first requests. It would
have been possible to use a source IP hash instead, but since such
applications are generally buried behind multiple levels of
reverse-proxies, it would not provide a good balance.
The doc has been updated, and two regression testing configurations
have been added.
A new function "backend_parse_balance" has been created in backend.c,
which is dedicated to the parsing of the "balance" keyword. It will
provide easier methods for adding new algorithms.
In preparation for newer balance algorithms, group the
sparse PR_O_BALANCE_* values into layer4 and layer7-based
algorithms. This will ease addition of newer algorithms.
Currently, there is a hidden line length limit in the haproxy, set
to 256-1 chars. With large acls (for example many hdr(host) matches)
it may be not enough and which is even worse, error message may
be totally confusing as everything above this limit is treated
as a next line:
echo -ne "frontend aqq 1.2.3.4:80\nmode http\nacl e hdr(host) -i X X X X X X X www.xx.example.com stats\n"|
sed s/X/www.some-host-name.example.com/g > ha.cfg && haproxy -c -f ./ha.cfg
[WARNING] 300/163906 (11342) : parsing [./ha.cfg:4] : 'stats' ignored because frontend 'aqq' has no backend capability.
Recently I hit simmilar problem and it took me a while to find why
requests for "stats" are not handled properly.
This patch:
- makes the limit configurable (LINESIZE)
- increases default line length limit from 256 to 2048
- increases MAX_LINE_ARGS from 40 to 64
- fixes hidden assignment in fgets()
- moves arg/end/args/line inside the loop, making code auditing easier
- adds a check that shows error if the limit is reached
- changes "*line++ = 0;" to "*line++ = '\0';" (cosmetics)
With this patch, when LINESIZE is defined to 256, above example produces:
[ALERT] 300/164724 (27364) : parsing [/tmp/ha.cfg:3]: line too long, limit: 255.
[ALERT] 300/164724 (27364) : Error reading configuration file : /tmp/ha.cfg
Hello,
As it is possible to use the same name for two proxies, make sure that
use_backed & friends does not match wrong proxy when used with use_backend/
default_backend/setbe. For example, without this patch, when there is a
backend and frontend with the same name (first backend and then frontend
trying to use specific backend), the application will likely try to use
frontend instead of backend, complaining loudly about a loop.
Best regards,
Krzysztof Oledzki
Building ev_kqueue on OpenBSD causes some warnings to occur,
because OpenBSD also uses LIST_* macros in sys/queue.h, included
from sys/event.h. Simply undefine those macros since we don't
need them.
This patch adds the "maxqueue" parameter to the server. This allows new
sessions to be immediately rebalanced when the server's queue is filled.
It's useful when session stickiness is just a performance boost (even a
huge one) but not a requirement.
This should only be used if session affinity isn't a hard functional
requirement but provides performance boost by keeping server-local
caches hot and compact).
Absence of 'maxqueue' option means unlimited queue. When queue gets filled
up to 'maxqueue' client session is moved from server-local queue to a global
one.
This is in fact the same as ultoa() except that it's possible to
pass the string to be returned in case the value is NULL. This is
useful to report limits in printf calls.
Current ultoa() function is limited to one use per expression or
function call. Sometimes this is limitating. Change this in favor
of an array of 10 return values and shorter macros U2A0..U2A9
which respectively call the function with the 10 different buffers.
localtime() was called with pointers to tv_sec, which is time_t on
some platforms and long on others. A problem was encountered on
Sparc64 under OpenBSD where tv_sec is long (64 bits) and time_t is
32 bits. Since this architecture is big-endian, it exhibited the
bug because localtime() always worked with the high part of the
value which is always zero. This problem was identified and debugged
by Thierry Fournier.
The correct solution is to pass the date by value and not by pointer,
through an intermediate function. The use of localtime_r() instead of
localtime() also made it possible to get rid of the first call to
localtime() since it does not need to allocate memory anymore.
The strl2ic() and strl2uic() primitives used to convert string to
integers could return 10 times the value read if they stopped on
non-digit because of a mis-placed loop exit.
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
Currently haproxy accepts a config with duplicated proxies
(listen/fronted/backed/ruleset). This patch fix this, so the application
will complain when there is an error.
With this modification it is still possible to use the same name for two
proxies (for example frontend&backend) as long there is no conflict:
listen backend frontend ruleset
listen - - - -
backend - - OK -
frontend - OK - -
ruleset - - - -
Best regards,
Krzysztof Oledzki
- replace the code under O'Reilly license (Arnaud Cornet)
- add a small man page (Arnaud Cornet)
- stats: report haproxy's version by default (Krzysztof Oledzki)
- stats: count server retries and redispatches (Krzysztof Oledzki)
- core: added easy support for Doug Lea's malloc (dlmalloc)
- core: fade out memory usage when stopping proxies
- core: moved the sockaddr pointer to the fdtab structure
- core: add generic protocol support
- core: implement client-side support for PF_UNIX sockets
- stats: implement the CSV output
- stats: add a link to the CSV export HTML page
- stats: implement the statistics output on a unix socket
- config: introduce the "stats" keyword in global section
- build: centralize version and date into one file for each
- tests: added a new hash algorithm
It is important to know how your installation performs. Haproxy masks
connection errors, which is extremely good for a client but it is bad for
an administrator (except people believing that "ignorance is a bless").
Attached patch adds retries and redispatches counters, so now haproxy:
1. For server:
- counts retried connections (masked or not)
2. For backends:
- counts retried connections (masked or not) that happened to
a slave server
- counts redispatched connections
- does not count successfully redispatched connections as backend errors.
Errors are increased only when client does not get a valid response,
in other words: with failed redispatch or when this function is not
enabled.
3. For statistics:
- display Retr (retries) and Redis (redispatches) as a "Warning"
information.
Removed old unused MODE_LOG and MODE_STATS, and replaced the "stats"
keyword in the global section. The new "stats" keyword in the global
section is used to create a UNIX socket on which the statistics will
be accessed. The client must issue a "show stat\n" command in order
to get a CSV-formated output similar to the output on the HTTP socket
in CSV mode.
A unix socket can now access the statistics. It currently only
recognizes the "show stat\n" command at the beginning of the
input, then returns the statistics in CSV format.
It is now possible to get CSV ouput from the statistics by
simply appending ";csv" to the HTTP request sent to get the
stats. The fields keep the same ordering as in the HTML page,
and a field "pxname" has been prepended at the beginning of
the line.
A new file, proto_uxst.c, implements support of PF_UNIX sockets
of type SOCK_STREAM. It relies on generic stream_sock_read/write
and uses its own accept primitive which also tries to be generic.
Right now it only implements an echo service in sight of a general
support for start dumping via unix socket. The echo code is more
of a proof of concept than useful code.
A new generic protocol mechanism has been added. It provides
an easy method to implement new protocols with different
listeners (eg: unix sockets).
The listeners are automatically started at the right moment
and enabled after the possible fork().
This must come from a copy-paste typo: in the unlikely event that
fork() would fail, the parent process would only exit(1) if there
were old pids. That's non-sense.
In case the incoming socket is set for write and not for read (very
unlikely, except in HEALTH mode), the timeout may remain eternity due
to a copy-paste typo.
The stream_sock_* functions had to know about sessions just in
order to get the server's address for a connect() operation. This
is not desirable, particularly for non-IP protocols (eg: PF_UNIX).
Put a pointer to the peer's sockaddr_storage or sockaddr address
in the fdtab structure so that we never need to look further.
With this small change, the stream_sock.c file is now 100% protocol
independant.
For people who manage many haproxies, it is sometimes convenient
to be informed of their version. This patch adds this, with the
option to disable this report by specifying "stats hide-version".
Also, the feature may be permanently disabled by setting the
STATS_VERSION_STRING to "" (empty string), or the format can
simply be adjusted.
Initial patch only managed to spread the checks when the checks
failed. The randomization code needs to be added also in the path
where the server is going fine.
When one server in one backend has a very low check interval, it imposes
its value as the minimal interval, causing all other servers to start
their checks close to each other, thus partially voiding the benefits of
the spread checks.
The solution consists in ignoring intervals lower than a given value
(SRV_CHK_INTER_THRES = 1000 ms) when computing the minimal interval,
and then assigning them a start date relative to their own interval
and not the global one.
With this change, the checks distribution clearly looks better.
When one server appears at the same position in multiple backends, it
receives all the checks from all the backends exactly at the same time
because the health-checks are only spread within a backend but not
globally.
Attached patch implements per-server start delay in a different way.
Checks are now spread globally - not locally to one backend. It also makes
them start faster - IMHO there is no need to add a 'server->inter' when
calculating first execution. Calculation were moved from cfgparse.c to
checks.c. There is a new function start_checks() and now it is not called
when haproxy is started in MODE_CHECK.
With this patch it is also possible to set a global 'spread-checks'
parameter. It takes a percentage value (1..50, probably something near
5..10 is a good idea) so haproxy adds or removes that many percent to the
original interval after each check. My test shows that with 18 backends,
54 servers total and 10000ms/5% it takes about 45m to mix them completely.
I decided to use rand/srand pseudo-random number generator. I am aware it
is not recommend for a good randomness but a) we do not need a good random
generator here b) it is probably the most portable one.
The following patch will give the ability to tweak socket linger mode.
You can use this option with "option nolinger" inside fronted or backend
configuration declaration.
This will help in environments where lots of FIN_WAIT sockets are
encountered.
I noticed that haproxy, with "cookie (...) nocache" option, always adds
"Cache-control: private" at the end of a header list received from this
server:
Cache-Control: no-cache
(...)
Set-Cookie: SERVERID=s6; path=/
Cache-control: private
or:
Set-Cookie: ASPSESSIONIDCSRCTSSB=HCCBGGACGBHDHMMKIOILPHNG; path=/
Cache-control: private
Set-Cookie: SERVERID=s5; path=/
Cache-control: private
It may be just redundant (two "Cache-control: private"), but sometimes it
may be quite confused as we may end with two different, more and less
restricted directions (no-cache & private) and even quite conflicting
directions (eg. public & private):
So, I added and rearranged a code, so now haproxy adds a "Cache-control:
private" header only when there is no the same (private) or more
restrictive (no-cache) one. It was done in three steps:
1. Use check_response_for_cacheability to check if response is
not cacheable. I simply moved this call before http_header_add_tail2.
2. Use TX_CACHEABLE (not TX_CACHE_COOK - apache <= 1.3.26) to check if we
need to add a Cache-control header. If we add it, clear TX_CACHEABLE and
TX_CACHE_COOK.
3. Check cacheability not only with PR_O_CHK_CACHE but also with
PR_O_COOK_NOC, so:
- unlikely(t->be->options & PR_O_CHK_CACHE))
+ (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
I removed this unlikely since I believe that now it is not so unlikely.
The patch is definitely not perfect, proxy should probably also remove
"Cache-control: public". Unfortunately, I do not know the code good enough
to do in myself, yet. ;)
Anyway, I think that even now, it should be very useful.
On Sat, 22 Sep 2007, Willy Tarreau wrote:
> On Sun, Sep 23, 2007 at 03:23:38AM +0200, Krzysztof Oledzki wrote:
> > I noticed that with httpchk, haproxy generates TCP RST at end of a check.
> > IMHO, it would be more polite to send FIN to a server, especially that
> > each TCP RST found by a tcpdump makes me concerned that something is
> > wrong, as it is hard to distinguish between a RST from a httpchk and from
> > a normal request, forwarded for a client.
>
> I have also noticed it very recently. In fact, it's never the
> application (here haproxy) which decides to send an RST, it's the
> system. It does so because the server returns data on a terminated
> socket. I guess it's because the health-check code does not read much
> of the response. In fact, we just need to read enough to process common
> responses. If people are dumb enough to check with something like "GET
> /image.iso", they should expect to get an RST after a few kbytes
> instead of reading the whole file!
Right, that was easy. Attached patch changed what you described. Now
haproxy finishes http checks with FIN.
This patch fixes a nasty bug raported by both glibc and valgrind, which
leads into a problem that haproxy does not exit when a new instace
starts ap (-sf/-st).
==9299== Invalid free() / delete / delete[]
==9299== at 0x401D095: free (in
/usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==9299== by 0x804A377: deinit (haproxy.c:721)
==9299== by 0x804A883: main (haproxy.c:1014)
==9299== Address 0x41859E0 is 0 bytes inside a block of size 21 free'd
==9299== at 0x401D095: free (in
/usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==9299== by 0x804A84B: main (haproxy.c:985)
==9299==
6542 open("/dev/tty", O_RDWR|O_NONBLOCK|O_NOCTTY) = -1 ENOENT (No such file
or directory)
6542 writev(2, [{"*** glibc detected *** ", 23}, {"corrupted double-linked
list", 28}, {": 0x", 4}, {"6ff91878", 8}, {" ***\n", 5}], 5) = -1 EBADF (Bad
file descriptor)
I found this bug trying to find why, after one week with many restarts, I
finished with >100 haproxy process running. ;)
When switching from a frontend to a backend, the "retries" parameter
was not kept, resulting in the impossibility to reconnect after the
first connection failure. This problem was reported and analyzed by
Krzysztof Oledzki.
While fixing the code, it appeared that some of the backend's timeouts
were not updated in the session when using "use_backend" or "default_backend".
It seems this had no impact but just in case, it's better to set them as
they should have been.
Since the timers have been changed, the timeouts for the default instance
have not been adjusted. This results in unspecified timeouts becoming zero
instead of infinite.