1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

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
This commit is contained in:
Jim Jagielski
2006-07-31 17:01:40 +00:00
parent 7aa10a383a
commit 61a56451a3
4 changed files with 118 additions and 71 deletions

View File

@@ -2,6 +2,10 @@
Changes with Apache 2.3.0 Changes with Apache 2.3.0
[Remove entries to the current 2.0 and 2.2 section below, when backported] [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) *) SECURITY: CVE-2006-3747 (cve.mitre.org)
mod_rewrite: Fix an off-by-one security problem in the ldap scheme mod_rewrite: Fix an off-by-one security problem in the ldap scheme
handling. For some RewriteRules this could lead to a pointer being handling. For some RewriteRules this could lead to a pointer being

View File

@@ -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 = apr_time_from_sec(ival);
worker->ping_timeout_set = 1; 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 { else {
return "unknown Worker parameter"; return "unknown Worker parameter";
} }
@@ -1898,7 +1904,7 @@ static int proxy_status_hook(request_rec *r, int flags)
ap_rputs("\n\n<table border=\"0\"><tr>" ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>Sch</th><th>Host</th><th>Stat</th>" "<th>Sch</th><th>Host</th><th>Stat</th>"
"<th>Route</th><th>Redir</th>" "<th>Route</th><th>Redir</th>"
"<th>F</th><th>Acc</th><th>Wr</th><th>Rd</th>" "<th>F</th><th>Set</th><th>Acc</th><th>Wr</th><th>Rd</th>"
"</tr>\n", r); "</tr>\n", r);
worker = (proxy_worker *)balancer->workers->elts; worker = (proxy_worker *)balancer->workers->elts;
@@ -1917,6 +1923,7 @@ static int proxy_status_hook(request_rec *r, int flags)
ap_rvputs(r, "</td><td>", worker->s->route, NULL); ap_rvputs(r, "</td><td>", worker->s->route, NULL);
ap_rvputs(r, "</td><td>", worker->s->redirect, NULL); ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor); ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
ap_rprintf(r, "<td>%d</td>", worker->s->lbset);
ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td><td>", worker->s->elected); ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td><td>", worker->s->elected);
ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r); ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r);
ap_rputs("</td><td>", r); ap_rputs("</td><td>", r);

View File

