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-max-proto-version",
"redirect-https-port",
"frontend-max-requests",
]
LOGVARS = [

View File

@ -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<size_t>::max();
auto &http2conf = config->http2;
{
@ -2581,6 +2582,13 @@ DNS:
lookup.
Default: )"
<< 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:
--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,
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;
}

View File

@ -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";

View File

@ -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,

View File

@ -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<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);
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();

View File

@ -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_;
};

View File

@ -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<HttpsUpstream *>(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<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;
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;
}
} // 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;
}

View File

@ -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> downstream_;
IOControl ioctrl_;
// The number of requests seen so far.
size_t num_requests_;
};
} // namespace shrpx