httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jhri...@apache.org
Subject svn commit: r1828890 - in /httpd/httpd/trunk: ./ docs/log-message-tags/ docs/manual/howto/ docs/manual/mod/ modules/proxy/ modules/proxy/balancers/
Date Wed, 11 Apr 2018 12:11:05 GMT
Author: jhriggs
Date: Wed Apr 11 12:11:05 2018
New Revision: 1828890

URL: http://svn.apache.org/viewvc?rev=1828890&view=rev
Log:
mod_proxy_balancer: Add hot spare member type and corresponding flag (R). Hot spare members
are
used as drop-in replacements for unusable workers in the same load balancer set. This differs
from hot standbys which are only used when all workers in a set are unusable. PR 61140.

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/docs/manual/howto/reverse_proxy.xml
    httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
    httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bybusyness.c
    httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_byrequests.c
    httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bytraffic.c
    httpd/httpd/trunk/modules/proxy/mod_proxy.c
    httpd/httpd/trunk/modules/proxy/mod_proxy.h
    httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c
    httpd/httpd/trunk/modules/proxy/proxy_util.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Wed Apr 11 12:11:05 2018
@@ -1,6 +1,11 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) mod_proxy_balancer: Add hot spare member type and corresponding flag (R). Hot spare
members are
+     used as drop-in replacements for unusable workers in the same load balancer set. This
differs
+     from hot standbys which are only used when all workers in a set are unusable. PR 61140.
[Jim
+     Riggs]
+
   *) mod_logio: Add LogIOTrackTTFU and %^FU logformat to log the time
      difference between request start and last request body byte read (finished upload).
      [Rainer Jung]
@@ -637,4 +642,3 @@ Changes with Apache 2.2.x and later:
 Changes with Apache 2.0.x and later:
 
   *) http://svn.apache.org/viewvc/httpd/httpd/branches/2.0.x/CHANGES?view=markup
-

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Wed Apr 11 12:11:05 2018
@@ -1 +1 @@
-10122
+10124

Modified: httpd/httpd/trunk/docs/manual/howto/reverse_proxy.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/howto/reverse_proxy.xml?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/howto/reverse_proxy.xml (original)
+++ httpd/httpd/trunk/docs/manual/howto/reverse_proxy.xml Wed Apr 11 12:11:05 2018
@@ -182,20 +182,41 @@ ProxyPassReverse "/images"  "balancer://
     <title>Failover</title>
 
     <p>
-      You can also fine-tune various failover scenarios, detailing which
-      workers and even which balancers should accessed in such cases. For
-      example, the below setup implements 2 failover cases: In the first,
-      <code>http://hstandby.example.com:8080</code> is only sent traffic
-      if all other workers in the <em>myset</em> balancer are not available.
-      If that worker itself is not available, only then will the
-      <code>http://bkup1.example.com:8080</code> and <code>http://bkup2.example.com:8080</code>
-      workers be brought into rotation:
+      You can also fine-tune various failover scenarios, detailing which workers
+      and even which balancers should be accessed in such cases. For example, the
+      below setup implements three failover cases:
+    </p>
+    <ol>
+      <li>
+        <code>http://spare1.example.com:8080</code> and
+        <code>http://spare2.example.com:8080</code> are only sent traffic if
one
+        or both of <code>http://www2.example.com:8080</code> or
+        <code>http://www3.example.com:8080</code> is unavailable. (One spare
+        will be used to replace one unusable member of the same balancer set.)
+      </li>
+      <li>
+        <code>http://hstandby.example.com:8080</code> is only sent traffic if
+        all other workers in balancer set <code>0</code> are not available.
+      </li>
+      <li>
+        If all load balancer set <code>0</code> workers, spares, and the standby
+        are unavailable, only then will the
+        <code>http://bkup1.example.com:8080</code> and
+        <code>http://bkup2.example.com:8080</code> workers from balancer set
+        <code>1</code> be brought into rotation.
+      </li>
+    </ol>
+    <p>
+      Thus, it is possible to have one or more hot spares and hot standbys for
+      each load balancer set.
     </p>
 
     <highlight language="config">
 &lt;Proxy balancer://myset&gt;
     BalancerMember http://www2.example.com:8080
     BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
+    BalancerMember http://spare1.example.com:8080 status=+R
+    BalancerMember http://spare2.example.com:8080 status=+R
     BalancerMember http://hstandby.example.com:8080 status=+H
     BalancerMember http://bkup1.example.com:8080 lbset=1
     BalancerMember http://bkup2.example.com:8080 lbset=1
