redfin / react-server

:rocket: Blazing fast page load and seamless navigation.
https://react-server.io/
Apache License 2.0
3.89k stars 184 forks source link

Add support for HTTP/2 with server push #238

Open doug-wade opened 8 years ago

doug-wade commented 8 years ago

One of the most powerful things about react-server is that the server-side knows, in a structured way, about all of the associated resources for a page (JS, CSS, JSON XHR) and could push them pro-actively. Not only would this theoretically be faster than the current code, it would also obviate the need for the ReactServerAgent cache, which would simplify the logic a lot in the HTTP/2 case.

Migrated from #50

aickin commented 8 years ago

FYI for anyone thinking of working on this issue: I know that @roblg poked at it and built a working prototype. Also, the biggest problem he ran into was that Express is not compatible with node's http2 library (for extremely byzantine reasons). He had to migrate from Express to connect to get it to work.

cc @withinboredom

gigabo commented 8 years ago

From @withinboredom in #259:

I lately implemented a wordpress plugin for my workplace that turns this on. This is actually simpler than you'd think. I'm going to take a look under the hood of react-server and document the work that needs to be done and then we can figure out what to do about it.

Thanks @withinboredom!

kcjonson commented 8 years ago

I was able to use the spdy module to get an HTTP2 example together with express, code here: https://github.com/kcjonson/http2-boilerplate/tree/master

Edit: link to spdy: https://www.npmjs.com/package/spdy

karlhorky commented 7 years ago

@withinboredom Any news on this?

doug-wade commented 7 years ago

I've been trying to keep my eye on this. Work has been progressing pretty well on http2 in node core -- it looks like they're targeting having it available behind an experimental flag in node 8. I've been periodically building and tinkering with the in-progress http2 branch, and I believe that barring anyone else having implemented this, I should have a PR open sometime in April.

karlhorky commented 7 years ago

@doug-wade great, thanks for the update!

aickin commented 7 years ago

FWIW, my thinking on this has changed a bit since I filed it in #50 after I went to Velocity this past fall and started poking at server push for a few weeks.

One of the talks I saw at Velocity (lightly) suggested that server push is generally probably a bad idea at this point. It turns out that, at least as of October or so, no browsers implement client cancellation of push streams when a resource is already in cache. So if you always blindly push all your affiliated static resources, you will lose the entire benefit of the browser cache on repeat visit, at least as far as bandwidth is concerned.

Additionally, the speaker I saw suggested that even if browsers did support cancelling push streams, it wouldn't result in a lot of perf saving because in many cases the server would end up sending down a lot of the pushed resource before getting the cancellation. (I vaguely remember the speaker saying something about a situation where the server can easily get most of the pushed resources into the network buffers before the stream cancellation comes back from the client, but don't quote me on that.)

There is a rough plan to fix this situation but it's pretty early days. There's a draft spec for Cache Digests, which would allow browsers to send a compressed digest of all the server's URLs in the browser cache. The server can check what's in the client's cache and use that to decide what to push and what not to push. Due to some clever math, the digest is quite compact over the wire, although that compactness comes at a price: the digest is probabilistic and allows for some chance of false positives. In case of a false positive, the server incorrectly will believe that the client has the resource in cache, but that turns out to be fine; it just means the browser will request the resource as usual.

I believe that no current browsers support cache digests, but I might be wrong. Until they do, though, I feel like http/2 push is probably not a great feature for react-server. There are some implementations, like the h2o server, that have hacked together cache digests implemented in HTTP cookies, but that feels pretty brittle to me and not worth the effort if real cache digest support is on its way eventually. YMMV, of course.

There's a good, long article about some of the tradeoffs here: http://calendar.perfplanet.com/2016/cache-digests-http2-server-push/

karlhorky commented 7 years ago

Wow, didn't know about the downsides, good points. This is something that should be communicated loud and clear in the infrastructure / performance communities.

Edit: Doing my part: https://twitter.com/karlhorky/status/817515226564329473

dfabulich commented 7 years ago

That blog post mentions that Service Workers can polyfill HTTP/2 cache digests. On first load, the H2 server pushes everything. On second load, the browser hits the Service Worker, which can compute the cache digest itself and add it as a custom header to the request. The server can use the cache header to decide what to push and what not to push in the subsequent response.