top | item 15742304

The Performance Cost of Server Side Rendered React on Node.js

174 points| dberhane | 8 years ago |malloc.fi | reply

125 comments

order
[+] laurencerowe|8 years ago|reply
It would be worth verifying that NODE_ENV=production is set during these benchmarks (I see no mention in either the article or the source repository.) Running in development mode has a significant performance impact.

Edit: This PR shows that is likely to be the case. Running in production mode along with some other minor changes shows React running at 88% the speed of Pug. https://github.com/janit/node-templating-benchmark/pull/1

[+] anatoli|8 years ago|reply
NODE_ENV=production definitely wasn't set based on some basic testing I did (that's my PR there), which accounts for the atrocious performance.

Also, the React component is created on each request instead of just being created once. Unless one's goal is to specifically colour the perception of React, I don't understand that decision alongside the code for Pug which precompiles the template a single time.

(Also declaring the map function outside the component and not creating a closure makes for a tiny extra boost.)

It's disappointing to see that the article took off to this extent given how misleading and inaccurate it is.

[+] MatthewPhillips|8 years ago|reply
Note that React doesn't do streaming HTML in the traditional sense. You can't send out initial HTML while you wait on an API response, for example. Instead only the serializer is streaming. Your app renders to a VNode synchronously and then the serializer traverses the VNode, synchronously, and streams the strings out as it goes. This is why streaming is only a little bit better in these numbers.

If/when React gets real streaming it will compete better with traditional templating engines, most of which don't do streaming. If you use Node.js and want a traditional templating engine that uses JS template literals and does do streaming, check out my project: https://github.com/matthewp/flora

[+] kraftman|8 years ago|reply
I thought the idea was to render it server side just once, then have the client take over for all future requests? In which case it's 10x slow for the first page load, but all future requests are just hitting API endpoints and can be fairly fast?
[+] _greim_|8 years ago|reply
Correct, except that initial app load time for un-cookied users with cold browser caches is a critical metric, since it largely determines whether they'll keep using your app. Fortunately, those are the scenarios where server-side caching can have a decent benefit, since you're essentially rendering the same view to all such users.
[+] nathan_long|8 years ago|reply
Sure, but every user has to do that initial page load. If all initial page loads are slow and expensive, it affects the user experience and costs money.

Also, if you start getting requests faster than you can do the initial render, each subsequent user has to wait in line longer than the one before. Your server-side framework won't even show you how long people waited for a TCP connection.

[+] mottomotto|8 years ago|reply
If you're on the fence about server-side rendering being needed for your webapp don't do it! As a team of two with one engineer, I decided YAGNI and instead focused on the responsiveness of the React and Redux-based web application. It is very snappy to load and our (paying) customers are happy.

You might not need SSR. I don't. I expect there will be more work to optimize it and eventually it'll be obviously a good idea. But you don't need it right now if you're working on a SaaS product.

[+] timr|8 years ago|reply
It's the other way around: you might not (in fact, probably do not) need React.

Start with server-side rendering, and move to React if your application's dynamism demands it. Most applications don't. It's painful to see so many websites building huge, slow, JS-rendered monsters for one or two dynamic elements per page. Unless you are Facebook (and have your JS cached within one hop of every internet POP in the world), server-side rendering is going to yield performance wins for nearly all visitors.

[+] shams93|8 years ago|reply
No matter what system you use for server rendered pages most likely you will have to hit a database just to render out the site. These days that's a bad idea when we should be building progressive web apps that can fetch and cache content as needed from services but the entire app can live offline and even cache data in local storage to enable it to have at least limited offline functionality.
[+] spinlock|8 years ago|reply
Also, if you _need_ SSR, rails might be a better approach. It's too bad the author didn't include it in the benchmark.
[+] sandGorgon|8 years ago|reply
unless your startup's life and death depends on SEO - in which case, do it !
[+] qaq|8 years ago|reply
OK from single core $10 VPS you will be able to serve 1,080,000 unique initial loads per hour and depending on your pattern of traffic say 15,000,000 in a day could you remind me what the issue is again?
[+] dustingetz|8 years ago|reply
It's a real issue, my startup's react SSR times are ~5 seconds of blocking the node thread on my $40 droplet. It's about 50% react. Our pages are way more sophisticated than your average page with like a query and a form, though. There are many ways to make faster though, one of which is to simply configure your CDN properly.
[+] rsynnott|8 years ago|reply
Assuming that your actual use case is rendering one small HTML table, yes. It probably isn’t, though.
[+] foepys|8 years ago|reply
The issue is that it could be ~14,040,000.
[+] ec109685|8 years ago|reply
Latency still matters though. A stack that can render things in 50ms likely ends up simpler than one that takes 500ms, where things like caching templates, esi, start being introduced to compensate for latency.
[+] olegkikin|8 years ago|reply
The issue is other solutions give you ~10X more page loads per unit of time at the same price.
[+] kennu|8 years ago|reply
Isn't the whole point of server-side rendered React to render it just once, when building the website, and then serve it as static HTML/JS/CSS assets using a static webserver?
[+] andrewwharton|8 years ago|reply
That's one use case.

