nghttpx: Add --frontend-max-requests option

This commit is contained in:
Tatsuhiro Tsujikawa 2017-02-20 23:36:50 +09:00
parent e2b9590c0f
commit 9d16292fe4
8 changed files with 87 additions and 26 deletions

View File

@ -161,6 +161,7 @@ OPTIONS = [
"tls-min-proto-version", "tls-min-proto-version",
"tls-max-proto-version", "tls-max-proto-version",
"redirect-https-port", "redirect-https-port",
"frontend-max-requests",
] ]
LOGVARS = [ LOGVARS = [

View File

@ -1448,6 +1448,7 @@ void fill_default_config(Config *config) {
httpconf.response_header_field_buffer = 64_k; httpconf.response_header_field_buffer = 64_k;
httpconf.max_response_header_fields = 500; httpconf.max_response_header_fields = 500;
httpconf.redirect_https_port = StringRef::from_lit("443"); httpconf.redirect_https_port = StringRef::from_lit("443");
httpconf.max_requests = std::numeric_limits<size_t>::max();
auto &http2conf = config->http2; auto &http2conf = config->http2;
{ {
@ -2581,6 +2582,13 @@ DNS:
lookup. lookup.
Default: )" Default: )"
<< config->dns.max_try << R"( << config->dns.max_try << R"(
--frontend-max-requests=<N>
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: Debug:
--frontend-http2-dump-request-header=<PATH> --frontend-http2-dump-request-header=<PATH>
@ -3266,6 +3274,8 @@ int main(int argc, char **argv) {
{SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag, {SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag,
153}, 153},
{SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154}, {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}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
@ -3992,6 +4002,11 @@ int main(int argc, char **argv) {
// --redirect-https-port // --redirect-https-port
cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg}); cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg});
break; break;
case 155:
// --frontend-max-requests
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_MAX_REQUESTS,
StringRef{optarg});
break;
default: default:
break; break;
} }

View File

@ -1817,6 +1817,11 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_TLS_TICKET_KEY_CIPHER; return SHRPX_OPTID_TLS_TICKET_KEY_CIPHER;
} }
break; break;
case 's':
if (util::strieq_l("frontend-max-request", name, 20)) {
return SHRPX_OPTID_FRONTEND_MAX_REQUESTS;
}
break;
case 't': case 't':
if (util::strieq_l("backend-write-timeou", name, 20)) { if (util::strieq_l("backend-write-timeou", name, 20)) {
return SHRPX_OPTID_BACKEND_WRITE_TIMEOUT; 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; config->http.redirect_https_port = optarg;
return 0; return 0;
} }
case SHRPX_OPTID_FRONTEND_MAX_REQUESTS:
return parse_uint(&config->http.max_requests, opt, optarg);
case SHRPX_OPTID_CONF: case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored"; LOG(WARN) << "conf: ignored";

View File

