mod_proxy_balancer.c

来自「linux网络服务器工具」· C语言 代码 · 共 1,123 行 · 第 1/3 页

C
1,123
字号
    const char *path = NULL;    if (scheme)        path = ap_strchr_c(scheme + 3, '/');    /* we break the URL into host, port, uri */    if (!worker) {        return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,                             "missing worker. URI cannot be parsed: ", *url,                             NULL));    }    *url = apr_pstrcat(r->pool, worker->name, path, NULL);    return OK;}static int proxy_balancer_pre_request(proxy_worker **worker,                                      proxy_balancer **balancer,                                      request_rec *r,                                      proxy_server_conf *conf, char **url){    int access_status;    proxy_worker *runtime;    char *route = NULL;    char *sticky = NULL;    apr_status_t rv;    *worker = NULL;    /* Step 1: check if the url is for us     * The url we can handle starts with 'balancer://'     * If balancer is already provided skip the search     * for balancer, because this is failover attempt.     */    if (!*balancer &&        !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url)))        return DECLINED;    /* Step 2: find the session route */    runtime = find_session_route(*balancer, r, &route, &sticky, url);    /* Lock the LoadBalancer     * XXX: perhaps we need the process lock here     */    if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,                     "proxy: BALANCER: (%s). Lock failed for pre_request",                     (*balancer)->name);        return DECLINED;    }    if (runtime) {        int i, total_factor = 0;        proxy_worker *workers;        /* We have a sticky load balancer         * Update the workers status         * so that even session routes get         * into account.         */        workers = (proxy_worker *)(*balancer)->workers->elts;        for (i = 0; i < (*balancer)->workers->nelts; i++) {            /* Take into calculation only the workers that are             * not in error state or not disabled.             *             * TODO: Abstract the below, since this is dependent             *       on the LB implementation             */            if (PROXY_WORKER_IS_USABLE(workers)) {                workers->s->lbstatus += workers->s->lbfactor;                total_factor += workers->s->lbfactor;            }            workers++;        }        runtime->s->lbstatus -= total_factor;        runtime->s->elected++;        *worker = runtime;    }    else if (route && (*balancer)->sticky_force) {        int i, member_of = 0;        proxy_worker *workers;        /*         * We have a route provided that doesn't match the         * balancer name. See if the provider route is the         * member of the same balancer in which case return 503         */        workers = (proxy_worker *)(*balancer)->workers->elts;        for (i = 0; i < (*balancer)->workers->nelts; i++) {            if (*(workers->s->route) && strcmp(workers->s->route, route) == 0) {                member_of = 1;                break;            }            workers++;        }        if (member_of) {            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,                         "proxy: BALANCER: (%s). All workers are in error state for route (%s)",                         (*balancer)->name, route);            if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) {                ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,                             "proxy: BALANCER: (%s). Unlock failed for pre_request",                             (*balancer)->name);            }            return HTTP_SERVICE_UNAVAILABLE;        }    }    if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,                     "proxy: BALANCER: (%s). Unlock failed for pre_request",                     (*balancer)->name);    }    if (!*worker) {        runtime = find_best_worker(*balancer, r);        if (!runtime) {            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,                         "proxy: BALANCER: (%s). All workers are in error state",                         (*balancer)->name);            return HTTP_SERVICE_UNAVAILABLE;        }        if ((*balancer)->sticky && runtime) {            /*             * This balancer has sticky sessions and the client either has not             * supplied any routing information or all workers for this route             * including possible redirect and hotstandby workers are in error             * state, but we have found another working worker for this             * balancer where we can send the request. Thus notice that we have             * changed the route to the backend.             */            apr_table_setn(r->subprocess_env, "BALANCER_ROUTE_CHANGED", "1");        }        *worker = runtime;    }    /* Add balancer/worker info to env. */    apr_table_setn(r->subprocess_env,                   "BALANCER_NAME", (*balancer)->name);    apr_table_setn(r->subprocess_env,                   "BALANCER_WORKER_NAME", (*worker)->name);    apr_table_setn(r->subprocess_env,                   "BALANCER_WORKER_ROUTE", (*worker)->s->route);    /* Rewrite the url from 'balancer://url'     * to the 'worker_scheme://worker_hostname[:worker_port]/url'     * This replaces the balancers fictional name with the     * real hostname of the elected worker.     */    access_status = rewrite_url(r, *worker, url);    /* Add the session route to request notes if present */    if (route) {        apr_table_setn(r->notes, "session-sticky", sticky);        apr_table_setn(r->notes, "session-route", route);        /* Add session info to env. */        apr_table_setn(r->subprocess_env,                       "BALANCER_SESSION_STICKY", sticky);        apr_table_setn(r->subprocess_env,                       "BALANCER_SESSION_ROUTE", route);    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                 "proxy: BALANCER (%s) worker (%s) rewritten to %s",                 (*balancer)->name, (*worker)->name, *url);    return access_status;}static int proxy_balancer_post_request(proxy_worker *worker,                                       proxy_balancer *balancer,                                       request_rec *r,                                       proxy_server_conf *conf){#if 0    apr_status_t rv;    if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,            "proxy: BALANCER: (%s). Lock failed for post_request",            balancer->name);        return HTTP_INTERNAL_SERVER_ERROR;    }    /* TODO: placeholder for post_request actions     */    if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,            "proxy: BALANCER: (%s). Unlock failed for post_request",            balancer->name);    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                 "proxy_balancer_post_request for (%s)", balancer->name);#endif    return OK;}static void recalc_factors(proxy_balancer *balancer){    int i;    proxy_worker *workers;    /* Recalculate lbfactors */    workers = (proxy_worker *)balancer->workers->elts;    /* Special case if there is only one worker it's     * load factor will always be 1     */    if (balancer->workers->nelts == 1) {        workers->s->lbstatus = workers->s->lbfactor = 1;        return;    }    for (i = 0; i < balancer->workers->nelts; i++) {        /* Update the status entries */        workers[i].s->lbstatus = workers[i].s->lbfactor;    }}/* post_config hook: */static int balancer_init(apr_pool_t *p, apr_pool_t *plog,                         apr_pool_t *ptemp, server_rec *s){    void *data;    const char *userdata_key = "mod_proxy_balancer_init";    apr_uuid_t uuid;    /* balancer_init() will be called twice during startup.  So, only     * set up the static data the second time through. */    apr_pool_userdata_get(&data, userdata_key, s->process->pool);    if (!data) {        apr_pool_userdata_set((const void *)1, userdata_key,                               apr_pool_cleanup_null, s->process->pool);        return OK;    }    /* Retrieve a UUID and store the nonce for the lifetime of     * the process. */    apr_uuid_get(&uuid);    apr_uuid_format(balancer_nonce, &uuid);    return OK;}/* Manages the loadfactors and member status */static int balancer_handler(request_rec *r){    void *sconf = r->server->module_config;    proxy_server_conf *conf = (proxy_server_conf *)        ap_get_module_config(sconf, &proxy_module);    proxy_balancer *balancer, *bsel = NULL;    proxy_worker *worker, *wsel = NULL;    apr_table_t *params = apr_table_make(r->pool, 10);    int access_status;    int i, n;    const char *name;    /* is this for us? */    if (strcmp(r->handler, "balancer-manager"))        return DECLINED;    r->allowed = (AP_METHOD_BIT << M_GET);    if (r->method_number != M_GET)        return DECLINED;    if (r->args) {        char *args = apr_pstrdup(r->pool, r->args);        char *tok, *val;        while (args && *args) {            if ((val = ap_strchr(args, '='))) {                *val++ = '\0';                if ((tok = ap_strchr(val, '&')))                    *tok++ = '\0';                /*                 * Special case: workers are allowed path information                 */                if ((access_status = ap_unescape_url(val)) != OK)                    if (strcmp(args, "w") || (access_status !=  HTTP_NOT_FOUND))                        return access_status;                apr_table_setn(params, args, val);                args = tok;            }            else                return HTTP_BAD_REQUEST;        }    }        /* Check that the supplied nonce matches this server's nonce;     * otherwise ignore all parameters, to prevent a CSRF attack. */    if ((name = apr_table_get(params, "nonce")) == NULL         || strcmp(balancer_nonce, name) != 0) {        apr_table_clear(params);    }    if ((name = apr_table_get(params, "b")))        bsel = ap_proxy_get_balancer(r->pool, conf,            apr_pstrcat(r->pool, "balancer://", name, NULL));    if ((name = apr_table_get(params, "w"))) {        proxy_worker *ws;        ws = ap_proxy_get_worker(r->pool, conf, name);        if (bsel && ws) {            worker = (proxy_worker *)bsel->workers->elts;            for (n = 0; n < bsel->workers->nelts; n++) {                if (strcasecmp(worker->name, ws->name) == 0) {                    wsel = worker;                    break;                }                ++worker;            }        }    }    /* First set the params */    /*     * Note that it is not possible set the proxy_balancer because it is not     * in shared memory.     */    if (wsel) {        const char *val;        if ((val = apr_table_get(params, "lf"))) {            int ival = atoi(val);            if (ival >= 1 && ival <= 100) {                wsel->s->lbfactor = ival;                if (bsel)                    recalc_factors(bsel);            }        }        if ((val = apr_table_get(params, "wr"))) {            if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)                strcpy(wsel->s->route, val);            else                *wsel->s->route = '\0';        }        if ((val = apr_table_get(params, "rr"))) {            if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)                strcpy(wsel->s->redirect, val);            else                *wsel->s->redirect = '\0';        }        if ((val = apr_table_get(params, "dw"))) {            if (!strcasecmp(val, "Disable"))                wsel->s->status |= PROXY_WORKER_DISABLED;            else if (!strcasecmp(val, "Enable"))                wsel->s->status &= ~PROXY_WORKER_DISABLED;        }        if ((val = apr_table_get(params, "ls"))) {            int ival = atoi(val);            if (ival >= 0 && ival <= 99) {                wsel->s->lbset = ival;             }        }    }    if (apr_table_get(params, "xml")) {        ap_set_content_type(r, "text/xml");        ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", r);        ap_rputs("<httpd:manager xmlns:httpd=\"http://httpd.apache.org\">\n", r);        ap_rputs("  <httpd:balancers>\n", r);        balancer = (proxy_balancer *)conf->balancers->elts;        for (i = 0; i < conf->balancers->nelts; i++) {            ap_rputs("    <httpd:balancer>\n", r);            ap_rvputs(r, "      <httpd:name>", balancer->name, "</httpd:name>\n", NULL);            ap_rputs("      <httpd:workers>\n", r);            worker = (proxy_worker *)balancer->workers->elts;            for (n = 0; n < balancer->workers->nelts; n++) {                ap_rputs("        <httpd:worker>\n", r);                ap_rvputs(r, "          <httpd:scheme>", worker->scheme,                          "</httpd:scheme>\n", NULL);                ap_rvputs(r, "          <httpd:hostname>", worker->hostname,                          "</httpd:hostname>\n", NULL);               ap_rprintf(r, "          <httpd:loadfactor>%d</httpd:loadfactor>\n",                          worker->s->lbfactor);                ap_rputs("        </httpd:worker>\n", r);                ++worker;            }            ap_rputs("      </httpd:workers>\n", r);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?