📄 mod_proxy_balancer.c
字号:
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, "proxy: BALANCER: (%s). Lock failed for find_best_worker()", balancer->name); return NULL; } candidate = (*balancer->lbmethod->finder)(balancer, r); if (candidate) candidate->s->elected++;/* PROXY_THREAD_UNLOCK(balancer); return NULL;*/ if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, "proxy: BALANCER: (%s). Unlock failed for find_best_worker()", balancer->name); } if (candidate == NULL) { /* All the workers are in error state or disabled. * If the balancer has a timeout sleep for a while * and try again to find the worker. The chances are * that some other thread will release a connection. * By default the timeout is not set, and the server * returns SERVER_BUSY. */#if APR_HAS_THREADS if (balancer->timeout) { /* XXX: This can perhaps be build using some * smarter mechanism, like tread_cond. * But since the statuses can came from * different childs, use the provided algo. */ apr_interval_time_t timeout = balancer->timeout; apr_interval_time_t step, tval = 0; /* Set the timeout to 0 so that we don't * end in infinite loop */ balancer->timeout = 0; step = timeout / 100; while (tval < timeout) { apr_sleep(step); /* Try again */ if ((candidate = find_best_worker(balancer, r))) break; tval += step; } /* restore the timeout */ balancer->timeout = timeout; }#endif } return candidate;}static int rewrite_url(request_rec *r, proxy_worker *worker, char **url){ const char *scheme = strstr(*url, "://"); 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 void force_recovery(proxy_balancer *balancer, server_rec *s){ int i; int ok = 0; proxy_worker *worker; worker = (proxy_worker *)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { if (!(worker->s->status & PROXY_WORKER_IN_ERROR)) { ok = 1; break; } } if (!ok) { /* If all workers are in error state force the recovery. */ worker = (proxy_worker *)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { ++worker->s->retries; worker->s->status &= ~PROXY_WORKER_IN_ERROR; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: BALANCER: (%s). Forcing recovery for worker (%s)", balancer->name, worker->hostname); } }}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: 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; } /* Step 3: force recovery */ force_recovery(*balancer, r->server); /* Step 4: find the session route */ runtime = find_session_route(*balancer, r, &route, &sticky, url); 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; } (*worker)->s->busy++; /* 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 if (worker && worker->s->busy) worker->s->busy--; 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: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -