apache / incubator-pagespeed-ngx

Automatic PageSpeed optimization module for Nginx
http://ngxpagespeed.com/
Apache License 2.0
4.37k stars 365 forks source link

Will ngx_pagespeed affect the use of http / 2 server push? #1539

Open chaihongjun opened 6 years ago

chaihongjun commented 6 years ago

Recently I upgraded nginx to 1.13.9, hoping to use server push.But, ngx_pagespeed will overwrite the static resource file name, it seems that I can not complete my expectation 。

Introducing HTTP/2 Server Push with NGINX 1.13.9 https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/

jmarantz commented 6 years ago

This is a great question. The direct answer you are asking for is that you can have h2 server push and still get value from ngx_pagespeed by setting:

pagespeed RewriteLevel OptimizeForBandwidth;

With this setting, pagespeed will not rewrite any URLs, but will just compress and minify contents of css/js/images. Read more here: https://www.modpagespeed.com/doc/optimize-for-bandwidth

However, I'm not convinced that's the best thing for your users, with the spotty support for h2 push in some browsers. The blog-post you give references another blog post, which I encourage you to read carefully: https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/

We actually attempted to make PageSpeed automatically determine which were the best resources to trigger for h2 push a couple of years ago, but in general could not find any particular setting where we measured any kind of improvement visible to users. h2 push worked, but didn't help. The reasons we found were similar to those in the blog post, where in a bandwidth-constrained scenario you might actually block a critical resource with a non-critical one and make the experience worse. Worse, you may push a resource already in the browser cache. While request-cancellation might mitigate that partially, I'm skeptical it would really help in high-latency scenarios. By the time the cancel request reaches the server from the browser, it may have already sent everything.

It was much easier for PageSpeed to create some tangible benefit using h2 preload, and there's an off-by-default setting for that in the the latest stable branch of PageSpeed.

pagespeed EnableFilters hint_preload_subresources;

See https://www.modpagespeed.com/doc/filter-hint-preload-subresources for more details.

It'd be great if you could do some experiments with these various settings, using webpagetest.org with various settings for latency and bandwidth. My thinking is that server-push does best in high-latency/high-bandwidth scenarios.

Note that PageSpeed's inlining features for css/js/images/font-loaders duplicates much of the benefit of h2 push, but with less overhead and complete browser independence.

Please try all this out and let us know what you find!

injust commented 6 years ago

I was experimenting with the hint_preload_subresources filter on the PageSpeed example pages. In some cases, it would generate a <Link> header to resources with rewritten URLs. Unsure if this is intended behaviour, cross-linking to apache/incubator-pagespeed-mod#1756. But this shows that the filter is capable of hinting resources after they are rewritten.

When optimizations done by other filters expire, hints for optimizing those resources will not be generated (as it is unknown whether they'll get re-optimized at the point the HTTP headers are generated).

If this is the case, is it possible to push all hinted resources, as the hints are only generated for resources that have completed their optimizations?

injust commented 6 years ago

The reasons we found were similar to those in the blog post, where in a bandwidth-constrained scenario you might actually block a critical resource with a non-critical one and make the experience worse. Worse, you may push a resource already in the browser cache. While request-cancellation might mitigate that partially, I'm skeptical it would really help in high-latency scenarios. By the time the cancel request reaches the server from the browser, it may have already sent everything.

Outside of Apache and nginx, H2O has server push implemented with cache-awareness as well as push prioritization, which looks promising. I haven't experimented much with it, but cache-awareness looks to be a good way to get around the disadvantages of server push in high-latency situations.

jmarantz commented 6 years ago

I think cache awareness is a hard problem. The good news is that it doesn't have to be a perfect solution as the penalty for being wrong is suboptimal performance, not a broken page. It would be interesting to see some studies indicating how well it works in practice under various scenarios.

fabiograsso commented 6 years ago

I've tried using hint_preload_subresources but I've found that the Link header are sent with the "nopush" attribute

This is also what's reported on example in PageSpeed documentation:

Then PageSpeed will add the following HTTP headers to the page:

link: </styles_all_styles.css>; rel=preload; as=style; nopush
link: </basic.css>; rel=preload; as=style; nopush
link: </fancy.css>; rel=preload; as=style; nopush
link: </script.js>; rel=preload; as=script; nopush

According to nginx documentation:

If you don’t want NGINX to push a preloaded resource, add a nopush parameter to the header:

# Resource is not pushed
Link: </nginx.png>; as=image; rel=preload; nopush

I don't know if there is a way for setup PageSpeed in order to not send the "nopush" but if not it's normal for the push to fail, and it's working as expected. I wonder why this choice to put nopush in the headers.

asshaposhnikov commented 5 years ago

I've tried using hint_preload_subresources but I've found that the Link header are sent with the "nopush" attribute

This is also what's reported on example in PageSpeed documentation:

Then PageSpeed will add the following HTTP headers to the page:

link: </styles_all_styles.css>; rel=preload; as=style; nopush
link: </basic.css>; rel=preload; as=style; nopush
link: </fancy.css>; rel=preload; as=style; nopush
link: </script.js>; rel=preload; as=script; nopush

According to nginx documentation:

If you don’t want NGINX to push a preloaded resource, add a nopush parameter to the header:

# Resource is not pushed
Link: </nginx.png>; as=image; rel=preload; nopush

I don't know if there is a way for setup PageSpeed in order to not send the "nopush" but if not it's normal for the push to fail, and it's working as expected. I wonder why this choice to put nopush in the headers.

See same behavior. Pagespeed add - Link ... ; nopush . It make good thing, but vice versa.