Commit 36a8cb0b authored by Jim Jagielski's avatar Jim Jagielski
Browse files

Merge r686805, r687099 from trunk:

Add in bybusyness LB method, via Joel Gluth in
   https://issues.apache.org/bugzilla/show_bug.cgi?id=45501

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


Add in additional logging and use correct formats

Reviewed by: jim


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@696752 13f79535-47bb-0310-9956-ffa450edef68
parent 651ae89c
Loading
Loading
Loading
Loading
+3 −0
Changes for CHANGES: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -8,6 +8,9 @@ Changes with Apache 2.2.10
     mod_proxy_ftp: Prevent XSS attacks when using wildcards in the path of
     the FTP URL. Discovered by Marc Bevand of Rapid7. [Ruediger Pluem]

  *) mod_proxy_balancer: Add 'bybusyness' load balance method.
     [Joel Gluth <joelgluth yahoo.com.au>, Jim Jagielski]

  *) mod_authn_alias: Detect during startup when AuthDigestProvider
     is configured to use an incompatible provider via AuthnProviderAlias.
     PR 45196 [Eric Covener]
+0 −8
Changes for STATUS: 0 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -92,14 +92,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   http://svn.apache.org/viewvc?rev=639010&view=rev (mmn)
   +1: niq, rpluem, mturk

 * mod_proxy_balancer: Add in new bybusyness LB method.
    Trunk version of patch:
       http://svn.apache.org/viewvc?rev=686805&view=rev
       http://svn.apache.org/viewvc?rev=687099&view=rev
    Backport version for 2.2.x of patch:
       Trunk version of patch works
    +1: rpluem, jerenkrantz, jfclere


PATCHES PROPOSED TO BACKPORT FROM TRUNK:
  [ New proposals should be added at the end of the list ]
+3 −2
Changes for docs/manual/mod/mod_proxy.xml: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -816,8 +816,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>
+24 −5
Changes for docs/manual/mod/mod_proxy_balancer.xml: 24 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -50,11 +50,11 @@

<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>
+111 −0
Changes for modules/proxy/mod_proxy_balancer.c: 111 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -370,7 +370,9 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer,
        }
#endif
    }

    return candidate;

}

static int rewrite_url(request_rec *r, proxy_worker *worker,
@@ -511,6 +513,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);
@@ -571,7 +575,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)
@@ -997,6 +1005,10 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer,

    if (mycandidate) {
        mycandidate->s->lbstatus -= total_factor;
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                     "proxy: byrequests selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d",
                     mycandidate->name, mycandidate->s->busy, mycandidate->s->lbstatus);

    }

    return mycandidate;
@@ -1075,9 +1087,99 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
        cur_lbset++;
    } while (cur_lbset <= max_lbset && !mycandidate);

    if (mycandidate) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                     "proxy: bytraffic selected worker \"%s\" : busy %" APR_SIZE_T_FMT,
                     mycandidate->name, mycandidate->s->busy);

    }

    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) {
        mycandidate->s->lbstatus -= total_factor;
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                     "proxy: bybusyness selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d",
                     mycandidate->name, mycandidate->s->busy, mycandidate->s->lbstatus);

    }

    return mycandidate;

}

/*
 * How to add additional lbmethods:
 *   1. Create func which determines "best" candidate worker
@@ -1098,6 +1200,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.
@@ -1114,6 +1224,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 = {