]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: compression: maximum compression rate limit
authorWilliam Lallemand <wlallemand@exceliance.fr>
Fri, 9 Nov 2012 16:05:39 +0000 (17:05 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 10 Nov 2012 16:47:27 +0000 (17:47 +0100)
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.

doc/configuration.txt
include/types/global.h
src/cfgparse.c
src/compression.c
src/dumpstats.c
src/haproxy.c
src/proto_http.c

index f624abbbc931816cf94b04cf21703bd54b338c44..0b310ee301699a438c803df03b82c26c52b0e0fa 100644 (file)
@@ -455,6 +455,7 @@ The following keywords are supported in the "global" section :
  * Performance tuning
    - maxconn
    - maxconnrate
+   - maxcomprate
    - maxpipes
    - maxsslconn
    - noepoll
@@ -672,6 +673,15 @@ maxconnrate <number>
   value close to its expected share. Also, lowering tune.maxaccept can improve
   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>
   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
@@ -11110,6 +11120,11 @@ set rate-limit connections global <value>
   applies to all frontends and the change has an immediate effect. The value
   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>
   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
index cfb10d1f1f8a8047e27fc7d67ebdbf694c38768e..6b267fbfcc8b12e76ff7dc44e7964e97295f6db6 100644 (file)
@@ -80,7 +80,10 @@ struct global {
        char *connect_default_ciphers;
 #endif
        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 comp_rate_lim;           /* HTTP compression rate limit */
        int maxpipes;           /* max # of pipes */
        int maxsock;            /* max # of sockets */
        int rlimit_nofile;      /* default ulimit-n value : 0=unset */
index 5f22b2424841afa9501c5d2079df616cecdaf38d..c601cbc8e30e5555d57646770768df9213a98968 100644 (file)
@@ -844,6 +844,14 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                }
                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")) {
                if (global.maxpipes != 0) {
                        Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
index 4c942aad702f12573e0ced7b9cd06bcf5965ef47..ae43cd3759405145b1bc85887d3f4956b380c57d 100644 (file)
@@ -31,6 +31,7 @@
 #include <types/compression.h>
 
 #include <proto/compression.h>
+#include <proto/freq_ctr.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;
 
+       /* 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. */
        if (ib->i > 0) {
                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;
        *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 */
        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->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;
 }
 
index da84f2a3de8edbd6abd58e17234e3352c984c9a4..0ee664164a30ca7d69e3033114cfdd7cbe2ca3e6 100644 (file)
@@ -1246,8 +1246,21 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
                                        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 {
-                               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;
                                return 1;
                        }
@@ -1708,6 +1721,8 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si)
                                     "ConnRate: %d\n"
                                     "ConnRateLimit: %d\n"
                                     "MaxConnRate: %d\n"
+                                    "CompressBpsIn: %u\n"
+                                    "CompressBpsOut: %u\n"
                                     "Tasks: %d\n"
                                     "Run_queue: %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,
                                     actconn, pipes_used, pipes_free,
                                     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,
                                     global.node, global.desc?global.desc:""
                                     );
index b322244fc4783efe033a7f75bce8e3345605b352..cfd6f84396e5f99a4fdf7c4b4cc77f093e37d732 100644 (file)
@@ -113,6 +113,7 @@ struct global global = {
        .req_count = 0,
        .logsrvs = LIST_HEAD_INIT(global.logsrvs),
        .maxzlibmem = 0,
+       .comp_rate_lim = 0,
        .unix_bind = {
                 .ux = {
                         .uid = -1,
index 7f151076476462a3f92b6e153221318234abc410..d768b87ac0ea6d10ff70994205caa3ac2153401d 100644 (file)
@@ -2087,6 +2087,11 @@ int select_compression_response_header(struct session *s, struct buffer *res)
 
        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 */
        if (s->comp_algo->init(&s->comp_ctx, global.tune.comp_maxlevel) < 0)
                goto fail;