@@ -207,11 +228,12 @@ ProxyPassReverse "/images/"  "balancer:/
     </highlight>
 
     <p>
-      The magic of this failover setup is setting <code>http://hstandby.example.com:8080</code>
-      with the <code>+H</code> status flag, which puts it in <em>hot standby</em>
mode,
-      and making the 2 <code>bkup#</code> servers part of the #1 load balancer
set (the
-      default set is 0); for failover, hot standbys (if they exist) are used 1st, when all
regular
-      workers are unavailable; load balancer sets with lowest number are always tried first.
+      For failover, hot spares are used as replacements for unusable workers in
+      the same load balancer set. A worker is considered unusable if it is
+      draining, stopped, or otherwise in an error/failed state. Hot standbys are
+      used if all workers and spares in the load balancer set are
+      unavailable. Load balancer sets (with their respective hot spares and
+      standbys) are always tried in order from lowest to highest.
     </p>
 
   </section>
@@ -301,8 +323,12 @@ ProxyPassReverse "/images/"  "balancer:/
         <tr><td><code>S</code></td><td><em>Stop</em></td><td>Worker
is administratively stopped; will not accept requests
                     and will not be automatically retried</td></tr>
         <tr><td><code>I</code></td><td><em>Ign</em></td><td>Worker
is in ignore-errors mode and will always be considered available.</td></tr>
+        <tr><td><code>R</code></td><td><em>Spar</em></td><td>Worker
is a hot spare. For each worker in a given lbset that is unusable
+                    (draining, stopped, in error, etc.), a usable hot spare with the same
lbset will be used in
+                    its place. Hot spares can help ensure that a specific number of workers
are always available
+                    for use by a balancer.</td></tr>
         <tr><td><code>H</code></td><td><em>Stby</em></td><td>Worker
is in hot-standby mode and will only be used if no other
-                    viable workers are available.</td></tr>
+                    viable workers or spares are available in the balancer set.</td></tr>
         <tr><td><code>E</code></td><td><em>Err</em></td><td>Worker
is in an error state, usually due to failing pre-request check;
                     requests will not be proxied to this worker, but it will be retried depending
on
                     the <code>retry</code> setting of the worker.</td></tr>

Modified: httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml Wed Apr 11 12:11:05 2018
@@ -1217,8 +1217,12 @@ ProxyPass "/example" "http://backend.exa
          <tr><td><code>S</code></td><td>Worker is administratively
stopped; will not accept requests
                     and will not be automatically retried</td></tr>
          <tr><td><code>I</code></td><td>Worker is in
ignore-errors mode and will always be considered available.</td></tr>
+         <tr><td><code>R</code></td><td>Worker is a hot
spare. For each worker in a given lbset that is unusable
+                    (draining, stopped, in error, etc.), a usable hot spare with the same
lbset will be used in
+                    its place. Hot spares can help ensure that a specific number of workers
are always available
+                    for use by a balancer.</td></tr>
          <tr><td><code>H</code></td><td>Worker is in
hot-standby mode and will only be used if no other
-                    viable workers are available.</td></tr>
+                    viable workers or spares are available in the balancer set.</td></tr>
          <tr><td><code>E</code></td><td>Worker is in
an error state.</td></tr>
          <tr><td><code>N</code></td><td>Worker is in
drain mode and will only accept existing sticky sessions
                     destined for itself and ignore all other requests.</td></tr>
@@ -1374,8 +1378,24 @@ ProxyPass "/"             "balancer://my
 &lt;/Proxy&gt;
     </highlight>
 
+    <p>Configuring hot spares can help ensure that a certain number of
+    workers are always available for use per load balancer set:</p>
+    <highlight language="config">
+ProxyPass "/" "balancer://sparecluster/"
+&lt;Proxy balancer://sparecluster&gt;
+    BalancerMember ajp://1.2.3.4:8009
+    BalancerMember ajp://1.2.3.5:8009
+    # The servers below are hot spares. For each server above that is unusable
+    # (draining, stopped, unreachable, in error state, etc.), one of these spares
+    # will be used in its place. Two servers will always be available for a request
+    # unless one or more of the spares is also unusable.
+    BalancerMember ajp://1.2.3.6:8009 status=+R
+    BalancerMember ajp://1.2.3.7:8009 status=+R
+&lt;/Proxy&gt;
+    </highlight>
+
     <p>Setting up a hot-standby that will only be used if no other
