MINOR: compression: maximum compression rate limit

This patch adds input and output rate calcutation on the HTTP compresion
feature.

Compression can be limited with a maximum rate value in kilobytes per
second. The rate is set with the global 'maxcomprate' option. You can
change this value dynamicaly with 'set rate-limit http-compression
global' on the UNIX socket.
This commit is contained in:
William Lallemand 2012-11-09 17:05:39 +01:00 committed by Willy Tarreau
parent f3747837e5
commit d85f917daf
7 changed files with 74 additions and 1 deletions

View File

@ -455,6 +455,7 @@ The following keywords are supported in the "global" section :
* Performance tuning * Performance tuning
- maxconn - maxconn
- maxconnrate - maxconnrate
- maxcomprate
- maxpipes - maxpipes
- maxsslconn - maxsslconn
- noepoll - noepoll
@ -672,6 +673,15 @@ maxconnrate <number>
value close to its expected share. Also, lowering tune.maxaccept can improve value close to its expected share. Also, lowering tune.maxaccept can improve
fairness. fairness.
maxcomprate <number>
Sets the maximum per-process input compression rate to <number> kilobytes
pers second. For each session, if the maximum is reached, the compression
level will be decreased during the session. If the maximum is reached at the
beginning of a session, the session will not compress at all. If the maximum
is not reached, the compression level will be increased up to
tune.comp.maxlevel. A value of zero means there is no limit, this is the
default value.
maxpipes <number> maxpipes <number>
Sets the maximum per-process number of pipes to <number>. Currently, pipes Sets the maximum per-process number of pipes to <number>. Currently, pipes
are only used by kernel-based tcp splicing. Since a pipe contains two file are only used by kernel-based tcp splicing. Since a pipe contains two file
@ -11110,6 +11120,11 @@ set rate-limit connections global <value>
applies to all frontends and the change has an immediate effect. The value applies to all frontends and the change has an immediate effect. The value
is passed in number of connections per second. is passed in number of connections per second.
set rate-limit http-compression global <value>
Change the maximum input compression rate, which is set by the global
'maxcomprate' setting. A value of zero disables the limitation. The value is
passed in number of kilobytes per second.
set table <table> key <key> data.<data_type> <value> set table <table> key <key> data.<data_type> <value>
Create or update a stick-table entry in the table. If the key is not present, Create or update a stick-table entry in the table. If the key is not present,
an entry is inserted. See stick-table in section 4.2 to find all possible an entry is inserted. See stick-table in section 4.2 to find all possible

View File

