]> granicus.if.org Git - apache/commitdiff
Add in bybusyness LB method, via Joel Gluth in
authorJim Jagielski <jim@apache.org>
Mon, 18 Aug 2008 15:59:48 +0000 (15:59 +0000)
committerJim Jagielski <jim@apache.org>
Mon, 18 Aug 2008 15:59:48 +0000 (15:59 +0000)
   https://issues.apache.org/bugzilla/show_bug.cgi?id=45501

NOTE: Name changed and added in to ease enhancement/bugfixes

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@686805 13f79535-47bb-0310-9956-ffa450edef68

docs/manual/mod/mod_proxy.xml
docs/manual/mod/mod_proxy_balancer.xml
modules/proxy/mod_proxy_balancer.c

index f1ec76d7134708670d83e3ba99340cc90043d64b..a87567b715291a52d060cff97615331366c22330 100644 (file)
@@ -818,8 +818,9 @@ expressions</description>
         <td>byrequests</td>
         <td>Balancer load-balance method. Select the load-balancing scheduler
         method to use. Either <code>byrequests</code>, to perform weighted
-        request counting or <code>bytraffic</code>, to perform weighted
-        traffic byte count balancing. Default is <code>byrequests</code>.
+        request counting, <code>bytraffic</code>, to perform weighted
+        traffic byte count balancing, or <code>bybusyness</code>, to perform 
+        pending request balancing. Default is <code>byrequests</code>.
     </td></tr>
     <tr><td>maxattempts</td>
         <td>1</td>
index 925dbd2409ab0017d0fc6417a5e0590f682f0adb..1097f71d8190c8779fd693d0222581a78dcde870 100644 (file)
 
 <section id="scheduler">
     <title>Load balancer scheduler algorithm</title>
-    <p>At present, there are 2 load balancer scheduler algorithms available
-    for use: Request Counting and Weighted Traffic Counting. These are controlled
-    via the <code>lbmethod</code> value of the Balancer definition. See
-    the <directive module="mod_proxy">ProxyPass</directive> directive for
-    more information.</p>
+    <p>At present, there are 3 load balancer scheduler algorithms available
+    for use: Request Counting, Weighted Traffic Counting and Pending Request 
+    Counting. These are controlled via the <code>lbmethod</code> value of
+    the Balancer definition. See the <directive module="mod_proxy">ProxyPass</directive> 
+    directive for more information.</p>
 
 </section>
 
@@ -287,6 +287,25 @@ candidate lbstatus -= total factor</code></pre>
 
 </section>
 
+<section id="busyness">
+
+    <title>Pending Request Counting Algorithm</title>
+
+    <p>Enabled via <code>lbmethod=bybusyness</code>, this scheduler keeps
+    track of how many requests each worker is assigned at present. A new
+    request is automatically assigned to the worker with the lowest
+    number of active requests. This is useful in the case of workers
+    that queue incoming requests independently of Apache, to ensure that
+    queue length stays even and a request is always given to the worker
+    most likely to service it fastest.</p>
+
+    <p>In the case of multiple least-busy workers, the statistics (and
+    weightings) used by the Request Counting method are used to break the
+    tie. Over time, the distribution of work will come to resemble that
+    characteristic of <code>byrequests</code>.</p>
+
+</section>
+
 <section id="environment">
     <title>Exported Environment Variables</title>
     <p>At present there are 6 environment variables exported:</p>
index 7b65db9931800641582fe3faa9fd167d08a6b9f8..a03650764d45114654b6680e405dfc1fbb0a9a95 100644 (file)
@@ -367,7 +367,9 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer,
         }
 #endif
     }
+
     return candidate;
+
 }
 
 static int rewrite_url(request_rec *r, proxy_worker *worker,
@@ -538,6 +540,8 @@ static int proxy_balancer_pre_request(proxy_worker **worker,
         *worker = runtime;
     }
 
+    (*worker)->s->busy++;
+
     /* Add balancer/worker info to env. */
     apr_table_setn(r->subprocess_env,
                    "BALANCER_NAME", (*balancer)->name);
@@ -598,7 +602,11 @@ static int proxy_balancer_post_request(proxy_worker *worker,
 
 #endif
 
+    if (worker && worker->s->busy)
+        worker->s->busy--;
+
     return OK;
+
 }
 
 static void recalc_factors(proxy_balancer *balancer)
@@ -1111,6 +1119,91 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
     return mycandidate;
 }
 
+static proxy_worker *find_best_bybusyness(proxy_balancer *balancer,
+                                request_rec *r)
+{
+
+    int i;
+    proxy_worker *worker;
+    proxy_worker *mycandidate = NULL;
+    int cur_lbset = 0;
+    int max_lbset = 0;
+    int checking_standby;
+    int checked_standby;
+
+    int total_factor = 0;
+    
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: Entering bybusyness for BALANCER (%s)",
+                 balancer->name);
+
+    /* First try to see if we have available candidate */
+    do {
+
+        checking_standby = checked_standby = 0;
+        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->busy < mycandidate->s->busy
+                        || (worker->s->busy == mycandidate->s->busy && worker->s->lbstatus > mycandidate->s->lbstatus))
+                        mycandidate = worker;
+
+                }
+
+            }
+
+            checked_standby = checking_standby++;
+
+        }
+
+        cur_lbset++;
+
+    } while (cur_lbset <= max_lbset && !mycandidate);
+
+    if (mycandidate) {
+
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: selected worker \"%s\" by busy factor %i (request lbstatus %i)",
+                     mycandidate->name, mycandidate->s->busy, mycandidate->s->lbstatus);
+
+        mycandidate->s->lbstatus -= total_factor;
+
+    }
+
+    return mycandidate;
+
+}
+
 /*
  * How to add additional lbmethods:
  *   1. Create func which determines "best" candidate worker
@@ -1131,6 +1224,14 @@ static const proxy_balancer_method bytraffic =
     NULL
 };
 
+static const proxy_balancer_method bybusyness =
+{
+    "bybusyness",
+    &find_best_bybusyness,
+    NULL
+};
+
+
 static void ap_proxy_balancer_register_hook(apr_pool_t *p)
 {
     /* Only the mpm_winnt has child init hook handler.
@@ -1147,6 +1248,7 @@ static void ap_proxy_balancer_register_hook(apr_pool_t *p)
     proxy_hook_canon_handler(proxy_balancer_canon, NULL, NULL, APR_HOOK_FIRST);
     ap_register_provider(p, PROXY_LBMETHOD, "bytraffic", "0", &bytraffic);
     ap_register_provider(p, PROXY_LBMETHOD, "byrequests", "0", &byrequests);
+    ap_register_provider(p, PROXY_LBMETHOD, "bybusyness", "0", &bybusyness);
 }
 
 module AP_MODULE_DECLARE_DATA proxy_balancer_module = {