-     members are available:</p>
+    members (or spares) are available in the load balancer set:</p>
     <highlight language="config">
 ProxyPass "/" "balancer://hotcluster/"
 &lt;Proxy balancer://hotcluster&gt;

Modified: httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bybusyness.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bybusyness.c?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bybusyness.c (original)
+++ httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bybusyness.c Wed Apr 11 12:11:05
2018
@@ -22,101 +22,36 @@
 
 module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module;
 
-static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
-        proxy_worker *worker, server_rec *s) = NULL;
+static int is_best_bybusyness(proxy_worker *current, proxy_worker *prev_best, void *baton)
+{
+    int *total_factor = (int *)baton;
+
+    current->s->lbstatus += current->s->lbfactor;
+    *total_factor += current->s->lbfactor;
+
+    return (
+        !prev_best
+        || (current->s->busy < prev_best->s->busy)
+        || (
+            (current->s->busy == prev_best->s->busy)
+            && (current->s->lbstatus > prev_best->s->lbstatus)
+        )
+    );
+}
 
 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;
+    proxy_worker *worker = ap_proxy_balancer_get_best_worker(balancer, r, is_best_bybusyness,
&total_factor);
 
-    if (!ap_proxy_retry_worker_fn) {
-        ap_proxy_retry_worker_fn =
-                APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
-        if (!ap_proxy_retry_worker_fn) {
-            /* can only happen if mod_proxy isn't loaded */
-            return NULL;
+    if (worker) {
+        worker->s->lbstatus -= total_factor;
         }
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01211)
-                 "proxy: Entering bybusyness for BALANCER (%s)",
-                 balancer->s->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) ||
-                    (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker))
||
-                    (PROXY_WORKER_IS_DRAINING(*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_fn("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;
 
+    return worker;
                 }
 
-            }
-
-            checked_standby = checking_standby++;
-
-        }
-
-        cur_lbset++;
-
-    } while (cur_lbset <= max_lbset && !mycandidate);
-
-    if (mycandidate) {
-        mycandidate->s->lbstatus -= total_factor;
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01212)
-                     "proxy: bybusyness selected worker \"%s\" : busy %" APR_SIZE_T_FMT "
: lbstatus %d",
-                     mycandidate->s->name, mycandidate->s->busy, mycandidate->s->lbstatus);
-
-    }
-
-    return mycandidate;
-}
-
 /* assumed to be mutex protected by caller */
 static apr_status_t reset(proxy_balancer *balancer, server_rec *s)
 {

Modified: httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_byrequests.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_byrequests.c?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_byrequests.c (original)
+++ httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_byrequests.c Wed Apr 11 12:11:05
2018
@@ -22,8 +22,15 @@
 
 module AP_MODULE_DECLARE_DATA lbmethod_byrequests_module;
 
-static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
-        proxy_worker *worker, server_rec *s) = NULL;
+static int is_best_byrequests(proxy_worker *current, proxy_worker *prev_best, void *baton)
+{
+    int *total_factor = (int *)baton;
+
+    current->s->lbstatus += current->s->lbfactor;
+    *total_factor += current->s->lbfactor;
+
+    return (!prev_best || (current->s->lbstatus > prev_best->s->lbstatus));
+}
 
 /*
  * The idea behind the find_best_byrequests scheduler is the following:
@@ -70,83 +77,18 @@ static int (*ap_proxy_retry_worker_fn)(c
  *   b a d c d a c d b d ...
  *
  */
-
 static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
                                 request_rec *r)
 {
-    int i;
     int total_factor = 0;
-    proxy_worker **worker;
-    proxy_worker *mycandidate = NULL;
-    int cur_lbset = 0;
-    int max_lbset = 0;
-    int checking_standby;
-    int checked_standby;
-
-    if (!ap_proxy_retry_worker_fn) {
-        ap_proxy_retry_worker_fn =
-                APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
-        if (!ap_proxy_retry_worker_fn) {
-            /* can only happen if mod_proxy isn't loaded */
-            return NULL;
-        }
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01207)
-                 "proxy: Entering byrequests for BALANCER (%s)",
-                 balancer->s->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) ||
-                    (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker))
||
-                    (PROXY_WORKER_IS_DRAINING(*worker))
-                    ) {
-                    continue;
-                }
+    proxy_worker *worker = ap_proxy_balancer_get_best_worker(balancer, r, is_best_byrequests,
&total_factor);
 
