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

simple, functional interface to add additional balancer lb selection methods

without requiring code changes to mod_proxy/mod_proxy_balancer;
these can be implemented via sub-modules now.

Let the games begin...


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@232282 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jim Jagielski
2005-08-12 12:47:04 +00:00
parent 5d7d8f280f
commit a7d488a6d2
5 changed files with 134 additions and 57 deletions

View File

@@ -1,6 +1,11 @@
-*- coding: utf-8 -*- -*- coding: utf-8 -*-
Changes with Apache 2.3.0 Changes with Apache 2.3.0
*) mod_proxy/mod_proxy_balancer: Provide a simple, functional
interface to add additional balancer lb selection methods
without requiring code changes to mod_proxy/mod_proxy_balancer;
these can be implemented via sub-modules now. [Jim Jagielski]
*) mod_cache: Fix incorrectly served 304 responses when expired cache *) mod_cache: Fix incorrectly served 304 responses when expired cache
entity is valid, but cache is unwritable and headers cannot be entity is valid, but cache is unwritable and headers cannot be
updated. [Colm MacCarthaigh <colm stdlib.net>] updated. [Colm MacCarthaigh <colm stdlib.net>]

View File

@@ -224,7 +224,8 @@ static const char *set_worker_param(apr_pool_t *p,
return NULL; return NULL;
} }
static const char *set_balancer_param(apr_pool_t *p, static const char *set_balancer_param(proxy_server_conf *conf,
apr_pool_t *p,
proxy_balancer *balancer, proxy_balancer *balancer,
const char *key, const char *key,
const char *val) const char *val)
@@ -272,13 +273,17 @@ static const char *set_balancer_param(apr_pool_t *p,
balancer->max_attempts_set = 1; balancer->max_attempts_set = 1;
} }
else if (!strcasecmp(key, "lbmethod")) { else if (!strcasecmp(key, "lbmethod")) {
/* Which LB scheduler method */ struct proxy_balancer_method *ent =
if (!strcasecmp(val, "traffic")) (struct proxy_balancer_method *) conf->lbmethods->elts;
balancer->lbmethod = lbmethod_traffic; int i;
else if (!strcasecmp(val, "requests")) for (i = 0; i < conf->lbmethods->nelts; i++) {
balancer->lbmethod = lbmethod_requests; if (!strcasecmp(val, ent->name)) {
else balancer->lbmethod = ent;
return "lbmethod must be Traffic|Requests"; return NULL;
}
ent++;
}
return "unknown lbmethod";
} }
else { else {
return "unknown Balancer parameter"; return "unknown Balancer parameter";
@@ -793,6 +798,7 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s)
ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int)); ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
ps->workers = apr_array_make(p, 10, sizeof(proxy_worker)); ps->workers = apr_array_make(p, 10, sizeof(proxy_worker));
ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer)); ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer));
ps->lbmethods = apr_array_make(p, 10, sizeof(proxy_balancer_method));
ps->forward = NULL; ps->forward = NULL;
ps->reverse = NULL; ps->reverse = NULL;
ps->domain = NULL; ps->domain = NULL;
@@ -815,6 +821,9 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s)
ps->badopt = bad_error; ps->badopt = bad_error;
ps->badopt_set = 0; ps->badopt_set = 0;
ps->pool = p; ps->pool = p;
proxy_run_load_lbmethods(ps);
return ps; return ps;
} }
@@ -832,6 +841,7 @@ static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv)
ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports); ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
ps->workers = apr_array_append(p, base->workers, overrides->workers); ps->workers = apr_array_append(p, base->workers, overrides->workers);
ps->balancers = apr_array_append(p, base->balancers, overrides->balancers); ps->balancers = apr_array_append(p, base->balancers, overrides->balancers);
ps->lbmethods = apr_array_append(p, base->lbmethods, overrides->lbmethods);
ps->forward = overrides->forward ? overrides->forward : base->forward; ps->forward = overrides->forward ? overrides->forward : base->forward;
ps->reverse = overrides->reverse ? overrides->reverse : base->reverse; ps->reverse = overrides->reverse ? overrides->reverse : base->reverse;
@@ -1021,7 +1031,7 @@ static const char *
return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL); return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
} }
for (i = 0; i < arr->nelts; i++) { for (i = 0; i < arr->nelts; i++) {
const char *err = set_balancer_param(cmd->pool, balancer, elts[i].key, const char *err = set_balancer_param(conf, cmd->pool, balancer, elts[i].key,
elts[i].val); elts[i].val);
if (err) if (err)
return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL); return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
@@ -1509,7 +1519,7 @@ static const char *
if (worker) if (worker)
err = set_worker_param(cmd->pool, worker, word, val); err = set_worker_param(cmd->pool, worker, word, val);
else else
err = set_balancer_param(cmd->pool, balancer, word, val); err = set_balancer_param(conf, cmd->pool, balancer, word, val);
if (err) if (err)
return apr_pstrcat(cmd->temp_pool, "ProxySet ", err, " ", word, " ", name, NULL); return apr_pstrcat(cmd->temp_pool, "ProxySet ", err, " ", word, " ", name, NULL);
@@ -1754,9 +1764,7 @@ static int proxy_status_hook(request_rec *r, int flags)
ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>", ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
apr_time_sec(balancer->timeout)); apr_time_sec(balancer->timeout));
ap_rprintf(r, "<td>%s</td>\n", ap_rprintf(r, "<td>%s</td>\n",
balancer->lbmethod == lbmethod_requests ? "Requests" : balancer->lbmethod->name);
balancer->lbmethod == lbmethod_traffic ? "Traffic" :
"Unknown");
ap_rputs("</table>\n", r); ap_rputs("</table>\n", r);
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>"
@@ -1917,6 +1925,7 @@ APR_HOOK_STRUCT(
APR_HOOK_LINK(canon_handler) APR_HOOK_LINK(canon_handler)
APR_HOOK_LINK(pre_request) APR_HOOK_LINK(pre_request)
APR_HOOK_LINK(post_request) APR_HOOK_LINK(post_request)
APR_HOOK_LINK(load_lbmethods)
APR_HOOK_LINK(request_status) APR_HOOK_LINK(request_status)
) )
@@ -1942,6 +1951,10 @@ APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, post_request,
request_rec *r, request_rec *r,
proxy_server_conf *conf),(worker, proxy_server_conf *conf),(worker,
balancer,r,conf),DECLINED) balancer,r,conf),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(proxy, PROXY, int, load_lbmethods,
(proxy_server_conf *conf),
(conf),
OK, DECLINED)
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups, APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups,
(request_rec *r), (r), (request_rec *r), (r),
OK, DECLINED) OK, DECLINED)

