mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-21 05:00:42 +00:00
[MINOR] add the ability to force kernel socket buffer size.
Sometimes we need to be able to change the default kernel socket buffer size (recv and send). Four new global settings have been added for this : - tune.rcvbuf.client - tune.rcvbuf.server - tune.sndbuf.client - tune.sndbuf.server Those can be used to reduce kernel memory footprint with large numbers of concurrent connections, and to reduce risks of write timeouts with very slow clients due to excessive kernel buffering.
This commit is contained in:
parent
6046652253
commit
e803de2c6b
@ -399,6 +399,10 @@ The following keywords are supported in the "global" section :
|
||||
- tune.maxaccept
|
||||
- tune.maxpollevents
|
||||
- tune.maxrewrite
|
||||
- tune.rcvbuf.client
|
||||
- tune.rcvbuf.server
|
||||
- tune.sndbuf.client
|
||||
- tune.sndbuf.server
|
||||
|
||||
* Debugging
|
||||
- debug
|
||||
@ -639,6 +643,29 @@ tune.maxrewrite <number>
|
||||
larger than that. This means you don't have to worry about it when changing
|
||||
bufsize.
|
||||
|
||||
tune.rcvbuf.client <number>
|
||||
tune.rcvbuf.server <number>
|
||||
Forces the kernel socket receive buffer size on the client or the server side
|
||||
to the specified value in bytes. This value applies to all TCP/HTTP frontends
|
||||
and backends. It should normally never be set, and the default size (0) lets
|
||||
the kernel autotune this value depending on the amount of available memory.
|
||||
However it can sometimes help to set it to very low values (eg: 4096) in
|
||||
order to save kernel memory by preventing it from buffering too large amounts
|
||||
of received data. Lower values will significantly increase CPU usage though.
|
||||
|
||||
tune.sndbuf.client <number>
|
||||
tune.sndbuf.server <number>
|
||||
Forces the kernel socket send buffer size on the client or the server side to
|
||||
the specified value in bytes. This value applies to all TCP/HTTP frontends
|
||||
and backends. It should normally never be set, and the default size (0) lets
|
||||
the kernel autotune this value depending on the amount of available memory.
|
||||
However it can sometimes help to set it to very low values (eg: 4096) in
|
||||
order to save kernel memory by preventing it from buffering too large amounts
|
||||
of received data. Lower values will significantly increase CPU usage though.
|
||||
Another use case is to prevent write timeouts with extremely slow clients due
|
||||
to the kernel waiting for a large part of the buffer to be read before
|
||||
notifying haproxy again.
|
||||
|
||||
|
||||
3.3. Debugging
|
||||
--------------
|
||||
|
@ -87,6 +87,10 @@ struct global {
|
||||
int recv_enough; /* how many input bytes at once are "enough" */
|
||||
int bufsize; /* buffer size in bytes, defaults to BUFSIZE */
|
||||
int maxrewrite; /* buffer max rewrite size in bytes, defaults to MAXREWRITE */
|
||||
int client_sndbuf; /* set client sndbuf to this value if not null */
|
||||
int client_rcvbuf; /* set client rcvbuf to this value if not null */
|
||||
int server_sndbuf; /* set server sndbuf to this value if not null */
|
||||
int server_rcvbuf; /* set server rcvbuf to this value if not null */
|
||||
} tune;
|
||||
struct listener stats_sock; /* unix socket listener for statistics */
|
||||
struct proxy *stats_fe; /* the frontend holding the stats settings */
|
||||
|
@ -475,6 +475,58 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
|
||||
if (global.tune.maxrewrite >= global.tune.bufsize / 2)
|
||||
global.tune.maxrewrite = global.tune.bufsize / 2;
|
||||
}
|
||||
else if (!strcmp(args[0], "tune.rcvbuf.client")) {
|
||||
if (global.tune.client_rcvbuf != 0) {
|
||||
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT;
|
||||
goto out;
|
||||
}
|
||||
if (*(args[1]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
global.tune.client_rcvbuf = atol(args[1]);
|
||||
}
|
||||
else if (!strcmp(args[0], "tune.rcvbuf.server")) {
|
||||
if (global.tune.server_rcvbuf != 0) {
|
||||
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT;
|
||||
goto out;
|
||||
}
|
||||
if (*(args[1]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
global.tune.server_rcvbuf = atol(args[1]);
|
||||
}
|
||||
else if (!strcmp(args[0], "tune.sndbuf.client")) {
|
||||
if (global.tune.client_sndbuf != 0) {
|
||||
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT;
|
||||
goto out;
|
||||
}
|
||||
if (*(args[1]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
global.tune.client_sndbuf = atol(args[1]);
|
||||
}
|
||||
else if (!strcmp(args[0], "tune.sndbuf.server")) {
|
||||
if (global.tune.server_sndbuf != 0) {
|
||||
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT;
|
||||
goto out;
|
||||
}
|
||||
if (*(args[1]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
global.tune.server_sndbuf = atol(args[1]);
|
||||
}
|
||||
else if (!strcmp(args[0], "uid")) {
|
||||
if (global.uid != 0) {
|
||||
Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
|
||||
|
@ -172,6 +172,12 @@ int event_accept(int fd) {
|
||||
if (p->options & PR_O_TCP_NOLING)
|
||||
setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
|
||||
|
||||
if (global.tune.client_sndbuf)
|
||||
setsockopt(cfd, SOL_SOCKET, SO_SNDBUF, &global.tune.client_sndbuf, sizeof(global.tune.client_sndbuf));
|
||||
|
||||
if (global.tune.client_rcvbuf)
|
||||
setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));
|
||||
|
||||
t->process = l->handler;
|
||||
t->context = s;
|
||||
t->nice = l->nice;
|
||||
|
@ -378,6 +378,12 @@ int tcpv4_connect_server(struct stream_interface *si,
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
|
||||
#endif
|
||||
|
||||
if (global.tune.server_sndbuf)
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &global.tune.server_sndbuf, sizeof(global.tune.server_sndbuf));
|
||||
|
||||
if (global.tune.server_rcvbuf)
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
|
||||
|
||||
if ((connect(fd, (struct sockaddr *)srv_addr, sizeof(struct sockaddr_in)) == -1) &&
|
||||
(errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user