-                /* 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_fn("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++;
+    if (worker) {
+        worker->s->lbstatus -= total_factor;
         }
-        cur_lbset++;
-    } while (cur_lbset <= max_lbset && !mycandidate);
-
-    if (mycandidate) {
-        mycandidate->s->lbstatus -= total_factor;
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01208)
-                     "proxy: byrequests selected worker \"%s\" : busy %" APR_SIZE_T_FMT "
: lbstatus %d",
-                     mycandidate->s->name, mycandidate->s->busy, mycandidate->s->lbstatus);
 
-    }
-
-    return mycandidate;
-}
+    return worker;
+                }
 
 /* assumed to be mutex protected by caller */
 static apr_status_t reset(proxy_balancer *balancer, server_rec *s)

Modified: httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bytraffic.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bytraffic.c?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bytraffic.c (original)
+++ httpd/httpd/trunk/modules/proxy/balancers/mod_lbmethod_bytraffic.c Wed Apr 11 12:11:05
2018
@@ -22,8 +22,20 @@
 
 module AP_MODULE_DECLARE_DATA lbmethod_bytraffic_module;
 
-static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
-        proxy_worker *worker, server_rec *s) = NULL;
+static int is_best_bytraffic(proxy_worker *current, proxy_worker *prev_best, void *baton)
+{
+    apr_off_t *min_traffic = (apr_off_t *)baton;
+    apr_off_t traffic = (current->s->transferred / current->s->lbfactor)
+                        + (current->s->read / current->s->lbfactor);
+
+    if (!prev_best || (traffic < *min_traffic)) {
+        *min_traffic = traffic;
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
 
 /*
  * The idea behind the find_best_bytraffic scheduler is the following:
@@ -45,80 +57,10 @@ static int (*ap_proxy_retry_worker_fn)(c
 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 *mycandidate = NULL;
-    int cur_lbset = 0;
-    int max_lbset = 0;
-    int checking_standby;
-    int checked_standby;
-
-    if (!ap_proxy_retry_worker_fn) {
-        ap_proxy_retry_worker_fn =
-                APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
-        if (!ap_proxy_retry_worker_fn) {
-            /* can only happen if mod_proxy isn't loaded */
-            return NULL;
-        }
-    }
+    apr_off_t min_traffic = 0;
 
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01209)
-                 "proxy: Entering bytraffic for BALANCER (%s)",
-                 balancer->s->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) ||
-                    (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker))
||
-                    (PROXY_WORKER_IS_DRAINING(*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_fn("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++;
+    return ap_proxy_balancer_get_best_worker(balancer, r, is_best_bytraffic, &min_traffic);
         }
-        cur_lbset++;
-    } while (cur_lbset <= max_lbset && !mycandidate);
-
-    if (mycandidate) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01210)
-                     "proxy: bytraffic selected worker \"%s\" : busy %" APR_SIZE_T_FMT,
-                     mycandidate->s->name, mycandidate->s->busy);
-    }
-
-    return mycandidate;
-}
 
 /* assumed to be mutex protected by caller */
 static apr_status_t reset(proxy_balancer *balancer, server_rec *s)

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.c?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.c Wed Apr 11 12:11:05 2018
@@ -68,6 +68,7 @@ proxy_wstat_t PROXY_DECLARE_DATA proxy_w
     {PROXY_WORKER_STOPPED,       PROXY_WORKER_STOPPED_FLAG,       "Stop "},
     {PROXY_WORKER_IN_ERROR,      PROXY_WORKER_IN_ERROR_FLAG,      "Err "},
     {PROXY_WORKER_HOT_STANDBY,   PROXY_WORKER_HOT_STANDBY_FLAG,   "Stby "},
+    {PROXY_WORKER_HOT_SPARE,     PROXY_WORKER_HOT_SPARE_FLAG,     "Spar "},
     {PROXY_WORKER_FREE,          PROXY_WORKER_FREE_FLAG,          "Free "},
     {PROXY_WORKER_HC_FAIL,       PROXY_WORKER_HC_FAIL_FLAG,       "HcFl "},
     {0x0, '\0', NULL}
@@ -3123,4 +3124,3 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(prox
 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, detach_backend,
                                     (request_rec *r, proxy_conn_rec *backend),
                                     (r, backend), OK, DECLINED)