@ -80,7 +80,10 @@ struct global {
char *connect_default_ciphers; char *connect_default_ciphers;
#endif #endif
struct freq_ctr conn_per_sec; struct freq_ctr conn_per_sec;
struct freq_ctr comp_bps_in; /* bytes per second, before http compression */
struct freq_ctr comp_bps_out; /* bytes per second, after http compression */
int cps_lim, cps_max; int cps_lim, cps_max;
int comp_rate_lim; /* HTTP compression rate limit */
int maxpipes; /* max # of pipes */ int maxpipes; /* max # of pipes */
int maxsock; /* max # of sockets */ int maxsock; /* max # of sockets */
int rlimit_nofile; /* default ulimit-n value : 0=unset */ int rlimit_nofile; /* default ulimit-n value : 0=unset */

View File

@ -844,6 +844,14 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
} }
global.cps_lim = atol(args[1]); global.cps_lim = atol(args[1]);
} }
else if (!strcmp(args[0], "maxcomprate")) {
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer argument in kb/s.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
global.comp_rate_lim = atoi(args[1]) * 1024;
}
else if (!strcmp(args[0], "maxpipes")) { else if (!strcmp(args[0], "maxpipes")) {
if (global.maxpipes != 0) { if (global.maxpipes != 0) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);

View File

@ -31,6 +31,7 @@
#include <types/compression.h> #include <types/compression.h>
#include <proto/compression.h> #include <proto/compression.h>
#include <proto/freq_ctr.h>
#include <proto/proto_http.h> #include <proto/proto_http.h>
@ -261,6 +262,10 @@ int http_compression_buffer_end(struct session *s, struct buffer **in, struct bu
to_forward = ob->i; to_forward = ob->i;
/* update input rate */
if (s->comp_ctx.cur_lvl > 0)
update_freq_ctr(&global.comp_bps_in, ib->o - ob->o);
/* copy the remaining data in the tmp buffer. */ /* copy the remaining data in the tmp buffer. */
if (ib->i > 0) { if (ib->i > 0) {
left = ib->i - bi_contig_data(ib); left = ib->i - bi_contig_data(ib);
@ -276,6 +281,9 @@ int http_compression_buffer_end(struct session *s, struct buffer **in, struct bu
*in = ob; *in = ob;
*out = ib; *out = ib;
if (s->comp_ctx.cur_lvl > 0)
update_freq_ctr(&global.comp_bps_out, to_forward);
/* forward the new chunk without remaining data */ /* forward the new chunk without remaining data */
b_adv(ob, to_forward); b_adv(ob, to_forward);
@ -490,6 +498,23 @@ int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out, int flag)
out_len = (out->size - buffer_len(out)) - strm->avail_out; out_len = (out->size - buffer_len(out)) - strm->avail_out;
out->i += out_len; out->i += out_len;
/* compression rate limit */
if (global.comp_rate_lim > 0) {
if (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim) {
/* decrease level */
if (comp_ctx->cur_lvl > 0) {
comp_ctx->cur_lvl--;
deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
}
} else if (comp_ctx->cur_lvl < global.comp_rate_lim) {
/* increase level */
comp_ctx->cur_lvl++ ;
deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
}
}
return out_len; return out_len;
} }

View File

@ -1246,8 +1246,21 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
return 1; return 1;
} }
} }
else if (strcmp(args[2], "http-compression") == 0) {
if (strcmp(args[3], "global") == 0) {
int v;
v = atoi(args[4]);
global.comp_rate_lim = v * 1024; /* Kilo to bytes. */
}
else {
si->applet.ctx.cli.msg = "'set rate-limit http-compression' only supports 'global'.\n";
si->applet.st0 = STAT_CLI_PRINT;
return 1;
}
}
else { else {
si->applet.ctx.cli.msg = "'set rate-limit' only supports 'connections'.\n"; si->applet.ctx.cli.msg = "'set rate-limit' supports 'connections' and 'http-compression'.\n";
si->applet.st0 = STAT_CLI_PRINT; si->applet.st0 = STAT_CLI_PRINT;
return 1; return 1;
} }
@ -1708,6 +1721,8 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si)
"ConnRate: %d\n" "ConnRate: %d\n"
"ConnRateLimit: %d\n" "ConnRateLimit: %d\n"
"MaxConnRate: %d\n" "MaxConnRate: %d\n"
"CompressBpsIn: %u\n"
"CompressBpsOut: %u\n"
"Tasks: %d\n" "Tasks: %d\n"
"Run_queue: %d\n" "Run_queue: %d\n"
"Idle_pct: %d\n" "Idle_pct: %d\n"
@ -1724,6 +1739,7 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si)
global.maxsock, global.maxconn, global.hardmaxconn, global.maxpipes, global.maxsock, global.maxconn, global.hardmaxconn, global.maxpipes,
actconn, pipes_used, pipes_free, actconn, pipes_used, pipes_free,
read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max, read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max,
read_freq_ctr(&global.comp_bps_in), read_freq_ctr(&global.comp_bps_out),
nb_tasks_cur, run_queue_cur, idle_pct, nb_tasks_cur, run_queue_cur, idle_pct,
global.node, global.desc?global.desc:"" global.node, global.desc?global.desc:""
); );

View File

@ -113,6 +113,7 @@ struct global global = {
.req_count = 0, .req_count = 0,
.logsrvs = LIST_HEAD_INIT(global.logsrvs), .logsrvs = LIST_HEAD_INIT(global.logsrvs),
.maxzlibmem = 0, .maxzlibmem = 0,
.comp_rate_lim = 0,
.unix_bind = { .unix_bind = {
.ux = { .ux = {
.uid = -1, .uid = -1,

View File

@ -2087,6 +2087,11 @@ int select_compression_response_header(struct session *s, struct buffer *res)
ctx.idx = 0; ctx.idx = 0;
/* limit compression rate */
if (global.comp_rate_lim > 0)
if (read_freq_ctr(&global.comp_bps_in) > global.comp_rate_lim)
goto fail;
/* initialize compression */ /* initialize compression */
if (s->comp_algo->init(&s->comp_ctx, global.tune.comp_maxlevel) < 0) if (s->comp_algo->init(&s->comp_ctx, global.tune.comp_maxlevel) < 0)
goto fail; goto fail;