From 7bc35044c7ec1149240c38868ae4ab762d7f9851 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 8 Apr 2016 22:35:45 +0900 Subject: [PATCH] nghttpx: Add --backend-fall and --backend-rise options These options are analogous to fall and rise parameter found in haproxy. --- gennghttpxfun.py | 2 ++ src/shrpx.cc | 28 ++++++++++++++++++++++++++++ src/shrpx_config.cc | 14 ++++++++++++++ src/shrpx_config.h | 4 ++++ src/shrpx_live_check.cc | 4 +++- src/shrpx_worker.cc | 13 +++++++++++-- 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 03eec22d..3049d8aa 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -129,6 +129,8 @@ OPTIONS = [ "backend-tls", "backend-connections-per-host", "error-page", + "backend-fall", + "backend-rise", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 3c32776b..87240223 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1314,6 +1314,24 @@ Connections: --backend-write-timeout options. --accept-proxy-protocol Accept PROXY protocol version 1 on frontend connection. + --backend-fall= + If nghttpx cannot connect to a specific backend + times in a row, that backend is assumed to be offline, + and it is excluded from load balancing. See also + --backend-rise option. If is 0, a backend never be + excluded from load balancing whatever times nghttpx + cannot connect to it. + Default: )" << get_config()->conn.downstream.fall << R"( + --backend-rise= + As described in --backend-fall, a backend is excluded + from load balancing if nghttpx assumes that it is + offline. Then nghttpx periodically attempts to make a + connection to the failed backend, and if the connection + is made successfully times in a row, the backend is + assumed to be online, and it is now eligible for load + balancing target. If is 0, a backend is permanently + offline, once it goes in that state. + Default: )" << get_config()->conn.downstream.rise << R"( Performance: -n, --workers= @@ -2519,6 +2537,8 @@ int main(int argc, char **argv) { {SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST.c_str(), required_argument, &flag, 121}, {SHRPX_OPT_ERROR_PAGE.c_str(), required_argument, &flag, 122}, + {SHRPX_OPT_BACKEND_FALL.c_str(), required_argument, &flag, 123}, + {SHRPX_OPT_BACKEND_RISE.c_str(), required_argument, &flag, 124}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3094,6 +3114,14 @@ int main(int argc, char **argv) { // --error-page cmdcfgs.emplace_back(SHRPX_OPT_ERROR_PAGE, StringRef{optarg}); break; + case 123: + // --backend-fall + cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_FALL, StringRef{optarg}); + break; + case 124: + // --backend-rise + cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_RISE, StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 1bb0266f..b718da52 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -893,6 +893,7 @@ enum { SHRPX_OPTID_BACKEND_ADDRESS_FAMILY, SHRPX_OPTID_BACKEND_CONNECTIONS_PER_FRONTEND, SHRPX_OPTID_BACKEND_CONNECTIONS_PER_HOST, + SHRPX_OPTID_BACKEND_FALL, SHRPX_OPTID_BACKEND_HTTP_PROXY_URI, SHRPX_OPTID_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND, SHRPX_OPTID_BACKEND_HTTP1_CONNECTIONS_PER_HOST, @@ -908,6 +909,7 @@ enum { SHRPX_OPTID_BACKEND_READ_TIMEOUT, SHRPX_OPTID_BACKEND_REQUEST_BUFFER, SHRPX_OPTID_BACKEND_RESPONSE_BUFFER, + SHRPX_OPTID_BACKEND_RISE, SHRPX_OPTID_BACKEND_TLS, SHRPX_OPTID_BACKEND_TLS_SNI_FIELD, SHRPX_OPTID_BACKEND_WRITE_TIMEOUT, @@ -1187,6 +1189,9 @@ int option_lookup_token(const char *name, size_t namelen) { } break; case 'e': + if (util::strieq_l("backend-ris", name, 11)) { + return SHRPX_OPTID_BACKEND_RISE; + } if (util::strieq_l("host-rewrit", name, 11)) { return SHRPX_OPTID_HOST_REWRITE; } @@ -1194,6 +1199,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_HTTP2_BRIDGE; } break; + case 'l': + if (util::strieq_l("backend-fal", name, 11)) { + return SHRPX_OPTID_BACKEND_FALL; + } + break; case 'y': if (util::strieq_l("client-prox", name, 11)) { return SHRPX_OPTID_CLIENT_PROXY; @@ -2672,6 +2682,10 @@ int parse_config(const StringRef &opt, const StringRef &optarg, opt, optarg); case SHRPX_OPTID_ERROR_PAGE: return parse_error_page(mod_config()->http.error_pages, opt, optarg); + case SHRPX_OPTID_BACKEND_FALL: + return parse_uint(&mod_config()->conn.downstream.fall, opt, optarg); + case SHRPX_OPTID_BACKEND_RISE: + return parse_uint(&mod_config()->conn.downstream.rise, opt, optarg); case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 9f285688..d2e662d3 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -275,6 +275,8 @@ constexpr auto SHRPX_OPT_BACKEND_TLS = StringRef::from_lit("backend-tls"); constexpr auto SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST = StringRef::from_lit("backend-connections-per-host"); constexpr auto SHRPX_OPT_ERROR_PAGE = StringRef::from_lit("error-page"); +constexpr auto SHRPX_OPT_BACKEND_FALL = StringRef::from_lit("backend-fall"); +constexpr auto SHRPX_OPT_BACKEND_RISE = StringRef::from_lit("backend-rise"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -615,6 +617,8 @@ struct ConnectionConfig { size_t connections_per_frontend; size_t request_buffer_size; size_t response_buffer_size; + size_t fall; + size_t rise; // Address family of backend connection. One of either AF_INET, // AF_INET6 or AF_UNSPEC. This is ignored if backend connection // is made via Unix domain socket. diff --git a/src/shrpx_live_check.cc b/src/shrpx_live_check.cc index 2cf22619..3c10577c 100644 --- a/src/shrpx_live_check.cc +++ b/src/shrpx_live_check.cc @@ -294,7 +294,9 @@ void LiveCheck::on_success() { LOG(WARN) << "Liveness check for " << util::to_numeric_addr(&addr_->addr) << " succeeded " << success_count_ << " time(s) in a row"; - if (success_count_ < 3) { + auto &downstreamconf = get_config()->conn.downstream; + + if (success_count_ < downstreamconf.rise) { disconnect(); schedule(); diff --git a/src/shrpx_worker.cc b/src/shrpx_worker.cc index c354d1aa..827ef52f 100644 --- a/src/shrpx_worker.cc +++ b/src/shrpx_worker.cc @@ -475,12 +475,21 @@ void downstream_failure(DownstreamAddr *addr) { auto fail_count = connect_blocker->get_fail_count(); - if (fail_count >= 3) { + auto &downstreamconf = get_config()->conn.downstream; + + if (downstreamconf.fall == 0) { + return; + } + + if (fail_count >= downstreamconf.fall) { LOG(WARN) << "Could not connect to " << util::to_numeric_addr(&addr->addr) << " " << fail_count << " times in a row; considered as offline"; connect_blocker->offline(); - addr->live_check->schedule(); + + if (downstreamconf.rise) { + addr->live_check->schedule(); + } } }