@ -333,6 +333,8 @@ constexpr auto SHRPX_OPT_TLS_MAX_PROTO_VERSION =
StringRef::from_lit("tls-max-proto-version"); StringRef::from_lit("tls-max-proto-version");
constexpr auto SHRPX_OPT_REDIRECT_HTTPS_PORT = constexpr auto SHRPX_OPT_REDIRECT_HTTPS_PORT =
StringRef::from_lit("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; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@ -647,6 +649,7 @@ struct HttpConfig {
size_t max_request_header_fields; size_t max_request_header_fields;
size_t response_header_field_buffer; size_t response_header_field_buffer;
size_t max_response_header_fields; size_t max_response_header_fields;
size_t max_requests;
bool no_via; bool no_via;
bool no_location_rewrite; bool no_location_rewrite;
bool no_host_rewrite; bool no_host_rewrite;
@ -994,6 +997,7 @@ enum {
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS, SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE, SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE,
SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT, SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT,
SHRPX_OPTID_FRONTEND_MAX_REQUESTS,
SHRPX_OPTID_FRONTEND_NO_TLS, SHRPX_OPTID_FRONTEND_NO_TLS,
SHRPX_OPTID_FRONTEND_READ_TIMEOUT, SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT, SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,

View File

@ -271,16 +271,21 @@ int on_begin_headers_callback(nghttp2_session *session,
<< frame->hd.stream_id; << frame->hd.stream_id;
} }
auto handler = upstream->get_client_handler(); upstream->on_start_request(frame);
auto downstream = make_unique<Downstream>(upstream, handler->get_mcpool(), return 0;
}
} // namespace
void Http2Upstream::on_start_request(const nghttp2_frame *frame) {
auto downstream = make_unique<Downstream>(this, handler_->get_mcpool(),
frame->hd.stream_id); 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.get());
downstream->reset_upstream_rtimer(); downstream->reset_upstream_rtimer();
handler->repeat_read_timer(); handler_->repeat_read_timer();
auto &req = downstream->request(); auto &req = downstream->request();
@ -289,11 +294,16 @@ int on_begin_headers_callback(nghttp2_session *session,
req.http_major = 2; req.http_major = 2;
req.http_minor = 0; 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, int Http2Upstream::on_request_headers(Downstream *downstream,
const nghttp2_frame *frame) { const nghttp2_frame *frame) {
@ -873,8 +883,6 @@ void Http2Upstream::submit_goaway() {
} }
void Http2Upstream::check_shutdown() { void Http2Upstream::check_shutdown() {
int rv;
auto worker = handler_->get_worker(); auto worker = handler_->get_worker();
if (!worker->get_graceful_shutdown()) { if (!worker->get_graceful_shutdown()) {
@ -883,6 +891,15 @@ void Http2Upstream::check_shutdown() {
ev_prepare_stop(handler_->get_loop(), &prep_); 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_); rv = nghttp2_submit_shutdown_notice(session_);
if (rv != 0) { if (rv != 0) {
ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: " ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: "
@ -965,7 +982,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
!get_config()->http2_proxy), !get_config()->http2_proxy),
handler_(handler), handler_(handler),
session_(nullptr), session_(nullptr),
max_buffer_size_(MAX_BUFFER_SIZE) { max_buffer_size_(MAX_BUFFER_SIZE),
num_requests_(0) {
int rv; int rv;
auto config = get_config(); auto config = get_config();

View File

@ -111,11 +111,15 @@ public:
void submit_goaway(); void submit_goaway();
void check_shutdown(); void check_shutdown();
// Starts graceful shutdown period.
void start_graceful_shutdown();
int prepare_push_promise(Downstream *downstream); int prepare_push_promise(Downstream *downstream);
int submit_push_promise(const StringRef &scheme, const StringRef &authority, int submit_push_promise(const StringRef &scheme, const StringRef &authority,
const StringRef &path, Downstream *downstream); 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); int on_request_headers(Downstream *downstream, const nghttp2_frame *frame);
DefaultMemchunks *get_response_buf(); DefaultMemchunks *get_response_buf();
@ -134,6 +138,8 @@ private:
ClientHandler *handler_; ClientHandler *handler_;
nghttp2_session *session_; nghttp2_session *session_;
size_t max_buffer_size_; size_t max_buffer_size_;
// The number of requests seen so far.
size_t num_requests_;
bool flow_control_; bool flow_control_;
}; };

View File

@ -52,7 +52,8 @@ namespace shrpx {
HttpsUpstream::HttpsUpstream(ClientHandler *handler) HttpsUpstream::HttpsUpstream(ClientHandler *handler)
: handler_(handler), : handler_(handler),
current_header_length_(0), current_header_length_(0),
ioctrl_(handler->get_rlimit()) { ioctrl_(handler->get_rlimit()),
num_requests_(0) {
http_parser_init(&htp_, HTTP_REQUEST); http_parser_init(&htp_, HTTP_REQUEST);
htp_.data = this; htp_.data = this;
} }
@ -63,27 +64,30 @@ void HttpsUpstream::reset_current_header_length() {
current_header_length_ = 0; current_header_length_ = 0;
} }
namespace { void HttpsUpstream::on_start_request() {
int htp_msg_begin(http_parser *htp) {
auto upstream = static_cast<HttpsUpstream *>(htp->data);
if (LOG_ENABLED(INFO)) { 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<Downstream>(this, handler_->get_mcpool(), 0);
auto downstream = make_unique<Downstream>(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; auto &upstreamconf = get_config()->conn.upstream;
conn->rt.repeat = upstreamconf.timeout.read; 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<HttpsUpstream *>(htp->data);
upstream->on_start_request();
return 0; return 0;
} }
} // namespace } // namespace
@ -868,12 +872,14 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
auto &resp = downstream->response(); auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator(); auto &balloc = downstream->get_block_allocator();
auto config = get_config(); auto config = get_config();
auto &httpconf = config->http;
auto connection_close = false; auto connection_close = false;
auto worker = handler_->get_worker(); 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"), resp.fs.add_header_token(StringRef::from_lit("connection"),
StringRef::from_lit("close"), false, StringRef::from_lit("close"), false,
http2::HD_CONNECTION); http2::HD_CONNECTION);
@ -917,8 +923,6 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
output->append("\r\n"); output->append("\r\n");
} }
auto &httpconf = config->http;
for (auto &p : httpconf.add_response_headers) { for (auto &p : httpconf.add_response_headers) {
output->append(p.name); output->append(p.name);
output->append(": "); output->append(": ");
@ -1078,7 +1082,8 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
// after graceful shutdown commenced, add connection: close header // after graceful shutdown commenced, add connection: close header
// field. // field.
if (worker->get_graceful_shutdown()) { if (httpconf.max_requests <= num_requests_ ||
worker->get_graceful_shutdown()) {
resp.connection_close = true; resp.connection_close = true;
} }

View File

@ -95,12 +95,17 @@ public:
void log_response_headers(DefaultMemchunks *buf) const; void log_response_headers(DefaultMemchunks *buf) const;
int redirect_to_https(Downstream *downstream); int redirect_to_https(Downstream *downstream);
// Called when new request has started.
void on_start_request();
private: private:
ClientHandler *handler_; ClientHandler *handler_;
http_parser htp_; http_parser htp_;
size_t current_header_length_; size_t current_header_length_;
std::unique_ptr<Downstream> downstream_; std::unique_ptr<Downstream> downstream_;
IOControl ioctrl_; IOControl ioctrl_;
// The number of requests seen so far.
size_t num_requests_;
}; };
} // namespace shrpx } // namespace shrpx