Commit fd40a2da authored by Jim Jagielski's avatar Jim Jagielski
Browse files

Merge r1828890, r1832500 from trunk:

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.


mod_proxy_balancer: follow up to r1828890: indentation and 80 col.


Submitted by: jhriggs, ylavic
Reviewed by: jhriggs, jim, ylavic


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1832609 13f79535-47bb-0310-9956-ffa450edef68
parent 19988bcf
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
                                                         -*- coding: utf-8 -*-
Changes with Apache 2.4.34

  *) 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]

  *) suexec: Add --enable-suexec-capabilites support on Linux, to use
     setuid/setgid capability bits rather than a setuid root binary.
     [Joe Orton]
@@ -5789,4 +5794,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
+0 −9
Original line number Diff line number Diff line
@@ -155,15 +155,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
     jailletc36: There should be a compatibility note for the new directives.
                 (done in r1828478)

  *) 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.
     trunk patch: https://svn.apache.org/r1828890
     2.4.x patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/hot-spare-2.4.patch
     +1: jhriggs, jim
     ylavic: +1 with r1832500.


PATCHES PROPOSED TO BACKPORT FROM TRUNK:
  [ New proposals should be added at the end of the list ]

+40 −14
Original line number Diff line number Diff line
@@ -182,20 +182,41 @@ ProxyPassReverse "/images" "balancer://myset/"
    <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://myset/"
    </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 are always tried lowest number 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://myset/"
        <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>
+22 −2
Original line number Diff line number Diff line
@@ -1186,8 +1186,12 @@ ProxyPass "/mirror/foo/i" "!"
         <tr><td>D: Worker is disabled and will not accept any requests.</td></tr>
         <tr><td>S: Worker is administratively stopped.</td></tr>
         <tr><td>I: Worker is in ignore-errors mode and will always be considered available.</td></tr>
         <tr><td>R: 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>H: 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>E: Worker is in an error state.</td></tr>
         <tr><td>N: Worker is in drain mode and will only accept existing sticky sessions
                    destined for itself and ignore all other requests.</td></tr>
@@ -1342,8 +1346,24 @@ ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofail
&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;
+23 −86
Original line number Diff line number Diff line
@@ -22,99 +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;
        }
    }

    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;

                }

            }

            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);

    if (worker) {
        worker->s->lbstatus -= total_factor;
    }

    return mycandidate;
    return worker;
}

/* assumed to be mutex protected by caller */
Loading