From: Jim Jagielski Date: Mon, 24 Jan 2005 18:28:16 +0000 (+0000) Subject: Add in a weighted byte count of all traffic (in and out) as X-Git-Tag: 2.1.3~104 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fe2650384de1a98942a333af466290522ed1ab91;p=thirdparty%2Fapache%2Fhttpd.git Add in a weighted byte count of all traffic (in and out) as an alternative balancing method. We do not "adjust" the byte count wrt scheme or method, simply by factoring in the lbfactor value. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@126304 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index b7c892bac5f..e63bae447e3 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.1.3 [Remove entries to the current 2.0 section below, when backported] + *) proxy_balancer: Add in load-balancing via weighted traffic + byte count. [Jim Jagielski] + *) mod_disk_cache: Cache r->err_headers_out headers. This allows CGI scripts to be properly cached. [Justin Erenkrantz, Sander Striker] diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml index 3f0249464ba..34b3d6fcbf4 100644 --- a/docs/manual/mod/mod_proxy.xml +++ b/docs/manual/mod/mod_proxy.xml @@ -443,8 +443,8 @@ loadfactor 1 Worker load factor. Used with BalancerMember. - It is a number between 1 and 100 and defines the load applied to - the worker. + It is a number between 1 and 100 and defines the normalized weighted + load applied to the worker. route - @@ -472,6 +472,13 @@ Parameter Default Description + lbmethod + - + Balancer load-balance method. Select the load-balancing scheduler + method to use. Either requests, to perform weighted + request counting or traffic, to perform weighted + traffic byte count balancing. Default is requests. + stickysession - Balancer sticky session name. The value is usually set to something diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 83e87b98803..15e3ff5eed6 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -253,6 +253,15 @@ static const char *set_balancer_param(apr_pool_t *p, balancer->max_attempts = ival; balancer->max_attempts_set = 1; } + else if (!strcasecmp(key, "lbmethod")) { + /* Which LB scheduler method */ + if (!strcasecmp(val, "traffic")) + balancer->lbmethod = lbmethod_traffic; + else if (!strcasecmp(val, "requests")) + balancer->lbmethod = lbmethod_requests; + else + return "lbmethod must be Traffic|Requests"; + } else { return "unknown Balancer parameter"; } @@ -1695,11 +1704,15 @@ static int proxy_status_hook(request_rec *r, int flags) ap_rputs("
\n

Proxy LoadBalancer Status for ", r); ap_rvputs(r, balancer->name, "

\n\n", NULL); ap_rputs("\n\n" - "" + "" "\n", r); ap_rvputs(r, "\n", + ap_rprintf(r, "", apr_time_sec(balancer->timeout)); + ap_rprintf(r, "\n", + balancer->lbmethod == lbmethod_requests ? "Requests" : + balancer->lbmethod == lbmethod_traffic ? "Traffic" : + "Unknown"); ap_rputs("
SSesTimeoutSSesTimeoutMethod
", balancer->sticky, NULL); - ap_rprintf(r, "%" APR_TIME_T_FMT "%" APR_TIME_T_FMT "%s
\n", r); ap_rputs("\n\n" "" diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index db403d104f3..3a83c5ad8db 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -292,6 +292,10 @@ struct proxy_balancer { apr_interval_time_t timeout; /* Timeout for waiting on free connection */ int max_attempts; /* Number of attempts before failing */ char max_attempts_set; + enum { + lbmethod_requests = 1, + lbmethod_traffic = 2 + } lbmethod; /* XXX: Perhaps we will need the proc mutex too. * Altrough we are only using arithmetic operations diff --git a/modules/proxy/proxy_balancer.c b/modules/proxy/proxy_balancer.c index f0ea37d5c94..96774b8b011 100644 --- a/modules/proxy/proxy_balancer.c +++ b/modules/proxy/proxy_balancer.c @@ -161,7 +161,7 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, } /* - * The idea behind this scheduler is the following: + * The idea behind the find_best_byrequests scheduler is the following: * * lbfactor is "how much we expect this worker to work", or "the worker's * normalized work quota". @@ -205,7 +205,7 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, * b a d c d a c d b d ... * */ -static proxy_worker *find_best_worker(proxy_balancer *balancer, +static proxy_worker *find_best_byrequests(proxy_balancer *balancer, request_rec *r) { int i; @@ -213,9 +213,6 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, proxy_worker *worker = (proxy_worker *)balancer->workers->elts; proxy_worker *candidate = NULL; - if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS) - return NULL; - /* First try to see if we have available candidate */ for (i = 0; i < balancer->workers->nelts; i++) { /* If the worker is in error state run @@ -241,11 +238,88 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, if (candidate) { candidate->s->lbstatus -= total_factor; candidate->s->elected++; - PROXY_THREAD_UNLOCK(balancer); - return candidate; } - else { + + return candidate; +} + +/* + * The idea behind the find_best_bytraffic scheduler is the following: + * + * We know the amount of traffic (bytes in and out) handled by each + * worker. We normalize that traffic by each workers' weight. So assuming + * a setup as below: + * + * worker a b c + * lbfactor 1 1 3 + * + * the scheduler will allow worker c to handle 3 times the + * traffic of a and b. If each request/response results in the + * same amount of traffic, then c would be accessed 3 times as + * often as a or b. If, for example, a handled a request that + * resulted in a large i/o bytecount, then b and c would be + * chosen more often, to even things out. + */ +static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, + request_rec *r) +{ + int i; + apr_off_t mytraffic = 0; + apr_off_t curmin = 0; + proxy_worker *worker = (proxy_worker *)balancer->workers->elts; + proxy_worker *candidate = NULL; + + /* First try to see if we have available candidate */ + for (i = 0; i < balancer->workers->nelts; i++) { + /* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + */ + if (!PROXY_WORKER_IS_USABLE(worker)) + ap_proxy_retry_worker("BALANCER", worker, r->server); + /* Take into calculation only the workers that are + * not in error state or not disabled. + */ + if (PROXY_WORKER_IS_USABLE(worker)) { + mytraffic = (worker->s->transferred/worker->s->lbfactor) + + (worker->s->read/worker->s->lbfactor); + if (!candidate || mytraffic < curmin) { + candidate = worker; + curmin = mytraffic; + } + } + worker++; + } + + if (candidate) { + candidate->s->elected++; + } + + return candidate; +} + +static proxy_worker *find_best_worker(proxy_balancer *balancer, + request_rec *r) +{ + proxy_worker *candidate = NULL; + + if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS) + return NULL; + + if (balancer->lbmethod == lbmethod_requests) { + candidate = find_best_byrequests(balancer, r); + } else if (balancer->lbmethod == lbmethod_traffic) { + candidate = find_best_bytraffic(balancer, r); + } else { PROXY_THREAD_UNLOCK(balancer); + return NULL; + } + + PROXY_THREAD_UNLOCK(balancer); + + if (candidate == NULL) { /* All the workers are in error state or disabled. * If the balancer has a timeout sleep for a while * and try again to find the worker. The chances are @@ -522,6 +596,21 @@ static int balancer_handler(request_rec *r) bsel->max_attempts = ival; bsel->max_attempts_set = 1; } + if ((val = apr_table_get(params, "lm"))) { + int ival = atoi(val); + switch(ival) { + case 0: + break; + case lbmethod_traffic: + bsel->lbmethod = lbmethod_traffic; + break; + case lbmethod_requests: + bsel->lbmethod = lbmethod_requests; + break; + default: + break; + } + } } if (wsel) { const char *val; @@ -599,12 +688,15 @@ static int balancer_handler(request_rec *r) "\">", NULL); ap_rvputs(r, balancer->name, "\n\n", NULL); ap_rputs("\n\n
SchHostStat
" - "" + "" "\n", r); ap_rvputs(r, "", apr_time_sec(balancer->timeout)); ap_rprintf(r, "\n", balancer->max_attempts); + ap_rprintf(r, "\n", + balancer->lbmethod == lbmethod_requests ? "Requests" : + balancer->lbmethod == lbmethod_traffic ? "Traffic" : "Unknown"); ap_rputs("
StickySesionTimeoutFailoverAttemptsStickySessionTimeoutFailoverAttemptsMethod
", balancer->sticky, NULL); ap_rprintf(r, "%" APR_TIME_T_FMT "%d%s
\n", r); ap_rputs("\n\n" "" @@ -681,6 +773,12 @@ static int balancer_handler(request_rec *r) ap_rputs("\n", bsel->max_attempts); + ap_rputs("\n", r); ap_rputs("\n", r); ap_rvputs(r, "
SchemeHost
Failover Attempts:
LB Method:
\nname + sizeof("balancer://") - 1, diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 5c43fdee85e..679cafd97dd 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1164,6 +1164,7 @@ PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer, memset(*balancer, 0, sizeof(proxy_balancer)); (*balancer)->name = uri; + (*balancer)->lbmethod = lbmethod_requests; (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker)); /* XXX Is this a right place to create mutex */ #if APR_HAS_THREADS