mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 14:21:25 +02:00
BUG/MEDIUM: spoe: Don't start new applet if there are enough idle ones
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.
This commit is contained in:
parent
d2f61de8c2
commit
e99c43907c
@ -308,6 +308,7 @@ struct spoe_agent {
|
|||||||
struct freq_ctr conn_per_sec; /* connections per second */
|
struct freq_ctr conn_per_sec; /* connections per second */
|
||||||
struct freq_ctr err_per_sec; /* connection errors 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 eb_root idle_applets; /* idle SPOE applets available to process data */
|
||||||
struct list applets; /* all SPOE applets for this agent */
|
struct list applets; /* all SPOE applets for this agent */
|
||||||
struct list sending_queue; /* Queue of streams waiting to send data */
|
struct list sending_queue; /* Queue of streams waiting to send data */
|
||||||
|
@ -1294,6 +1294,7 @@ spoe_release_appctx(struct appctx *appctx)
|
|||||||
if (appctx->st0 == SPOE_APPCTX_ST_IDLE) {
|
if (appctx->st0 == SPOE_APPCTX_ST_IDLE) {
|
||||||
eb32_delete(&spoe_appctx->node);
|
eb32_delete(&spoe_appctx->node);
|
||||||
_HA_ATOMIC_DEC(&agent->counters.idles);
|
_HA_ATOMIC_DEC(&agent->counters.idles);
|
||||||
|
agent->rt[tid].idles--;
|
||||||
}
|
}
|
||||||
|
|
||||||
appctx->st0 = SPOE_APPCTX_ST_END;
|
appctx->st0 = SPOE_APPCTX_ST_END;
|
||||||
@ -1494,6 +1495,7 @@ spoe_handle_connecting_appctx(struct appctx *appctx)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
_HA_ATOMIC_INC(&agent->counters.idles);
|
_HA_ATOMIC_INC(&agent->counters.idles);
|
||||||
|
agent->rt[tid].idles++;
|
||||||
appctx->st0 = SPOE_APPCTX_ST_IDLE;
|
appctx->st0 = SPOE_APPCTX_ST_IDLE;
|
||||||
SPOE_APPCTX(appctx)->node.key = 0;
|
SPOE_APPCTX(appctx)->node.key = 0;
|
||||||
eb32_insert(&agent->rt[tid].idle_applets, &SPOE_APPCTX(appctx)->node);
|
eb32_insert(&agent->rt[tid].idle_applets, &SPOE_APPCTX(appctx)->node);
|
||||||
@ -1803,6 +1805,7 @@ spoe_handle_processing_appctx(struct appctx *appctx)
|
|||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
_HA_ATOMIC_INC(&agent->counters.idles);
|
_HA_ATOMIC_INC(&agent->counters.idles);
|
||||||
|
agent->rt[tid].idles++;
|
||||||
appctx->st0 = SPOE_APPCTX_ST_IDLE;
|
appctx->st0 = SPOE_APPCTX_ST_IDLE;
|
||||||
eb32_insert(&agent->rt[tid].idle_applets, &SPOE_APPCTX(appctx)->node);
|
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:
|
case SPOE_APPCTX_ST_IDLE:
|
||||||
_HA_ATOMIC_DEC(&agent->counters.idles);
|
_HA_ATOMIC_DEC(&agent->counters.idles);
|
||||||
|
agent->rt[tid].idles--;
|
||||||
eb32_delete(&SPOE_APPCTX(appctx)->node);
|
eb32_delete(&SPOE_APPCTX(appctx)->node);
|
||||||
if (stopping &&
|
if (stopping &&
|
||||||
LIST_ISEMPTY(&agent->rt[tid].sending_queue) &&
|
LIST_ISEMPTY(&agent->rt[tid].sending_queue) &&
|
||||||
@ -2066,8 +2070,8 @@ spoe_queue_context(struct spoe_context *ctx)
|
|||||||
struct spoe_appctx *spoe_appctx;
|
struct spoe_appctx *spoe_appctx;
|
||||||
|
|
||||||
/* Check if we need to create a new SPOE applet or not. */
|
/* Check if we need to create a new SPOE applet or not. */
|
||||||
if (!eb_is_empty(&agent->rt[tid].idle_applets) &&
|
if (agent->rt[tid].processing < agent->rt[tid].idles ||
|
||||||
(agent->rt[tid].processing == 1 || agent->rt[tid].processing < read_freq_ctr(&agent->rt[tid].processing_per_sec)))
|
agent->rt[tid].processing < read_freq_ctr(&agent->rt[tid].processing_per_sec))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
|
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].engine_id = NULL;
|
||||||
conf->agent->rt[i].frame_size = conf->agent->max_frame_size;
|
conf->agent->rt[i].frame_size = conf->agent->max_frame_size;
|
||||||
conf->agent->rt[i].processing = 0;
|
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].applets);
|
||||||
LIST_INIT(&conf->agent->rt[i].sending_queue);
|
LIST_INIT(&conf->agent->rt[i].sending_queue);
|
||||||
LIST_INIT(&conf->agent->rt[i].waiting_queue);
|
LIST_INIT(&conf->agent->rt[i].waiting_queue);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user