-

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.h?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.h Wed Apr 11 12:11:05 2018
@@ -307,6 +307,7 @@ struct proxy_conn_pool {
 #define PROXY_WORKER_HOT_STANDBY    0x0100
 #define PROXY_WORKER_FREE           0x0200
 #define PROXY_WORKER_HC_FAIL        0x0400
+#define PROXY_WORKER_HOT_SPARE      0x0800
 
 /* worker status flags */
 #define PROXY_WORKER_INITIALIZED_FLAG    'O'
@@ -320,6 +321,7 @@ struct proxy_conn_pool {
 #define PROXY_WORKER_HOT_STANDBY_FLAG    'H'
 #define PROXY_WORKER_FREE_FLAG           'F'
 #define PROXY_WORKER_HC_FAIL_FLAG        'C'
+#define PROXY_WORKER_HOT_SPARE_FLAG      'R'
 
 #define PROXY_WORKER_NOT_USABLE_BITMAP ( PROXY_WORKER_IN_SHUTDOWN | \
 PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR | \
@@ -330,6 +332,8 @@ PROXY_WORKER_HC_FAIL )
 
 #define PROXY_WORKER_IS_STANDBY(f)   ( (f)->s->status &  PROXY_WORKER_HOT_STANDBY
)
 
+#define PROXY_WORKER_IS_SPARE(f)   ( (f)->s->status &  PROXY_WORKER_HOT_SPARE )
+
 #define PROXY_WORKER_IS_USABLE(f)   ( ( !( (f)->s->status & PROXY_WORKER_NOT_USABLE_BITMAP)
) && \
   PROXY_WORKER_IS_INITIALIZED(f) )
 
@@ -858,6 +862,23 @@ PROXY_DECLARE(apr_status_t) ap_proxy_ini
                                                          server_rec *s,
                                                          apr_pool_t *p);
 
