]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: spoe: Don't start new applet if there are enough idle ones
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 26 Apr 2023 13:56:59 +0000 (15:56 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 28 Apr 2023 06:51:34 +0000 (08:51 +0200)
It is possible to start too many applets on sporadic burst of events after
an inactivity period. It is due to the way we estimate if a new applet must
be created or not. It is based on a frequency counter. We compare the events
processing rate against the number of events currently processed (in
progress or waiting to be processed). But we should also take care of the
number of idle applets.

We already track the number of idle applets, but it is global and not
per-thread. Thus we now also track the number of idle applets per-thread. It
is not a big deal because this fills a hole in the spoe_agent structure.
Thanks to this counter, we can refrain applets creation if there is enough
idle applets to handle currently processed events.

This patch should be backported to every stable versions.

include/haproxy/spoe-t.h
src/flt_spoe.c

index dcc217115a0c7b8e58fa3133fbb668bd27f269bf..57b8eacd2126c5989a5cf633d727bf5defe50c87 100644 (file)
@@ -308,6 +308,7 @@ struct spoe_agent {
                struct freq_ctr conn_per_sec;   /* connections per second */
                struct freq_ctr err_per_sec;    /* connection errors per second */
 
+               unsigned int    idles;          /* # of idle applets */
                struct eb_root  idle_applets;   /* idle SPOE applets available to process data */
                struct list     applets;        /* all SPOE applets for this agent */
                struct list     sending_queue;  /* Queue of streams waiting to send data */
index 48f2e2fbe82f4f818b0b77dd211278a52e5e7e96..1f88ab0a3e4762562ee15e44eda8ea3cb6c3adea 100644 (file)
@@ -1294,6 +1294,7 @@ spoe_release_appctx(struct appctx *appctx)
                if (appctx->st0 == SPOE_APPCTX_ST_IDLE) {
                        eb32_delete(&spoe_appctx->node);
                        _HA_ATOMIC_DEC(&agent->counters.idles);
+                       agent->rt[tid].idles--;
                }
 
                appctx->st0 = SPOE_APPCTX_ST_END;
@@ -1494,6 +1495,7 @@ spoe_handle_connecting_appctx(struct appctx *appctx)
 
                default:
                        _HA_ATOMIC_INC(&agent->counters.idles);
+                       agent->rt[tid].idles++;
                        appctx->st0 = SPOE_APPCTX_ST_IDLE;
                        SPOE_APPCTX(appctx)->node.key = 0;
                        eb32_insert(&agent->rt[tid].idle_applets, &SPOE_APPCTX(appctx)->node);
@@ -1803,6 +1805,7 @@ spoe_handle_processing_appctx(struct appctx *appctx)
                        goto next;
                }
                _HA_ATOMIC_INC(&agent->counters.idles);
+               agent->rt[tid].idles++;
                appctx->st0 = SPOE_APPCTX_ST_IDLE;
                eb32_insert(&agent->rt[tid].idle_applets, &SPOE_APPCTX(appctx)->node);
        }
@@ -1960,6 +1963,7 @@ spoe_handle_appctx(struct appctx *appctx)
 
                case SPOE_APPCTX_ST_IDLE:
                        _HA_ATOMIC_DEC(&agent->counters.idles);
+                       agent->rt[tid].idles--;
                        eb32_delete(&SPOE_APPCTX(appctx)->node);
                        if (stopping &&
                            LIST_ISEMPTY(&agent->rt[tid].sending_queue) &&
@@ -2066,8 +2070,8 @@ spoe_queue_context(struct spoe_context *ctx)
        struct spoe_appctx *spoe_appctx;
 
        /* Check if we need to create a new SPOE applet or not. */
-       if (!eb_is_empty(&agent->rt[tid].idle_applets) &&
-           (agent->rt[tid].processing == 1 || agent->rt[tid].processing < read_freq_ctr(&agent->rt[tid].processing_per_sec)))
+       if (agent->rt[tid].processing < agent->rt[tid].idles  ||
+           agent->rt[tid].processing < read_freq_ctr(&agent->rt[tid].processing_per_sec))
                goto end;
 
        SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
@@ -3107,6 +3111,7 @@ spoe_check(struct proxy *px, struct flt_conf *fconf)
                conf->agent->rt[i].engine_id    = NULL;
                conf->agent->rt[i].frame_size   = conf->agent->max_frame_size;
                conf->agent->rt[i].processing   = 0;
+               conf->agent->rt[i].idles        = 0;
                LIST_INIT(&conf->agent->rt[i].applets);
                LIST_INIT(&conf->agent->rt[i].sending_queue);
                LIST_INIT(&conf->agent->rt[i].waiting_queue);