From 61a56451a385ac3be1e1f5b2cfb4be61bd6eafa8 Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Mon, 31 Jul 2006 17:01:40 +0000 Subject: [PATCH] Add in a very simple balancer "set" concept, which allows for members to be assigned to a particular cluster set such that members in lower-numbered sets are checked/used before those in higher ones. Also bundled in this are some HTML cleanups for the balancer manager UI. Sorry for the mixins :) Compiles/builds clean: passes test framework as well as more normal usage tests ;) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@427172 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 4 + modules/proxy/mod_proxy.c | 9 +- modules/proxy/mod_proxy.h | 27 +++--- modules/proxy/mod_proxy_balancer.c | 149 ++++++++++++++++++----------- 4 files changed, 118 insertions(+), 71 deletions(-) diff --git a/CHANGES b/CHANGES index 5cc374d3a7..5f5da5276f 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,10 @@ Changes with Apache 2.3.0 [Remove entries to the current 2.0 and 2.2 section below, when backported] + *) mod_proxy_balancer: Workers can now be defined as part of + a balancer cluster "set" in which members of a lower-numbered set + are preferred over higher numbered ones. [Jim Jagielski] + *) SECURITY: CVE-2006-3747 (cve.mitre.org) mod_rewrite: Fix an off-by-one security problem in the ldap scheme handling. For some RewriteRules this could lead to a pointer being diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 2b1a9ba3d0..10865704fb 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -253,6 +253,12 @@ static const char *set_worker_param(apr_pool_t *p, worker->ping_timeout = apr_time_from_sec(ival); worker->ping_timeout_set = 1; } + else if (!strcasecmp(key, "lbset")) { + ival = atoi(val); + if (ival < 0 || ival > 99) + return "lbset must be between 0 and 99"; + worker->lbset = ival; + } else { return "unknown Worker parameter"; } @@ -1898,7 +1904,7 @@ static int proxy_status_hook(request_rec *r, int flags) ap_rputs("\n\n" "" "" - "" + "" "\n", r); worker = (proxy_worker *)balancer->workers->elts; @@ -1917,6 +1923,7 @@ static int proxy_status_hook(request_rec *r, int flags) ap_rvputs(r, "", worker->s->lbfactor); + ap_rprintf(r, "", worker->s->lbset); ap_rprintf(r, "
SchHostStatRouteRedirFAccWrRdFSetAccWrRd
", worker->s->route, NULL); ap_rvputs(r, "", worker->s->redirect, NULL); ap_rprintf(r, "%d%d%" APR_SIZE_T_FMT "", worker->s->elected); ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r); ap_rputs("", r); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index c6f8077af8..413953e65b 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -289,6 +289,8 @@ typedef struct { char route[PROXY_WORKER_MAX_ROUTE_SIZ+1]; char redirect[PROXY_WORKER_MAX_ROUTE_SIZ+1]; void *context; /* general purpose storage */ + apr_size_t busy; /* busyness factor */ + int lbset; /* load balancer cluster set */ } proxy_worker_stat; /* Worker configuration */ @@ -309,31 +311,32 @@ struct proxy_worker { apr_interval_time_t ttl; /* maximum amount of time in seconds a connection * may be available while exceeding the soft limit */ apr_interval_time_t timeout; /* connection timeout */ - char timeout_set; + char timeout_set; apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */ - char acquire_set; - apr_size_t recv_buffer_size; - char recv_buffer_size_set; - apr_size_t io_buffer_size; - char io_buffer_size_set; - char keepalive; - char keepalive_set; + char acquire_set; + apr_size_t recv_buffer_size; + char recv_buffer_size_set; + apr_size_t io_buffer_size; + char io_buffer_size_set; + char keepalive; + char keepalive_set; proxy_conn_pool *cp; /* Connection pool to use */ proxy_worker_stat *s; /* Shared data */ - void *opaque; /* per scheme worker data */ - int is_address_reusable; + void *opaque; /* per scheme worker data */ + int is_address_reusable; #if APR_HAS_THREADS apr_thread_mutex_t *mutex; /* Thread lock for updating address cache */ #endif - void *context; /* general purpose storage */ + void *context; /* general purpose storage */ enum { flush_off, flush_on, flush_auto } flush_packets; /* control AJP flushing */ - int flush_wait; /* poll wait time in microseconds if flush_auto */ + int flush_wait; /* poll wait time in microseconds if flush_auto */ apr_interval_time_t ping_timeout; char ping_timeout_set; + int lbset; /* load balancer cluster set */ }; /* diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index ff0322f663..27b43cb7cf 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -100,6 +100,7 @@ static int init_balancer_members(proxy_server_conf *conf, server_rec *s, /* Set to the original configuration */ workers[i].s->lbstatus = workers[i].s->lbfactor = (workers[i].lbfactor ? workers[i].lbfactor : 1); + workers[i].s->lbset = workers[i].lbset; } /* Set default number of attempts to the number of * workers. @@ -622,6 +623,12 @@ static int balancer_handler(request_rec *r) else if (!strcasecmp(val, "Enable")) wsel->s->status &= ~PROXY_WORKER_DISABLED; } + if ((val = apr_table_get(params, "ls"))) { + int ival = atoi(val); + if (ival >= 0 && ival <= 99) { + wsel->s->lbset = ival; + } + } } if (apr_table_get(params, "xml")) { @@ -684,13 +691,13 @@ static int balancer_handler(request_rec *r) ap_rputs("\n\n" "" "" - "" + "" "" "\n", r); worker = (proxy_worker *)balancer->workers->elts; for (n = 0; n < balancer->workers->nelts; n++) { - + char fbuf[50]; ap_rvputs(r, "\n", NULL); ap_rvputs(r, "", worker->s->lbfactor); + ap_rprintf(r, "", r); - ap_rprintf(r, "", worker->s->elected); - ap_rprintf(r, "", worker->s->transferred); - ap_rprintf(r, "", worker->s->read); - ap_rputs("\n", r); + ap_rprintf(r, "\n", r); ++worker; } @@ -729,20 +738,22 @@ static int balancer_handler(request_rec *r) ap_rvputs(r, "uri, "\">\n
", NULL); ap_rputs("
Worker URLRouteRouteRedirFactorStatusFactorSetStatusElectedToFrom
uri, "?b=", balancer->name + sizeof("balancer://") - 1, "&w=", ap_escape_uri(r->pool, worker->name), @@ -698,7 +705,8 @@ static int balancer_handler(request_rec *r) ap_rvputs(r, worker->name, "", worker->s->route, NULL); ap_rvputs(r, "", worker->s->redirect, NULL); - ap_rprintf(r, "%d", worker->s->lbfactor); + ap_rprintf(r, "%d%d", worker->s->lbset); if (worker->s->status & PROXY_WORKER_DISABLED) ap_rputs("Dis ", r); if (worker->s->status & PROXY_WORKER_IN_ERROR) @@ -712,10 +720,11 @@ static int balancer_handler(request_rec *r) if (!PROXY_WORKER_IS_INITIALIZED(worker)) ap_rputs("-", r); ap_rputs("%" APR_SIZE_T_FMT "%" APR_OFF_T_FMT "%" APR_OFF_T_FMT "
%" APR_SIZE_T_FMT "", worker->s->elected); + ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r); + ap_rputs("", r); + ap_rputs(apr_strfsize(worker->s->read, fbuf), r); + ap_rputs("
\n", wsel->s->lbfactor); + ap_rprintf(r, "value=\"%d\">\n", wsel->s->lbfactor); + ap_rputs("\n", wsel->s->lbset); ap_rputs("\n", r); + ap_rputs("\">\n", r); ap_rputs("\n", r); + ap_rputs("\">\n", r); ap_rputs("\n", r); + ap_rputs(">\n", r); ap_rputs("\n", r); ap_rvputs(r, "
Load factor:
LB Set:
Route:route, NULL); - ap_rputs("\">
Route Redirect:redirect, NULL); - ap_rputs("\">
Status:Disabled: s->status & PROXY_WORKER_DISABLED) ap_rputs(" checked", r); ap_rputs("> | Enabled: s->status & PROXY_WORKER_DISABLED)) ap_rputs(" checked", r); - ap_rputs(">
\npool, wsel->name), "\">\n", NULL); @@ -867,37 +878,48 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer, proxy_worker *mycandidate = NULL; int checking_standby = 0; int checked_standby = 0; + int cur_lbset = 0; + int max_lbset = 0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: Entering byrequests for BALANCER (%s)", balancer->name); /* First try to see if we have available candidate */ - while (!mycandidate && !checked_standby) { - worker = (proxy_worker *)balancer->workers->elts; - for (i = 0; i < balancer->workers->nelts; i++, worker++) { - if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) - continue; - /* 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)) { - worker->s->lbstatus += worker->s->lbfactor; - total_factor += worker->s->lbfactor; - if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus) - mycandidate = worker; + do { + while (!mycandidate && !checked_standby) { + worker = (proxy_worker *)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if (!checking_standby) { /* first time through */ + if (worker->s->lbset > max_lbset) + max_lbset = worker->s->lbset; + } + if (worker->s->lbset > cur_lbset) + continue; + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) + continue; + /* 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)) { + worker->s->lbstatus += worker->s->lbfactor; + total_factor += worker->s->lbfactor; + if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus) + mycandidate = worker; + } } + checked_standby = checking_standby++; } - checked_standby = checking_standby++; - } + cur_lbset++; + } while (cur_lbset < max_lbset && !mycandidate); if (mycandidate) { mycandidate->s->lbstatus -= total_factor; @@ -934,39 +956,50 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, int checking_standby = 0; int checked_standby = 0; proxy_worker *mycandidate = NULL; + int cur_lbset = 0; + int max_lbset = 0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: Entering bytraffic for BALANCER (%s)", balancer->name); /* First try to see if we have available candidate */ - while (!mycandidate && !checked_standby) { - worker = (proxy_worker *)balancer->workers->elts; - for (i = 0; i < balancer->workers->nelts; i++, worker++) { - if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) - continue; - /* 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 (!mycandidate || mytraffic < curmin) { - mycandidate = worker; - curmin = mytraffic; + do { + while (!mycandidate && !checked_standby) { + worker = (proxy_worker *)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if (!checking_standby) { /* first time through */ + if (worker->s->lbset > max_lbset) + max_lbset = worker->s->lbset; + } + if (worker->s->lbset > cur_lbset) + continue; + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) + continue; + /* 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 (!mycandidate || mytraffic < curmin) { + mycandidate = worker; + curmin = mytraffic; + } } } + checked_standby = checking_standby++; } - checked_standby = checking_standby++; - } + cur_lbset++; + } while (cur_lbset < max_lbset && !mycandidate); if (mycandidate) { mycandidate->s->elected++; -- 2.49.0