+typedef int (proxy_is_best_callback_fn_t)(proxy_worker *current, proxy_worker *prev_best,
void *baton);
+
+/**
+ * Retrieve the best worker in a balancer for the current request
+ * @param balancer balancer for which to find the best worker
+ * @param r        current request record
+ * @param is_best  a callback function provide by the lbmethod
+ *                 that determines if the current worker is best
+ * @param baton    an lbmethod-specific context pointer (baton)
+ *                 passed to the is_best callback
+ * @return         the best worker to be used for the request
+ */
+PROXY_DECLARE(proxy_worker *) ap_proxy_balancer_get_best_worker(proxy_balancer *balancer,
+                                                                request_rec *r,
+                                                                proxy_is_best_callback_fn_t
*is_best,
+                                                                void *baton);
+
 /**
  * Find the shm of the worker as needed
  * @param storage slotmem provider

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy_balancer.c Wed Apr 11 12:11:05 2018
@@ -1237,6 +1237,9 @@ static int balancer_handler(request_rec
         if ((val = apr_table_get(params, "w_status_H"))) {
             ap_proxy_set_wstatus(PROXY_WORKER_HOT_STANDBY_FLAG, atoi(val), wsel);
         }
+        if ((val = apr_table_get(params, "w_status_R"))) {
+            ap_proxy_set_wstatus(PROXY_WORKER_HOT_SPARE_FLAG, atoi(val), wsel);
+        }
         if ((val = apr_table_get(params, "w_status_S"))) {
             ap_proxy_set_wstatus(PROXY_WORKER_STOPPED_FLAG, atoi(val), wsel);
         }
@@ -1763,7 +1766,8 @@ static int balancer_handler(request_rec
                      "<th>Ignore Errors</th>"
                      "<th>Draining Mode</th>"
                      "<th>Disabled</th>"
-                     "<th>Hot Standby</th>", r);
+                     "<th>Hot Standby</th>"
+                     "<th>Hot Spare</th>", r);
             if (hc_show_exprs_f) {
                 ap_rputs("<th>HC Fail</th>", r);
             }
@@ -1772,6 +1776,7 @@ static int balancer_handler(request_rec
             create_radio("w_status_N", (PROXY_WORKER_IS(wsel, PROXY_WORKER_DRAIN)), r);
             create_radio("w_status_D", (PROXY_WORKER_IS(wsel, PROXY_WORKER_DISABLED)), r);
             create_radio("w_status_H", (PROXY_WORKER_IS(wsel, PROXY_WORKER_HOT_STANDBY)),
r);
+            create_radio("w_status_R", (PROXY_WORKER_IS(wsel, PROXY_WORKER_HOT_SPARE)), r);
             if (hc_show_exprs_f) {
                 create_radio("w_status_C", (PROXY_WORKER_IS(wsel, PROXY_WORKER_HC_FAIL)),
r);
             }

Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=1828890&r1=1828889&r2=1828890&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
+++ httpd/httpd/trunk/modules/proxy/proxy_util.c Wed Apr 11 12:11:05 2018
@@ -68,6 +68,7 @@ static int proxy_match_ipaddr(struct dir
 static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
 static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
 static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
+static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker, server_rec
*s);
 
 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
                                    (request_rec *r, request_rec *pr), (r, pr),
@@ -1293,6 +1294,121 @@ PROXY_DECLARE(apr_status_t) ap_proxy_ini
     return APR_SUCCESS;
 }
 
+PROXY_DECLARE(proxy_worker *) ap_proxy_balancer_get_best_worker(proxy_balancer *balancer,
+                                                                request_rec *r,
+                                                                proxy_is_best_callback_fn_t
*is_best,
+                                                                void *baton)
+{
+    int i = 0;
+    int cur_lbset = 0;
+    int max_lbset = 0;
+    int unusable_workers = 0;
+    apr_pool_t *tpool = NULL;
+    apr_array_header_t *spares = NULL;
+    apr_array_header_t *standbys = NULL;
+    proxy_worker *worker = NULL;
+    proxy_worker *best_worker = NULL;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(10122)
+                 "proxy: Entering %s for BALANCER (%s)",
+                 balancer->lbmethod->name, balancer->s->name);
+
+    apr_pool_create(&tpool, r->pool);
+
+    spares = apr_array_make(tpool, 1, sizeof(proxy_worker*));
+    standbys = apr_array_make(tpool, 1, sizeof(proxy_worker*));
+
+    /* Process lbsets in order, only replacing unusable workers in a given lbset
+     * with available spares from the same lbset. Hot standbys will be used as a
+     * last resort when all other workers and spares are unavailable.
+     */
+    for (cur_lbset = 0; !best_worker && (cur_lbset <= max_lbset); cur_lbset++)
{
+        unusable_workers = 0;
+        apr_array_clear(spares);
+        apr_array_clear(standbys);
+
+        for (i = 0; i < balancer->workers->nelts; i++) {
+            worker = APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
+
+            if (worker->s->lbset > max_lbset) {
+                max_lbset = worker->s->lbset;
+            }
+
+            if (worker->s->lbset != cur_lbset) {
+                continue;
+            }
+
+            /* A draining worker that is neither a spare nor a standby should be
+             * considered unusable to be replaced by spares.
+             */
+            if (PROXY_WORKER_IS_DRAINING(worker)) {
+                if (!PROXY_WORKER_IS_SPARE(worker) && !PROXY_WORKER_IS_STANDBY(worker))
{
+                    unusable_workers++;
+                }
+
+                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);
+            }
+
+            if (PROXY_WORKER_IS_SPARE(worker)) {
+                if (PROXY_WORKER_IS_USABLE(worker)) {
+                    APR_ARRAY_PUSH(spares, proxy_worker *) = worker;
+                }
+            }
+            else if (PROXY_WORKER_IS_STANDBY(worker)) {
+                if (PROXY_WORKER_IS_USABLE(worker)) {
+                    APR_ARRAY_PUSH(standbys, proxy_worker *) = worker;
+                }
+            }
+            else if (PROXY_WORKER_IS_USABLE(worker)) {
+              if (is_best(worker, best_worker, baton)) {
+                best_worker = worker;
+              }
+            }
+            else {
+                unusable_workers++;
+            }
+        }
+
+        /* Check if any spares are best. */
+        for (i = 0; (i < spares->nelts) && (i < unusable_workers); i++)
{
+          worker = APR_ARRAY_IDX(spares, i, proxy_worker *);
+
+          if (is_best(worker, best_worker, baton)) {
+            best_worker = worker;
+          }
+        }
+
+        /* If no workers are available, use the standbys. */
+        if (!best_worker) {
+            for (i = 0; i < standbys->nelts; i++) {
+              worker = APR_ARRAY_IDX(standbys, i, proxy_worker *);
+
+              if (is_best(worker, best_worker, baton)) {
+                best_worker = worker;
+              }
+            }
+        }
+    }
+
+    apr_pool_destroy(tpool);
+
+    if (best_worker) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(10123)
+                     "proxy: %s selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus
%d",
+                     balancer->lbmethod->name, best_worker->s->name, best_worker->s->busy,
best_worker->s->lbstatus);
+    }
+
+    return best_worker;
+}
+
 /*
  * CONNECTION related...
  */



Mime
View raw message