Commit 5d047caa authored by Jim Jagielski's avatar Jim Jagielski
Browse files

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


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@686805 13f79535-47bb-0310-9956-ffa450edef68
parent 42a8d33b
Loading
Loading
Loading
Loading
+3 −2
Changes for docs/manual/mod/mod_proxy.xml: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -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>
+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>
+102 −0
Changes for modules/proxy/mod_proxy_balancer.c: 102 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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 = {