View File

@@ -120,6 +120,7 @@ struct noproxy_entry {
typedef struct proxy_balancer proxy_balancer; typedef struct proxy_balancer proxy_balancer;
typedef struct proxy_worker proxy_worker; typedef struct proxy_worker proxy_worker;
typedef struct proxy_conn_pool proxy_conn_pool; typedef struct proxy_conn_pool proxy_conn_pool;
typedef struct proxy_balancer_method proxy_balancer_method;
typedef struct { typedef struct {
apr_array_header_t *proxies; apr_array_header_t *proxies;
@@ -179,6 +180,7 @@ typedef struct {
} proxy_status; /* Status display options */ } proxy_status; /* Status display options */
char proxy_status_set; char proxy_status_set;
apr_pool_t *pool; /* Pool used for allocating this struct */ apr_pool_t *pool; /* Pool used for allocating this struct */
apr_array_header_t *lbmethods;
} proxy_server_conf; } proxy_server_conf;
@@ -257,6 +259,7 @@ typedef struct {
apr_size_t elected; /* Number of times the worker was elected */ apr_size_t elected; /* Number of times the worker was elected */
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 */
} proxy_worker_stat; } proxy_worker_stat;
/* Worker configuration */ /* Worker configuration */
@@ -293,6 +296,7 @@ struct proxy_worker {
#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 */
}; };
struct proxy_balancer { struct proxy_balancer {
@@ -303,10 +307,7 @@ struct proxy_balancer {
apr_interval_time_t timeout; /* Timeout for waiting on free connection */ apr_interval_time_t timeout; /* Timeout for waiting on free connection */
int max_attempts; /* Number of attempts before failing */ int max_attempts; /* Number of attempts before failing */
char max_attempts_set; char max_attempts_set;
enum { proxy_balancer_method *lbmethod;
lbmethod_requests = 1,
lbmethod_traffic = 2
} lbmethod;
/* XXX: Perhaps we will need the proc mutex too. /* XXX: Perhaps we will need the proc mutex too.
* Altrough we are only using arithmetic operations * Altrough we are only using arithmetic operations
@@ -316,6 +317,14 @@ struct proxy_balancer {
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_t *mutex; /* Thread lock for updating lb params */ apr_thread_mutex_t *mutex; /* Thread lock for updating lb params */
#endif #endif
void *context; /* general purpose storage */
};
struct proxy_balancer_method {
const char *name; /* name of the load balancer method*/
proxy_worker *(*finder)(proxy_balancer *balancer,
request_rec *r);
void *context; /* general purpose storage */
}; };
#if APR_HAS_THREADS #if APR_HAS_THREADS
@@ -365,6 +374,14 @@ APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, canon_handler, (request_rec *r,
APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr)) APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr))
APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r)) APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r))
/*
* Useful hook run within the create per-server phase which
* adds the required lbmethod structs, so they exist at
* configure time
*/
APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, load_lbmethods,
(proxy_server_conf *conf))
/** /**
* pre request hook. * pre request hook.
* It will return the most suitable worker at the moment * It will return the most suitable worker at the moment

View File

@@ -21,6 +21,7 @@
#include "mod_proxy.h" #include "mod_proxy.h"
#include "ap_mpm.h" #include "ap_mpm.h"
#include "apr_version.h" #include "apr_version.h"
#include "apr_hooks.h"
module AP_MODULE_DECLARE_DATA proxy_balancer_module; module AP_MODULE_DECLARE_DATA proxy_balancer_module;
@@ -262,13 +263,14 @@ static proxy_worker *find_session_route(proxy_balancer *balancer,
* b a d c d a c d b d ... * b a d c d a c d b d ...
* *
*/ */
static proxy_worker *find_best_byrequests(proxy_balancer *balancer, static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
request_rec *r) request_rec *r)
{ {
int i; int i;
int total_factor = 0; int total_factor = 0;
proxy_worker *worker = (proxy_worker *)balancer->workers->elts; proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
proxy_worker *candidate = NULL; proxy_worker *mycandidate = NULL;
/* First try to see if we have available candidate */ /* First try to see if we have available candidate */
for (i = 0; i < balancer->workers->nelts; i++) { for (i = 0; i < balancer->workers->nelts; i++) {
@@ -286,18 +288,18 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
if (PROXY_WORKER_IS_USABLE(worker)) { if (PROXY_WORKER_IS_USABLE(worker)) {
worker->s->lbstatus += worker->s->lbfactor; worker->s->lbstatus += worker->s->lbfactor;
total_factor += worker->s->lbfactor; total_factor += worker->s->lbfactor;
if (!candidate || worker->s->lbstatus > candidate->s->lbstatus) if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus)
candidate = worker; mycandidate = worker;
} }
worker++; worker++;
} }
if (candidate) { if (mycandidate) {
candidate->s->lbstatus -= total_factor; mycandidate->s->lbstatus -= total_factor;
candidate->s->elected++; mycandidate->s->elected++;
} }
return candidate; return mycandidate;
} }
/* /*
@@ -324,7 +326,7 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
apr_off_t mytraffic = 0; apr_off_t mytraffic = 0;
apr_off_t curmin = 0; apr_off_t curmin = 0;
proxy_worker *worker = (proxy_worker *)balancer->workers->elts; proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
proxy_worker *candidate = NULL; proxy_worker *mycandidate = NULL;
/* First try to see if we have available candidate */ /* First try to see if we have available candidate */
for (i = 0; i < balancer->workers->nelts; i++) { for (i = 0; i < balancer->workers->nelts; i++) {
@@ -342,19 +344,19 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
if (PROXY_WORKER_IS_USABLE(worker)) { if (PROXY_WORKER_IS_USABLE(worker)) {
mytraffic = (worker->s->transferred/worker->s->lbfactor) + mytraffic = (worker->s->transferred/worker->s->lbfactor) +
(worker->s->read/worker->s->lbfactor); (worker->s->read/worker->s->lbfactor);
if (!candidate || mytraffic < curmin) { if (!mycandidate || mytraffic < curmin) {
candidate = worker; mycandidate = worker;
curmin = mytraffic; curmin = mytraffic;
} }
} }
worker++; worker++;
} }
if (candidate) { if (mycandidate) {
candidate->s->elected++; mycandidate->s->elected++;
} }
return candidate; return mycandidate;
} }
static proxy_worker *find_best_worker(proxy_balancer *balancer, static proxy_worker *find_best_worker(proxy_balancer *balancer,
@@ -365,14 +367,12 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer,
if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS) if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS)
return NULL; return NULL;
if (balancer->lbmethod == lbmethod_requests) { candidate = (*balancer->lbmethod->finder)(balancer, r);
candidate = find_best_byrequests(balancer, r);
} else if (balancer->lbmethod == lbmethod_traffic) { /*
candidate = find_best_bytraffic(balancer, r);
} else {
PROXY_THREAD_UNLOCK(balancer); PROXY_THREAD_UNLOCK(balancer);
return NULL; return NULL;
} */
PROXY_THREAD_UNLOCK(balancer); PROXY_THREAD_UNLOCK(balancer);
@@ -657,19 +657,16 @@ static int balancer_handler(request_rec *r)
bsel->max_attempts_set = 1; bsel->max_attempts_set = 1;
} }
if ((val = apr_table_get(params, "lm"))) { if ((val = apr_table_get(params, "lm"))) {
int ival = atoi(val); struct proxy_balancer_method *ent =
switch(ival) { (struct proxy_balancer_method *) conf->lbmethods->elts;
case 0: int i;
break; for (i = 0; i < conf->lbmethods->nelts; i++) {
case lbmethod_traffic: if (!strcasecmp(val, ent->name)) {
bsel->lbmethod = lbmethod_traffic; bsel->lbmethod = ent;
break;
case lbmethod_requests:
bsel->lbmethod = lbmethod_requests;
break;
default:
break; break;
} }
ent++;
}
} }
} }
if (wsel) { if (wsel) {
@@ -755,8 +752,7 @@ static int balancer_handler(request_rec *r)
apr_time_sec(balancer->timeout)); apr_time_sec(balancer->timeout));
ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts); ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts);
ap_rprintf(r, "<td>%s</td>\n", ap_rprintf(r, "<td>%s</td>\n",
balancer->lbmethod == lbmethod_requests ? "Requests" : balancer->lbmethod->name);
balancer->lbmethod == lbmethod_traffic ? "Traffic" : "Unknown");
ap_rputs("</table>\n", r); ap_rputs("</table>\n", r);
ap_rputs("\n\n<table border=\"0\"><tr>" ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>Scheme</th><th>Host</th>" "<th>Scheme</th><th>Host</th>"
@@ -834,10 +830,17 @@ static int balancer_handler(request_rec *r)
ap_rprintf(r, "value=\"%d\"></td></tr>\n", ap_rprintf(r, "value=\"%d\"></td></tr>\n",
bsel->max_attempts); bsel->max_attempts);
ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r); ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r);
ap_rprintf(r, "<option value=\"%d\" %s>Requests</option>", lbmethod_requests, {
bsel->lbmethod == lbmethod_requests ? "selected" : ""); struct proxy_balancer_method *ent =
ap_rprintf(r, "<option value=\"%d\" %s>Traffic</option>", lbmethod_traffic, (struct proxy_balancer_method *) conf->lbmethods->elts;
bsel->lbmethod == lbmethod_traffic ? "selected" : ""); int i;
for (i = 0; i < conf->lbmethods->nelts; i++) {
ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", ent->name,
(!strcasecmp(bsel->lbmethod->name, ent->name)) ? "selected" : "",
ent->name);
ent++;
}
}
ap_rputs("</select></td></tr>\n", r); ap_rputs("</select></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=\"b\" ", NULL); ap_rvputs(r, "</table>\n<input type=hidden name=\"b\" ", NULL);
@@ -871,6 +874,30 @@ static void child_init(apr_pool_t *p, server_rec *s)
} }
/*
* How to add additional lbmethods:
* 1. Create func which determines "best" candidate worker
* (eg: find_best_bytraffic, above)
* 2. Create proxy_balancer_method struct which
* defines the method and add it to
* available server methods using
* the proxy_hook_load_lbmethods hook
* (eg: add_lbmethods below).
*/
static int add_lbmethods(proxy_server_conf *conf)
{
proxy_balancer_method *new;
new = apr_array_push(conf->lbmethods);
new->name = "byrequests";
new->finder = find_best_byrequests;
new = apr_array_push(conf->lbmethods);
new->name = "bytraffic";
new->finder = find_best_bytraffic;
return OK;
}
static void ap_proxy_balancer_register_hook(apr_pool_t *p) static void ap_proxy_balancer_register_hook(apr_pool_t *p)
{ {
/* Only the mpm_winnt has child init hook handler. /* Only the mpm_winnt has child init hook handler.
@@ -884,6 +911,7 @@ static void ap_proxy_balancer_register_hook(apr_pool_t *p)
proxy_hook_pre_request(proxy_balancer_pre_request, NULL, NULL, APR_HOOK_FIRST); proxy_hook_pre_request(proxy_balancer_pre_request, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_post_request(proxy_balancer_post_request, NULL, NULL, APR_HOOK_FIRST); proxy_hook_post_request(proxy_balancer_post_request, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(proxy_balancer_canon, NULL, NULL, APR_HOOK_FIRST); proxy_hook_canon_handler(proxy_balancer_canon, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_load_lbmethods(add_lbmethods, NULL, NULL, APR_HOOK_FIRST);
} }
module AP_MODULE_DECLARE_DATA proxy_balancer_module = { module AP_MODULE_DECLARE_DATA proxy_balancer_module = {

View File

@@ -1155,6 +1155,8 @@ PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
const char *url) const char *url)
{ {
char *c, *q, *uri = apr_pstrdup(p, url); char *c, *q, *uri = apr_pstrdup(p, url);
int i;
proxy_balancer_method *lbmethod;
c = strchr(uri, ':'); c = strchr(uri, ':');
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
@@ -1167,8 +1169,20 @@ PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
*balancer = apr_array_push(conf->balancers); *balancer = apr_array_push(conf->balancers);
memset(*balancer, 0, sizeof(proxy_balancer)); memset(*balancer, 0, sizeof(proxy_balancer));
/*
* NOTE: The default method is byrequests, which we assume
* exists!
*/
lbmethod = (proxy_balancer_method *)conf->lbmethods->elts;
for (i = 0; i < conf->lbmethods->nelts; i++) {
if (!strcasecmp(lbmethod->name, "byrequests")) {
break;
}
lbmethod++;
}
(*balancer)->name = uri; (*balancer)->name = uri;
(*balancer)->lbmethod = lbmethod_requests; (*balancer)->lbmethod = lbmethod;
(*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker)); (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker));
/* XXX Is this a right place to create mutex */ /* XXX Is this a right place to create mutex */
#if APR_HAS_THREADS #if APR_HAS_THREADS