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 + -
显示快捷键?