@@ -289,6 +289,8 @@ typedef struct {
char route[PROXY_WORKER_MAX_ROUTE_SIZ+1]; char route[PROXY_WORKER_MAX_ROUTE_SIZ+1];
char redirect[PROXY_WORKER_MAX_ROUTE_SIZ+1]; char redirect[PROXY_WORKER_MAX_ROUTE_SIZ+1];
void *context; /* general purpose storage */ void *context; /* general purpose storage */
apr_size_t busy; /* busyness factor */
int lbset; /* load balancer cluster set */
} proxy_worker_stat; } proxy_worker_stat;
/* Worker configuration */ /* Worker configuration */
@@ -309,31 +311,32 @@ struct proxy_worker {
apr_interval_time_t ttl; /* maximum amount of time in seconds a connection apr_interval_time_t ttl; /* maximum amount of time in seconds a connection
* may be available while exceeding the soft limit */ * may be available while exceeding the soft limit */
apr_interval_time_t timeout; /* connection timeout */ 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 */ apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
char acquire_set; char acquire_set;
apr_size_t recv_buffer_size; apr_size_t recv_buffer_size;
char recv_buffer_size_set; char recv_buffer_size_set;
apr_size_t io_buffer_size; apr_size_t io_buffer_size;
char io_buffer_size_set; char io_buffer_size_set;
char keepalive; char keepalive;
char keepalive_set; char keepalive_set;
proxy_conn_pool *cp; /* Connection pool to use */ proxy_conn_pool *cp; /* Connection pool to use */
proxy_worker_stat *s; /* Shared data */ proxy_worker_stat *s; /* Shared data */
void *opaque; /* per scheme worker data */ void *opaque; /* per scheme worker data */
int is_address_reusable; int is_address_reusable;
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_t *mutex; /* Thread lock for updating address cache */ apr_thread_mutex_t *mutex; /* Thread lock for updating address cache */
#endif #endif
void *context; /* general purpose storage */ void *context; /* general purpose storage */
enum { enum {
flush_off, flush_off,
flush_on, flush_on,
flush_auto flush_auto
} flush_packets; /* control AJP flushing */ } 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; apr_interval_time_t ping_timeout;
char ping_timeout_set; char ping_timeout_set;
int lbset; /* load balancer cluster set */
}; };
/* /*

View File

@@ -100,6 +100,7 @@ static int init_balancer_members(proxy_server_conf *conf, server_rec *s,
/* Set to the original configuration */ /* Set to the original configuration */
workers[i].s->lbstatus = workers[i].s->lbfactor = workers[i].s->lbstatus = workers[i].s->lbfactor =
(workers[i].lbfactor ? workers[i].lbfactor : 1); (workers[i].lbfactor ? workers[i].lbfactor : 1);
workers[i].s->lbset = workers[i].lbset;
} }
/* Set default number of attempts to the number of /* Set default number of attempts to the number of
* workers. * workers.
@@ -622,6 +623,12 @@ static int balancer_handler(request_rec *r)
else if (!strcasecmp(val, "Enable")) else if (!strcasecmp(val, "Enable"))
wsel->s->status &= ~PROXY_WORKER_DISABLED; 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")) { if (apr_table_get(params, "xml")) {
@@ -684,13 +691,13 @@ static int balancer_handler(request_rec *r)
ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>" ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
"<th>Worker URL</th>" "<th>Worker URL</th>"
"<th>Route</th><th>RouteRedir</th>" "<th>Route</th><th>RouteRedir</th>"
"<th>Factor</th><th>Status</th>" "<th>Factor</th><th>Set</th><th>Status</th>"
"<th>Elected</th><th>To</th><th>From</th>" "<th>Elected</th><th>To</th><th>From</th>"
"</tr>\n", r); "</tr>\n", r);
worker = (proxy_worker *)balancer->workers->elts; worker = (proxy_worker *)balancer->workers->elts;
for (n = 0; n < balancer->workers->nelts; n++) { for (n = 0; n < balancer->workers->nelts; n++) {
char fbuf[50];
ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=", ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=",
balancer->name + sizeof("balancer://") - 1, "&w=", balancer->name + sizeof("balancer://") - 1, "&w=",
ap_escape_uri(r->pool, worker->name), ap_escape_uri(r->pool, worker->name),
@@ -698,7 +705,8 @@ static int balancer_handler(request_rec *r)
ap_rvputs(r, worker->name, "</a></td>", NULL); ap_rvputs(r, worker->name, "</a></td>", NULL);
ap_rvputs(r, "<td>", worker->s->route, NULL); ap_rvputs(r, "<td>", worker->s->route, NULL);
ap_rvputs(r, "</td><td>", worker->s->redirect, NULL); ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
ap_rprintf(r, "</td><td>%d</td><td>", worker->s->lbfactor); ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
ap_rprintf(r, "<td>%d</td><td>", worker->s->lbset);
if (worker->s->status & PROXY_WORKER_DISABLED) if (worker->s->status & PROXY_WORKER_DISABLED)
ap_rputs("Dis ", r); ap_rputs("Dis ", r);
if (worker->s->status & PROXY_WORKER_IN_ERROR) 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)) if (!PROXY_WORKER_IS_INITIALIZED(worker))
ap_rputs("-", r); ap_rputs("-", r);
ap_rputs("</td>", r); ap_rputs("</td>", r);
ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td>", worker->s->elected); ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td><td>", worker->s->elected);
ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->transferred); ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r);
ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->read); ap_rputs("</td><td>", r);
ap_rputs("</tr>\n", r); ap_rputs(apr_strfsize(worker->s->read, fbuf), r);
ap_rputs("</td></tr>\n", r);
++worker; ++worker;
} }
@@ -729,20 +738,22 @@ static int balancer_handler(request_rec *r)
ap_rvputs(r, "<form method=\"GET\" action=\"", NULL); ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
ap_rvputs(r, r->uri, "\">\n<dl>", NULL); ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r); ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
ap_rprintf(r, "value=\"%d\"></td><tr>\n", wsel->s->lbfactor); ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbfactor);
ap_rputs("<tr><td>LB Set:</td><td><input name=\"ls\" type=text ", r);
ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbset);
ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r); ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
ap_rvputs(r, "value=\"", wsel->route, NULL); ap_rvputs(r, "value=\"", wsel->route, NULL);
ap_rputs("\"></td><tr>\n", r); ap_rputs("\"></td></tr>\n", r);
ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r); ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
ap_rvputs(r, "value=\"", wsel->redirect, NULL); ap_rvputs(r, "value=\"", wsel->redirect, NULL);
ap_rputs("\"></td><tr>\n", r); ap_rputs("\"></td></tr>\n", r);
ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r); ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
if (wsel->s->status & PROXY_WORKER_DISABLED) if (wsel->s->status & PROXY_WORKER_DISABLED)
ap_rputs(" checked", r); ap_rputs(" checked", r);
ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r); ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r);
if (!(wsel->s->status & PROXY_WORKER_DISABLED)) if (!(wsel->s->status & PROXY_WORKER_DISABLED))
ap_rputs(" checked", r); ap_rputs(" checked", r);
ap_rputs("></td><tr>\n", r); ap_rputs("></td></tr>\n", r);
ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r); ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
ap_rvputs(r, "</table>\n<input type=hidden name=\"w\" ", NULL); ap_rvputs(r, "</table>\n<input type=hidden name=\"w\" ", NULL);
ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL); ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL);
@@ -867,37 +878,48 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
proxy_worker *mycandidate = NULL; proxy_worker *mycandidate = NULL;
int checking_standby = 0; int checking_standby = 0;
int checked_standby = 0; int checked_standby = 0;
int cur_lbset = 0;
int max_lbset = 0;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: Entering byrequests for BALANCER (%s)", "proxy: Entering byrequests for BALANCER (%s)",
balancer->name); balancer->name);
/* First try to see if we have available candidate */ /* First try to see if we have available candidate */
while (!mycandidate && !checked_standby) { do {
worker = (proxy_worker *)balancer->workers->elts; while (!mycandidate && !checked_standby) {
for (i = 0; i < balancer->workers->nelts; i++, worker++) { worker = (proxy_worker *)balancer->workers->elts;
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) for (i = 0; i < balancer->workers->nelts; i++, worker++) {
continue; if (!checking_standby) { /* first time through */
/* If the worker is in error state run if (worker->s->lbset > max_lbset)
* retry on that worker. It will be marked as max_lbset = worker->s->lbset;
* operational if the retry timeout is elapsed. }
* The worker might still be unusable, but we try if (worker->s->lbset > cur_lbset)
* anyway. continue;
*/ if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
if (!PROXY_WORKER_IS_USABLE(worker)) continue;
ap_proxy_retry_worker("BALANCER", worker, r->server); /* If the worker is in error state run
/* Take into calculation only the workers that are * retry on that worker. It will be marked as
* not in error state or not disabled. * operational if the retry timeout is elapsed.
*/ * The worker might still be unusable, but we try
if (PROXY_WORKER_IS_USABLE(worker)) { * anyway.
worker->s->lbstatus += worker->s->lbfactor; */
total_factor += worker->s->lbfactor; if (!PROXY_WORKER_IS_USABLE(worker))
if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus) ap_proxy_retry_worker("BALANCER", worker, r->server);
mycandidate = worker; /* 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) { if (mycandidate) {
mycandidate->s->lbstatus -= total_factor; mycandidate->s->lbstatus -= total_factor;
@@ -934,39 +956,50 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
int checking_standby = 0; int checking_standby = 0;
int checked_standby = 0; int checked_standby = 0;
proxy_worker *mycandidate = NULL; proxy_worker *mycandidate = NULL;
int cur_lbset = 0;
int max_lbset = 0;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: Entering bytraffic for BALANCER (%s)", "proxy: Entering bytraffic for BALANCER (%s)",
balancer->name); balancer->name);
/* First try to see if we have available candidate */ /* First try to see if we have available candidate */
while (!mycandidate && !checked_standby) { do {
worker = (proxy_worker *)balancer->workers->elts; while (!mycandidate && !checked_standby) {
for (i = 0; i < balancer->workers->nelts; i++, worker++) { worker = (proxy_worker *)balancer->workers->elts;
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) for (i = 0; i < balancer->workers->nelts; i++, worker++) {
continue; if (!checking_standby) { /* first time through */
/* If the worker is in error state run if (worker->s->lbset > max_lbset)
* retry on that worker. It will be marked as max_lbset = worker->s->lbset;
* operational if the retry timeout is elapsed. }
* The worker might still be unusable, but we try if (worker->s->lbset > cur_lbset)
* anyway. continue;
*/ if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
if (!PROXY_WORKER_IS_USABLE(worker)) continue;
ap_proxy_retry_worker("BALANCER", worker, r->server); /* If the worker is in error state run
/* Take into calculation only the workers that are * retry on that worker. It will be marked as
* not in error state or not disabled. * operational if the retry timeout is elapsed.
*/ * The worker might still be unusable, but we try
if (PROXY_WORKER_IS_USABLE(worker)) { * anyway.
mytraffic = (worker->s->transferred/worker->s->lbfactor) + */
(worker->s->read/worker->s->lbfactor); if (!PROXY_WORKER_IS_USABLE(worker))
if (!mycandidate || mytraffic < curmin) { ap_proxy_retry_worker("BALANCER", worker, r->server);
mycandidate = worker; /* Take into calculation only the workers that are
curmin = mytraffic; * 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) { if (mycandidate) {
mycandidate->s->elected++; mycandidate->s->elected++;