From 9d16292fe4e1a782675c291e4719c7b443e390bf Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 20 Feb 2017 23:36:50 +0900 Subject: [PATCH] nghttpx: Add --frontend-max-requests option --- gennghttpxfun.py | 1 + src/shrpx.cc | 15 +++++++++++++++ src/shrpx_config.cc | 7 +++++++ src/shrpx_config.h | 4 ++++ src/shrpx_http2_upstream.cc | 38 +++++++++++++++++++++++++++---------- src/shrpx_http2_upstream.h | 6 ++++++ src/shrpx_https_upstream.cc | 37 ++++++++++++++++++++---------------- src/shrpx_https_upstream.h | 5 +++++ 8 files changed, 87 insertions(+), 26 deletions(-) diff --git a/gennghttpxfun.py b/gennghttpxfun.py index eaf6ce00..c55ee559 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -161,6 +161,7 @@ OPTIONS = [ "tls-min-proto-version", "tls-max-proto-version", "redirect-https-port", + "frontend-max-requests", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 82c23e6e..9abe597f 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1448,6 +1448,7 @@ void fill_default_config(Config *config) { httpconf.response_header_field_buffer = 64_k; httpconf.max_response_header_fields = 500; httpconf.redirect_https_port = StringRef::from_lit("443"); + httpconf.max_requests = std::numeric_limits::max(); auto &http2conf = config->http2; { @@ -2581,6 +2582,13 @@ DNS: lookup. Default: )" << config->dns.max_try << R"( + --frontend-max-requests= + The number of requests that single frontend connection + can process. For HTTP/2, this is the number of streams + in one HTTP/2 connection. For HTTP/1, this is the + number of keep alive requests. This is hint to nghttpx, + and it may allow additional few requests. The default + value is unlimited. Debug: --frontend-http2-dump-request-header= @@ -3266,6 +3274,8 @@ int main(int argc, char **argv) { {SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag, 153}, {SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154}, + {SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag, + 155}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3992,6 +4002,11 @@ int main(int argc, char **argv) { // --redirect-https-port cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg}); break; + case 155: + // --frontend-max-requests + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_MAX_REQUESTS, + StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index cfc8a773..260055ff 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -1817,6 +1817,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_TLS_TICKET_KEY_CIPHER; } break; + case 's': + if (util::strieq_l("frontend-max-request", name, 20)) { + return SHRPX_OPTID_FRONTEND_MAX_REQUESTS; + } + break; case 't': if (util::strieq_l("backend-write-timeou", name, 20)) { return SHRPX_OPTID_BACKEND_WRITE_TIMEOUT; @@ -3369,6 +3374,8 @@ int parse_config(Config *config, int optid, const StringRef &opt, config->http.redirect_https_port = optarg; return 0; } + case SHRPX_OPTID_FRONTEND_MAX_REQUESTS: + return parse_uint(&config->http.max_requests, opt, optarg); case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 79293441..3c949083 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -333,6 +333,8 @@ constexpr auto SHRPX_OPT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("tls-max-proto-version"); constexpr auto SHRPX_OPT_REDIRECT_HTTPS_PORT = StringRef::from_lit("redirect-https-port"); +constexpr auto SHRPX_OPT_FRONTEND_MAX_REQUESTS = + StringRef::from_lit("frontend-max-requests"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -647,6 +649,7 @@ struct HttpConfig { size_t max_request_header_fields; size_t response_header_field_buffer; size_t max_response_header_fields; + size_t max_requests; bool no_via; bool no_location_rewrite; bool no_host_rewrite; @@ -994,6 +997,7 @@ enum { SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS, SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE, SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT, + SHRPX_OPTID_FRONTEND_MAX_REQUESTS, SHRPX_OPTID_FRONTEND_NO_TLS, SHRPX_OPTID_FRONTEND_READ_TIMEOUT, SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT, diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index d6f1ec8f..ef591636 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -271,16 +271,21 @@ int on_begin_headers_callback(nghttp2_session *session, << frame->hd.stream_id; } - auto handler = upstream->get_client_handler(); + upstream->on_start_request(frame); - auto downstream = make_unique(upstream, handler->get_mcpool(), + return 0; +} +} // namespace + +void Http2Upstream::on_start_request(const nghttp2_frame *frame) { + auto downstream = make_unique(this, handler_->get_mcpool(), frame->hd.stream_id); - nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, + nghttp2_session_set_stream_user_data(session_, frame->hd.stream_id, downstream.get()); downstream->reset_upstream_rtimer(); - handler->repeat_read_timer(); + handler_->repeat_read_timer(); auto &req = downstream->request(); @@ -289,11 +294,16 @@ int on_begin_headers_callback(nghttp2_session *session, req.http_major = 2; req.http_minor = 0; - upstream->add_pending_downstream(std::move(downstream)); + add_pending_downstream(std::move(downstream)); - return 0; + ++num_requests_; + + auto config = get_config(); + auto &httpconf = config->http; + if (httpconf.max_requests <= num_requests_) { + start_graceful_shutdown(); + } } -} // namespace int Http2Upstream::on_request_headers(Downstream *downstream, const nghttp2_frame *frame) { @@ -873,8 +883,6 @@ void Http2Upstream::submit_goaway() { } void Http2Upstream::check_shutdown() { - int rv; - auto worker = handler_->get_worker(); if (!worker->get_graceful_shutdown()) { @@ -883,6 +891,15 @@ void Http2Upstream::check_shutdown() { ev_prepare_stop(handler_->get_loop(), &prep_); + start_graceful_shutdown(); +} + +void Http2Upstream::start_graceful_shutdown() { + int rv; + if (ev_is_active(&shutdown_timer_)) { + return; + } + rv = nghttp2_submit_shutdown_notice(session_); if (rv != 0) { ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: " @@ -965,7 +982,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) !get_config()->http2_proxy), handler_(handler), session_(nullptr), - max_buffer_size_(MAX_BUFFER_SIZE) { + max_buffer_size_(MAX_BUFFER_SIZE), + num_requests_(0) { int rv; auto config = get_config(); diff --git a/src/shrpx_http2_upstream.h b/src/shrpx_http2_upstream.h index 1f3408b0..739c6ffa 100644 --- a/src/shrpx_http2_upstream.h +++ b/src/shrpx_http2_upstream.h @@ -111,11 +111,15 @@ public: void submit_goaway(); void check_shutdown(); + // Starts graceful shutdown period. + void start_graceful_shutdown(); int prepare_push_promise(Downstream *downstream); int submit_push_promise(const StringRef &scheme, const StringRef &authority, const StringRef &path, Downstream *downstream); + // Called when new request has started. + void on_start_request(const nghttp2_frame *frame); int on_request_headers(Downstream *downstream, const nghttp2_frame *frame); DefaultMemchunks *get_response_buf(); @@ -134,6 +138,8 @@ private: ClientHandler *handler_; nghttp2_session *session_; size_t max_buffer_size_; + // The number of requests seen so far. + size_t num_requests_; bool flow_control_; }; diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index 7d7cb105..2f0bbf0b 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -52,7 +52,8 @@ namespace shrpx { HttpsUpstream::HttpsUpstream(ClientHandler *handler) : handler_(handler), current_header_length_(0), - ioctrl_(handler->get_rlimit()) { + ioctrl_(handler->get_rlimit()), + num_requests_(0) { http_parser_init(&htp_, HTTP_REQUEST); htp_.data = this; } @@ -63,27 +64,30 @@ void HttpsUpstream::reset_current_header_length() { current_header_length_ = 0; } -namespace { -int htp_msg_begin(http_parser *htp) { - auto upstream = static_cast(htp->data); +void HttpsUpstream::on_start_request() { if (LOG_ENABLED(INFO)) { - ULOG(INFO, upstream) << "HTTP request started"; + ULOG(INFO, this) << "HTTP request started"; } - upstream->reset_current_header_length(); + reset_current_header_length(); - auto handler = upstream->get_client_handler(); + auto downstream = make_unique(this, handler_->get_mcpool(), 0); - auto downstream = make_unique(upstream, handler->get_mcpool(), 0); + attach_downstream(std::move(downstream)); - upstream->attach_downstream(std::move(downstream)); - - auto conn = handler->get_connection(); + auto conn = handler_->get_connection(); auto &upstreamconf = get_config()->conn.upstream; conn->rt.repeat = upstreamconf.timeout.read; - handler->repeat_read_timer(); + handler_->repeat_read_timer(); + ++num_requests_; +} + +namespace { +int htp_msg_begin(http_parser *htp) { + auto upstream = static_cast(htp->data); + upstream->on_start_request(); return 0; } } // namespace @@ -868,12 +872,14 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body, auto &resp = downstream->response(); auto &balloc = downstream->get_block_allocator(); auto config = get_config(); + auto &httpconf = config->http; auto connection_close = false; auto worker = handler_->get_worker(); - if (worker->get_graceful_shutdown()) { + if (httpconf.max_requests <= num_requests_ && + worker->get_graceful_shutdown()) { resp.fs.add_header_token(StringRef::from_lit("connection"), StringRef::from_lit("close"), false, http2::HD_CONNECTION); @@ -917,8 +923,6 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body, output->append("\r\n"); } - auto &httpconf = config->http; - for (auto &p : httpconf.add_response_headers) { output->append(p.name); output->append(": "); @@ -1078,7 +1082,8 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) { // after graceful shutdown commenced, add connection: close header // field. - if (worker->get_graceful_shutdown()) { + if (httpconf.max_requests <= num_requests_ || + worker->get_graceful_shutdown()) { resp.connection_close = true; } diff --git a/src/shrpx_https_upstream.h b/src/shrpx_https_upstream.h index 79236355..8e83cea5 100644 --- a/src/shrpx_https_upstream.h +++ b/src/shrpx_https_upstream.h @@ -95,12 +95,17 @@ public: void log_response_headers(DefaultMemchunks *buf) const; int redirect_to_https(Downstream *downstream); + // Called when new request has started. + void on_start_request(); + private: ClientHandler *handler_; http_parser htp_; size_t current_header_length_; std::unique_ptr downstream_; IOControl ioctrl_; + // The number of requests seen so far. + size_t num_requests_; }; } // namespace shrpx