The other is for performance/seo where the initial markup for the app is generated and served to the client as HTML, then the React app bootstraps on the client and takes over managing the DOM.

[+] abritinthebay|8 years ago|reply
That would be one way of using it. Though practically speaking a very limited way of doing it and not very useful for a lot of dynamic sites.
[+] paxy|8 years ago|reply
More and more sites are using React for general purpose server-side rendering, even if the site isn't a single page app. I believe that's what the article is targeting.
[+] OoooooooO|8 years ago|reply
How do you do that with dynamic content?
[+] ec109685|8 years ago|reply
The author mistakes increasing concurrent request as being some sort of proxy for concurrent users. Once you have maximized rps or maximized cpu, increasing concurrent just artificially hurts your average latency.

Max RPS equals number of users you can serve per second. Concurrency should just be tweaked until you eliminate the network latency of your test framework.

[+] makmanalp|8 years ago|reply
So I thought the entire point of SSR was to speed up initial page load - if you pre-render all the static parts of the page, including what happens after routing, but before any API calls, so that your webserver can cache that static HTML for that route and serve it up. What this means is that the user immediately sees much more of a rendered HTML page, rather than seeing a blank page for 2 seconds and having to wait to download and run a massive JS bundle first.
[+] k__|8 years ago|reply
No, it was to improve SEO and other clients without JS
[+] STRML|8 years ago|reply
For this reason, we don't use SSR for pages that change often, and turn it off completely for authenticated users. Some performance analysis showed it was actually slower in the average case than shipping the JS and having the client render it themselves, especially with a hot cache.

This still provides what we wanted anyway; the ability for pages to easily be viewable without JS and easily indexed by search engines.

[+] jondubois|8 years ago|reply
These results are not surprising to me but it's great that they were published because people have been very quick to jump on the hype bandwagon for these kinds of projects.

I think that the idea of the isomorphic JavaScript app never actually worked in practice. MeteorJS already had a really good go at it.

Sharing JavaScript modules between the client and the server is great but when you start to pretend that the backend and the frontend are the same environment, you're bound to run into all sorts of problems and create inefficiencies.

The kind of performance penalty incurred by server-rendered React is bound to make your system vulnerable to DoS attacks or at best make it unnecessarily expensive to operate.

When programming abstractions shift too far away from the reality of the underlying architecture, you will start paying dearly and the cost won't be worth it in the long run.

In my opinion, the client-server divide is a fundamental aspect of multiuser applications and no amount of abstraction can make it go away.

[+] _m8fo|8 years ago|reply
I'd be curious to know if this cost is similar with Ember's implementation of SSR, Fastboot.
[+] merb|8 years ago|reply
well wasn't that clear? Isn't something like a Template Engine quite CPU intensive? Things were node.js performce poorly?
[+] ralusek|8 years ago|reply
They include a comparison with using ES6 Template literals (native JavaScript string interpolation), and saw 10x increase over React. The native string interpolation actually came out just behind serving straight static files. JavaScript CPU performance is actually quite high among interpreted languages.

So to answer your question more specifically, no I don't think it is clear. What this is specifically isolating as the performance problem is that using React as a template renderer on the backend is not performant, not because of NodeJS performance, but because React is realistically not really specialized for this.

[+] always_good|8 years ago|reply
I don't understand how this can be your takeaway since you can see how fast Pug is in comparison. The article is clearly singling out React's slow render speed.
[+] arkh|8 years ago|reply
I'd like to see the results with php through node-phpcgi to render those pages. So we'd have gone full circle at last.
[+] opvasger|8 years ago|reply
My clients get to render their own html - it's not really that bad if you bundle, split and cache the code.