nghttpx: Add experimental TCP optimization for h2 frontend
This commit is contained in:
parent
b14375ec63
commit
27b250ac8e
|
@ -136,6 +136,8 @@ OPTIONS = [
|
||||||
"backend-max-backoff",
|
"backend-max-backoff",
|
||||||
"server-name",
|
"server-name",
|
||||||
"no-server-rewrite",
|
"no-server-rewrite",
|
||||||
|
"frontend-http2-optimize-write-buffer-size",
|
||||||
|
"frontend-http2-optimize-window-size",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|
36
src/shrpx.cc
36
src/shrpx.cc
|
@ -2032,6 +2032,27 @@ HTTP/2 and SPDY:
|
||||||
backend session is relayed to frontend, and server push
|
backend session is relayed to frontend, and server push
|
||||||
via Link header field is also supported. SPDY frontend
|
via Link header field is also supported. SPDY frontend
|
||||||
does not support server push.
|
does not support server push.
|
||||||
|
--frontend-http2-optimize-write-buffer-size
|
||||||
|
(Experimental) Enable write buffer size optimization in
|
||||||
|
frontend HTTP/2 TLS connection. This optimization aims
|
||||||
|
to reduce write buffer size so that it only contains
|
||||||
|
bytes which can send immediately. This makes server
|
||||||
|
more responsive to prioritized HTTP/2 stream because the
|
||||||
|
buffering of lower priority stream is reduced. This
|
||||||
|
option is only effective on recent Linux platform.
|
||||||
|
--frontend-http2-optimize-window-size
|
||||||
|
(Experimental) Automatically tune connection level
|
||||||
|
window size of frontend HTTP/2 TLS connection. If this
|
||||||
|
feature is enabled, connection window size starts with
|
||||||
|
the default window size, 65535 bytes. nghttpx
|
||||||
|
automatically adjusts connection window size based on
|
||||||
|
TCP receiving window size. The maximum window size is
|
||||||
|
capped by the value specified by
|
||||||
|
--frontend-http2-connection-window-bits. Since the
|
||||||
|
stream is subject to stream level window size, it should
|
||||||
|
be adjusted using --frontend-http2-window-bits option as
|
||||||
|
well. This option is only effective on recent Linux
|
||||||
|
platform.
|
||||||
|
|
||||||
Mode:
|
Mode:
|
||||||
(default mode)
|
(default mode)
|
||||||
|
@ -2842,6 +2863,10 @@ int main(int argc, char **argv) {
|
||||||
{SHRPX_OPT_BACKEND_MAX_BACKOFF.c_str(), required_argument, &flag, 127},
|
{SHRPX_OPT_BACKEND_MAX_BACKOFF.c_str(), required_argument, &flag, 127},
|
||||||
{SHRPX_OPT_SERVER_NAME.c_str(), required_argument, &flag, 128},
|
{SHRPX_OPT_SERVER_NAME.c_str(), required_argument, &flag, 128},
|
||||||
{SHRPX_OPT_NO_SERVER_REWRITE.c_str(), no_argument, &flag, 129},
|
{SHRPX_OPT_NO_SERVER_REWRITE.c_str(), no_argument, &flag, 129},
|
||||||
|
{SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE.c_str(),
|
||||||
|
no_argument, &flag, 130},
|
||||||
|
{SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE.c_str(), no_argument,
|
||||||
|
&flag, 131},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -3448,6 +3473,17 @@ int main(int argc, char **argv) {
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_REWRITE,
|
cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_REWRITE,
|
||||||
StringRef::from_lit("yes"));
|
StringRef::from_lit("yes"));
|
||||||
break;
|
break;
|
||||||
|
case 130:
|
||||||
|
// --frontend-http2-optimize-write-buffer-size
|
||||||
|
cmdcfgs.emplace_back(
|
||||||
|
SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE,
|
||||||
|
StringRef::from_lit("yes"));
|
||||||
|
break;
|
||||||
|
case 131:
|
||||||
|
// --frontend-http2-optimize-window-size
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE,
|
||||||
|
StringRef::from_lit("yes"));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,7 +244,6 @@ int ClientHandler::write_tls() {
|
||||||
|
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (on_write() != 0) {
|
if (on_write() != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -252,9 +251,14 @@ int ClientHandler::write_tls() {
|
||||||
auto iovcnt = upstream_->response_riovec(&iov, 1);
|
auto iovcnt = upstream_->response_riovec(&iov, 1);
|
||||||
if (iovcnt == 0) {
|
if (iovcnt == 0) {
|
||||||
conn_.start_tls_write_idle();
|
conn_.start_tls_write_idle();
|
||||||
break;
|
|
||||||
|
conn_.wlimit.stopw();
|
||||||
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
|
auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
|
||||||
if (nwrite < 0) {
|
if (nwrite < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -265,13 +269,13 @@ int ClientHandler::write_tls() {
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream_->response_drain(nwrite);
|
upstream_->response_drain(nwrite);
|
||||||
}
|
|
||||||
|
|
||||||
conn_.wlimit.stopw();
|
|
||||||
ev_timer_stop(conn_.loop, &conn_.wt);
|
|
||||||
|
|
||||||
|
iovcnt = upstream_->response_riovec(&iov, 1);
|
||||||
|
if (iovcnt == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ClientHandler::upstream_noop() { return 0; }
|
int ClientHandler::upstream_noop() { return 0; }
|
||||||
|
|
||||||
|
@ -1445,4 +1449,6 @@ StringRef ClientHandler::get_forwarded_for() const {
|
||||||
|
|
||||||
const UpstreamAddr *ClientHandler::get_upstream_addr() const { return faddr_; }
|
const UpstreamAddr *ClientHandler::get_upstream_addr() const { return faddr_; }
|
||||||
|
|
||||||
|
Connection *ClientHandler::get_connection() { return &conn_; };
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -154,6 +154,8 @@ public:
|
||||||
void repeat_read_timer();
|
void repeat_read_timer();
|
||||||
void stop_read_timer();
|
void stop_read_timer();
|
||||||
|
|
||||||
|
Connection *get_connection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Connection conn_;
|
Connection conn_;
|
||||||
ev_timer reneg_shutdown_timer_;
|
ev_timer reneg_shutdown_timer_;
|
||||||
|
|
|
@ -1643,6 +1643,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
break;
|
break;
|
||||||
case 35:
|
case 35:
|
||||||
switch (name[34]) {
|
switch (name[34]) {
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq_l("frontend-http2-optimize-window-siz", name, 34)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) {
|
if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER;
|
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER;
|
||||||
|
@ -1705,6 +1710,10 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
case 41:
|
case 41:
|
||||||
switch (name[40]) {
|
switch (name[40]) {
|
||||||
case 'e':
|
case 'e':
|
||||||
|
if (util::strieq_l("frontend-http2-optimize-write-buffer-siz", name,
|
||||||
|
40)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE;
|
||||||
|
}
|
||||||
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
|
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
|
||||||
40)) {
|
40)) {
|
||||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
|
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
|
||||||
|
@ -2689,6 +2698,15 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||||
case SHRPX_OPTID_NO_SERVER_REWRITE:
|
case SHRPX_OPTID_NO_SERVER_REWRITE:
|
||||||
config->http.no_server_rewrite = util::strieq_l("yes", optarg);
|
config->http.no_server_rewrite = util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE:
|
||||||
|
config->http2.upstream.optimize_write_buffer_size =
|
||||||
|
util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE:
|
||||||
|
config->http2.upstream.optimize_window_size = util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
|
@ -287,6 +287,10 @@ constexpr auto SHRPX_OPT_BACKEND_MAX_BACKOFF =
|
||||||
constexpr auto SHRPX_OPT_SERVER_NAME = StringRef::from_lit("server-name");
|
constexpr auto SHRPX_OPT_SERVER_NAME = StringRef::from_lit("server-name");
|
||||||
constexpr auto SHRPX_OPT_NO_SERVER_REWRITE =
|
constexpr auto SHRPX_OPT_NO_SERVER_REWRITE =
|
||||||
StringRef::from_lit("no-server-rewrite");
|
StringRef::from_lit("no-server-rewrite");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE =
|
||||||
|
StringRef::from_lit("frontend-http2-optimize-write-buffer-size");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE =
|
||||||
|
StringRef::from_lit("frontend-http2-optimize-window-size");
|
||||||
|
|
||||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
|
@ -586,6 +590,8 @@ struct Http2Config {
|
||||||
size_t window_bits;
|
size_t window_bits;
|
||||||
size_t connection_window_bits;
|
size_t connection_window_bits;
|
||||||
size_t max_concurrent_streams;
|
size_t max_concurrent_streams;
|
||||||
|
bool optimize_write_buffer_size;
|
||||||
|
bool optimize_window_size;
|
||||||
} upstream;
|
} upstream;
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
|
@ -818,6 +824,8 @@ enum {
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
|
SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
|
SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS,
|
SHRPX_OPTID_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_READ_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_HTTP2_READ_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
|
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif // HAVE_UNISTD_H
|
#endif // HAVE_UNISTD_H
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
@ -757,4 +758,55 @@ void Connection::handle_tls_pending_read() {
|
||||||
rlimit.handle_tls_pending_read();
|
rlimit.handle_tls_pending_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Connection::get_tcp_hint(TCPHint *hint) const {
|
||||||
|
#if defined(TCP_INFO) && defined(TCP_NOTSENT_LOWAT)
|
||||||
|
struct tcp_info tcp_info;
|
||||||
|
socklen_t tcp_info_len = sizeof(tcp_info);
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &tcp_info_len);
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto avail_packets = tcp_info.tcpi_snd_cwnd > tcp_info.tcpi_unacked
|
||||||
|
? tcp_info.tcpi_snd_cwnd - tcp_info.tcpi_unacked
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
// http://www.slideshare.net/kazuho/programming-tcp-for-responsiveness
|
||||||
|
//
|
||||||
|
// TODO 29 (5 + 8 + 16) is TLS overhead for AES-GCM. For
|
||||||
|
// CHACHA20_POLY1305, it is 21 since it does not need 8 bytes
|
||||||
|
// explicit nonce.
|
||||||
|
auto writable_size = (avail_packets + 2) * (tcp_info.tcpi_snd_mss - 29);
|
||||||
|
if (writable_size > 16_k) {
|
||||||
|
writable_size = writable_size & ~(16_k - 1);
|
||||||
|
} else {
|
||||||
|
if (writable_size < 536) {
|
||||||
|
LOG(INFO) << "writable_size is too small: " << writable_size;
|
||||||
|
}
|
||||||
|
// TODO is this required?
|
||||||
|
writable_size = std::max(writable_size, static_cast<uint32_t>(536 * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "snd_cwnd=" << tcp_info.tcpi_snd_cwnd
|
||||||
|
<< ", unacked=" << tcp_info.tcpi_unacked
|
||||||
|
<< ", snd_mss=" << tcp_info.tcpi_snd_mss
|
||||||
|
<< ", rtt=" << tcp_info.tcpi_rtt << "us"
|
||||||
|
<< ", rcv_space=" << tcp_info.tcpi_rcv_space
|
||||||
|
<< ", writable=" << writable_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
hint->write_buffer_size = writable_size;
|
||||||
|
// TODO tcpi_rcv_space is considered as rwin, is that correct?
|
||||||
|
hint->rwin = tcp_info.tcpi_rcv_space;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#else // !defined(TCP_INFO) || !defined(TCP_NOTSENT_LOWAT)
|
||||||
|
return -1;
|
||||||
|
#endif // !defined(TCP_INFO) || !defined(TCP_NOTSENT_LOWAT)
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -66,6 +66,11 @@ struct TLSConnection {
|
||||||
bool reneg_started;
|
bool reneg_started;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TCPHint {
|
||||||
|
size_t write_buffer_size;
|
||||||
|
uint32_t rwin;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T> using EVCb = void (*)(struct ev_loop *, T *, int);
|
template <typename T> using EVCb = void (*)(struct ev_loop *, T *, int);
|
||||||
|
|
||||||
using IOCb = EVCb<ev_io>;
|
using IOCb = EVCb<ev_io>;
|
||||||
|
@ -118,6 +123,8 @@ struct Connection {
|
||||||
|
|
||||||
void set_ssl(SSL *ssl);
|
void set_ssl(SSL *ssl);
|
||||||
|
|
||||||
|
int get_tcp_hint(TCPHint *hint) const;
|
||||||
|
|
||||||
TLSConnection tls;
|
TLSConnection tls;
|
||||||
ev_io wev;
|
ev_io wev;
|
||||||
ev_io rev;
|
ev_io rev;
|
||||||
|
|
|
@ -776,7 +776,9 @@ int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
// data transferred.
|
// data transferred.
|
||||||
downstream->response_sent_body_length += length;
|
downstream->response_sent_body_length += length;
|
||||||
|
|
||||||
return wb->rleft() >= MAX_BUFFER_SIZE ? NGHTTP2_ERR_PAUSE : 0;
|
auto max_buffer_size = upstream->get_max_buffer_size();
|
||||||
|
|
||||||
|
return wb->rleft() >= max_buffer_size ? NGHTTP2_ERR_PAUSE : 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -919,7 +921,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
||||||
downstream_queue_(downstream_queue_size(handler->get_worker()),
|
downstream_queue_(downstream_queue_size(handler->get_worker()),
|
||||||
!get_config()->http2_proxy),
|
!get_config()->http2_proxy),
|
||||||
handler_(handler),
|
handler_(handler),
|
||||||
session_(nullptr) {
|
session_(nullptr),
|
||||||
|
max_buffer_size_(MAX_BUFFER_SIZE) {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
auto &http2conf = get_config()->http2;
|
auto &http2conf = get_config()->http2;
|
||||||
|
@ -955,7 +958,9 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t window_bits =
|
int32_t window_bits =
|
||||||
faddr->alt_mode ? 31 : http2conf.upstream.connection_window_bits;
|
faddr->alt_mode ? 31 : http2conf.upstream.optimize_window_size
|
||||||
|
? 16
|
||||||
|
: http2conf.upstream.connection_window_bits;
|
||||||
|
|
||||||
if (window_bits != 16) {
|
if (window_bits != 16) {
|
||||||
int32_t window_size = (1u << window_bits) - 1;
|
int32_t window_size = (1u << window_bits) - 1;
|
||||||
|
@ -983,6 +988,25 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
||||||
prep_.data = this;
|
prep_.data = this;
|
||||||
ev_prepare_start(handler_->get_loop(), &prep_);
|
ev_prepare_start(handler_->get_loop(), &prep_);
|
||||||
|
|
||||||
|
#if defined(TCP_INFO) && defined(TCP_NOTSENT_LOWAT)
|
||||||
|
if (http2conf.upstream.optimize_write_buffer_size) {
|
||||||
|
auto conn = handler_->get_connection();
|
||||||
|
conn->tls_dyn_rec_warmup_threshold = 0;
|
||||||
|
|
||||||
|
uint32_t pollout_thres = 1;
|
||||||
|
rv = setsockopt(conn->fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &pollout_thres,
|
||||||
|
static_cast<socklen_t>(sizeof(pollout_thres)));
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
auto error = errno;
|
||||||
|
LOG(INFO) << "setsockopt(TCP_NOTSENT_LOWAT, " << pollout_thres
|
||||||
|
<< ") failed: errno=" << error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // defined(TCP_INFO) && defined(TCP_NOTSENT_LOWAT)
|
||||||
|
|
||||||
handler_->reset_upstream_read_timeout(
|
handler_->reset_upstream_read_timeout(
|
||||||
get_config()->conn.upstream.timeout.http2_read);
|
get_config()->conn.upstream.timeout.http2_read);
|
||||||
|
|
||||||
|
@ -1032,8 +1056,44 @@ int Http2Upstream::on_read() {
|
||||||
|
|
||||||
// After this function call, downstream may be deleted.
|
// After this function call, downstream may be deleted.
|
||||||
int Http2Upstream::on_write() {
|
int Http2Upstream::on_write() {
|
||||||
|
int rv;
|
||||||
|
auto &http2conf = get_config()->http2;
|
||||||
|
|
||||||
|
if ((http2conf.upstream.optimize_write_buffer_size ||
|
||||||
|
http2conf.upstream.optimize_window_size) &&
|
||||||
|
handler_->get_ssl()) {
|
||||||
|
auto conn = handler_->get_connection();
|
||||||
|
TCPHint hint;
|
||||||
|
rv = conn->get_tcp_hint(&hint);
|
||||||
|
if (rv == 0) {
|
||||||
|
if (http2conf.upstream.optimize_write_buffer_size) {
|
||||||
|
max_buffer_size_ = std::min(MAX_BUFFER_SIZE, hint.write_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (http2conf.upstream.optimize_window_size) {
|
||||||
|
auto faddr = handler_->get_upstream_addr();
|
||||||
|
if (!faddr->alt_mode) {
|
||||||
|
int32_t window_size =
|
||||||
|
(1u << http2conf.upstream.connection_window_bits) - 1;
|
||||||
|
window_size =
|
||||||
|
std::min(static_cast<uint32_t>(window_size), hint.rwin * 2);
|
||||||
|
|
||||||
|
rv = nghttp2_session_set_local_window_size(
|
||||||
|
session_, NGHTTP2_FLAG_NONE, 0, window_size);
|
||||||
|
if (rv != 0) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
ULOG(INFO, this)
|
||||||
|
<< "nghttp2_session_set_local_window_size() with window_size="
|
||||||
|
<< window_size << " failed: " << nghttp2_strerror(rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (wb_.rleft() >= MAX_BUFFER_SIZE) {
|
if (wb_.rleft() >= max_buffer_size_) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,10 +1313,26 @@ ssize_t downstream_data_read_callback(nghttp2_session *session,
|
||||||
auto downstream = static_cast<Downstream *>(source->ptr);
|
auto downstream = static_cast<Downstream *>(source->ptr);
|
||||||
auto body = downstream->get_response_buf();
|
auto body = downstream->get_response_buf();
|
||||||
assert(body);
|
assert(body);
|
||||||
|
auto upstream = static_cast<Http2Upstream *>(user_data);
|
||||||
|
|
||||||
const auto &resp = downstream->response();
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
auto nread = std::min(body->rleft(), length);
|
auto nread = std::min(body->rleft(), length);
|
||||||
|
|
||||||
|
auto max_buffer_size = upstream->get_max_buffer_size();
|
||||||
|
|
||||||
|
auto buffer = upstream->get_response_buf();
|
||||||
|
|
||||||
|
if (max_buffer_size <
|
||||||
|
std::min(nread, static_cast<size_t>(256)) + 9 + buffer->rleft()) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
ULOG(INFO, upstream) << "Buffer is almost full. Skip write DATA";
|
||||||
|
}
|
||||||
|
return NGHTTP2_ERR_PAUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nread = std::min(nread, max_buffer_size - 9 - buffer->rleft());
|
||||||
|
|
||||||
auto body_empty = body->rleft() == nread;
|
auto body_empty = body->rleft() == nread;
|
||||||
|
|
||||||
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
|
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
|
||||||
|
@ -2027,4 +2103,6 @@ void Http2Upstream::cancel_premature_downstream(
|
||||||
downstream_queue_.remove_and_get_blocked(promised_downstream, false);
|
downstream_queue_.remove_and_get_blocked(promised_downstream, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Http2Upstream::get_max_buffer_size() const { return max_buffer_size_; }
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -118,6 +118,8 @@ public:
|
||||||
|
|
||||||
DefaultMemchunks *get_response_buf();
|
DefaultMemchunks *get_response_buf();
|
||||||
|
|
||||||
|
size_t get_max_buffer_size() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DefaultMemchunks wb_;
|
DefaultMemchunks wb_;
|
||||||
std::unique_ptr<HttpsUpstream> pre_upstream_;
|
std::unique_ptr<HttpsUpstream> pre_upstream_;
|
||||||
|
@ -127,6 +129,7 @@ private:
|
||||||
ev_prepare prep_;
|
ev_prepare prep_;
|
||||||
ClientHandler *handler_;
|
ClientHandler *handler_;
|
||||||
nghttp2_session *session_;
|
nghttp2_session *session_;
|
||||||
|
size_t max_buffer_size_;
|
||||||
bool flow_control_;
|
bool flow_control_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue