From e3797a66a3d8213b5c34cafca5a8882b152fc2c2 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 5 Apr 2021 04:06:58 +0300 Subject: Gzip: support for zlib-ng. --- src/http/modules/ngx_http_gzip_filter_module.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'src/http/modules') diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index c75169c53..59cbad745 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -57,6 +57,7 @@ typedef struct { unsigned nomem:1; unsigned buffering:1; unsigned intel:1; + unsigned zlib_ng:1; size_t zin; size_t zout; @@ -214,6 +215,7 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_uint_t ngx_http_gzip_assume_intel; +static ngx_uint_t ngx_http_gzip_assume_zlib_ng; static ngx_int_t @@ -506,7 +508,7 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) if (!ngx_http_gzip_assume_intel) { ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); - } else { + } else if (!ngx_http_gzip_assume_zlib_ng) { /* * A zlib variant from Intel, https://github.com/jtkukunas/zlib. * It can force window bits to 13 for fast compression level, @@ -523,6 +525,20 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) + (1 << (ngx_max(memlevel, 8) + 8)) + (1 << (memlevel + 8)); ctx->intel = 1; + + } else { + /* + * Another zlib variant, https://github.com/zlib-ng/zlib-ng. + * Similar to Intel's variant, though uses 128K hash. + */ + + if (conf->level == 1) { + wbits = ngx_max(wbits, 13); + } + + ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) + + 131072 + (1 << (memlevel + 8)); + ctx->zlib_ng = 1; } } @@ -945,11 +961,14 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) return p; } - if (ctx->intel) { + if (ctx->zlib_ng) { ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, "gzip filter failed to use preallocated memory: " "%ud of %ui", items * size, ctx->allocated); + } else if (ctx->intel) { + ngx_http_gzip_assume_zlib_ng = 1; + } else { ngx_http_gzip_assume_intel = 1; } -- cgit From 4af67214ad3d7f0f525bea777d5a43aa7a702ecf Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 5 Apr 2021 04:07:17 +0300 Subject: Gzip: updated handling of zlib variant from Intel. In current versions (all versions based on zlib 1.2.11, at least since 2018) it no longer uses 64K hash and does not force window bits to 13 if it is less than 13. That is, it needs just 16 bytes more memory than normal zlib, so these bytes are simply added to the normal size calculation. --- src/http/modules/ngx_http_gzip_filter_module.c | 35 +++++++------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'src/http/modules') diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index 59cbad745..b8c5ccc5c 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -56,7 +56,6 @@ typedef struct { unsigned done:1; unsigned nomem:1; unsigned buffering:1; - unsigned intel:1; unsigned zlib_ng:1; size_t zin; @@ -214,7 +213,6 @@ static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; -static ngx_uint_t ngx_http_gzip_assume_intel; static ngx_uint_t ngx_http_gzip_assume_zlib_ng; @@ -503,33 +501,21 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) * 8K is for zlib deflate_state, it takes * *) 5816 bytes on i386 and sparc64 (32-bit mode) * *) 5920 bytes on amd64 and sparc64 + * + * A zlib variant from Intel (https://github.com/jtkukunas/zlib) + * uses additional 16-byte padding in one of window-sized buffers. */ - if (!ngx_http_gzip_assume_intel) { - ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); - - } else if (!ngx_http_gzip_assume_zlib_ng) { - /* - * A zlib variant from Intel, https://github.com/jtkukunas/zlib. - * It can force window bits to 13 for fast compression level, - * on processors with SSE 4.2 it uses 64K hash instead of scaling - * it from the specified memory level, and also introduces - * 16-byte padding in one out of the two window-sized buffers. - */ - - if (conf->level == 1) { - wbits = ngx_max(wbits, 13); - } - + if (!ngx_http_gzip_assume_zlib_ng) { ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) - + (1 << (ngx_max(memlevel, 8) + 8)) - + (1 << (memlevel + 8)); - ctx->intel = 1; + + (1 << (memlevel + 9)); } else { /* * Another zlib variant, https://github.com/zlib-ng/zlib-ng. - * Similar to Intel's variant, though uses 128K hash. + * It forces window bits to 13 for fast compression level, + * uses 16-byte padding in one of window-sized buffers, and + * uses 128K hash. */ if (conf->level == 1) { @@ -966,11 +952,8 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) "gzip filter failed to use preallocated memory: " "%ud of %ui", items * size, ctx->allocated); - } else if (ctx->intel) { - ngx_http_gzip_assume_zlib_ng = 1; - } else { - ngx_http_gzip_assume_intel = 1; + ngx_http_gzip_assume_zlib_ng = 1; } p = ngx_palloc(ctx->request->pool, items * size); -- cgit From d9996d6f27150bfb9c9c00d77fac940712aa1d28 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 8 Apr 2021 00:15:48 +0300 Subject: Introduced the "keepalive_time" directive. Similar to lingering_time, it limits total connection lifetime before keepalive is switched off. The default is 1 hour, which is close to the total maximum connection lifetime possible with default keepalive_requests and keepalive_timeout. --- src/http/modules/ngx_http_upstream_keepalive_module.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/http/modules') diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 1560807c6..bbd650b79 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -13,6 +13,7 @@ typedef struct { ngx_uint_t max_cached; ngx_uint_t requests; + ngx_msec_t time; ngx_msec_t timeout; ngx_queue_t cache; @@ -86,6 +87,13 @@ static ngx_command_t ngx_http_upstream_keepalive_commands[] = { 0, NULL }, + { ngx_string("keepalive_time"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_upstream_keepalive_srv_conf_t, time), + NULL }, + { ngx_string("keepalive_timeout"), NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -149,6 +157,7 @@ ngx_http_upstream_init_keepalive(ngx_conf_t *cf, kcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_keepalive_module); + ngx_conf_init_msec_value(kcf->time, 3600000); ngx_conf_init_msec_value(kcf->timeout, 60000); ngx_conf_init_uint_value(kcf->requests, 100); @@ -326,6 +335,10 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, goto invalid; } + if (ngx_current_msec - c->start_time > kp->conf->time) { + goto invalid; + } + if (!u->keepalive) { goto invalid; } @@ -513,6 +526,7 @@ ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) * conf->max_cached = 0; */ + conf->time = NGX_CONF_UNSET_MSEC; conf->timeout = NGX_CONF_UNSET_MSEC; conf->requests = NGX_CONF_UNSET_UINT; -- cgit From eb52de83114e8d98722cd17ec8435c47956b6315 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 8 Apr 2021 00:16:30 +0300 Subject: Changed keepalive_requests default to 1000 (ticket #2155). It turns out no browsers implement HTTP/2 GOAWAY handling properly, and large enough number of resources on a page results in failures to load some resources. In particular, Chrome seems to experience errors if loading of all resources requires more than 1 connection (while it is usually able to retry requests at least once, even with 2 connections there are occasional failures for some reason), Safari if loading requires more than 3 connections, and Firefox if loading requires more than 10 connections (can be configured with network.http.request.max-attempts, defaults to 10). It does not seem to be possible to resolve this on nginx side, even strict limiting of maximum concurrency does not help, and loading issues seems to be triggered by merely queueing of a request for a particular connection. The only available mitigation seems to use higher keepalive_requests value. The new default is 1000 and matches previously used default for http2_max_requests. It is expected to be enough for 99.98% of the pages (https://httparchive.org/reports/state-of-the-web?start=latest#reqTotal) even in Chrome. --- src/http/modules/ngx_http_upstream_keepalive_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/modules') diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index bbd650b79..1a4dfd776 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -159,7 +159,7 @@ ngx_http_upstream_init_keepalive(ngx_conf_t *cf, ngx_conf_init_msec_value(kcf->time, 3600000); ngx_conf_init_msec_value(kcf->timeout, 60000); - ngx_conf_init_uint_value(kcf->requests, 100); + ngx_conf_init_uint_value(kcf->requests, 1000); if (kcf->original_init_upstream(cf, us) != NGX_OK) { return NGX_ERROR; -- cgit