Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.

SSR performance optimization - caching #811

Closed
naveedahmed1 opened this issue Sep 29, 2017 · 18 comments
Closed

SSR performance optimization - caching #811

naveedahmed1 opened this issue Sep 29, 2017 · 18 comments
Milestone

Comments

@naveedahmed1
Copy link

naveedahmed1 commented Sep 29, 2017

  • I'm submitting a ...
- [x ] feature request
  • What modules are related to this Issue?
- [ x] aspnetcore-engine

It seems that Angular expects to construct a new app platform instance to serve each request. Which means that the bootstrap process is performed for each request. Is it possible to have some sort of cache so that the bootstrap is performed only for the first request.

I think react community is addressing similar issue for react through this plugin from Walmart Labs:

https://github.com/walmartlabs/react-ssr-optimization

  • Please tell us about your environment:
  • Angular version: 4.X
  • Browser: all
  • OS: Windows
  • Platform: .NETCore 2.0
@Toxicable
Copy link

We discussed this a bit over here #795
And the thing that came out of it is that if the request gets to Universal it should be rendered.
Since caching can get complicated with things like CDN's and different platforms I think it's best to let them take care of the caching

@naveedahmed1
Copy link
Author

Thank you so much @Toxicable for quick response. Actually I have already gone through it. But for each request we have to bootstrap the app on server. Which increases the time to first byte for server rendered pages in our case google page speed reports 0.8-2 sec as server response time with warning color. I am not sure what could be the best server response time for server rendered page of a real world angular app for both cases i.e. with and without http call, but I believe search engines consider 0.2-0.4 sec as good server response time. So, increased time to first byte certainly will have negative impact on SEO.

For large websites, we cant directly push contents to CDN in advance, and normally CDN would cache after first request. So, if the first request for a page comes from search engine it will notice delayed response from server.

Have you checked this video from Walmart on React plugin https://www.youtube.com/watch?feature=player_embedded&v=sn-C_DKLKPE , it seems that they are not actually caching the complete response.

@Toxicable
Copy link

Toxicable commented Sep 30, 2017

Thanks for that, some interesting ideas going on there that I think would warrant more investigation, however I don't think they're achievable at the moment and other issues do take priority.
So from what I understand they're caching on a component basis, where as I've been mainly talking about output caching which I think a normal cache is still the best way to handle it.

But purely spit balling here, this might be something like how component caching might work in Angular:
Somehow mark a component as Pure, maybe assume that OnPush means pure(?), if it's Pure then cache it while it's @input()'s remain the same, then provide a pluggable cache storage so you can have a distributed/persistant cache if you like.
However something like this would have to be implemented right into platform-server, @vikerman opinions?

For the time being I still think normal caching is the way to go, take a look here https://www.youtube.com/watch?v=geckI2J6naM
@davideast explains how you can measure the performance of a Server Side Rendered app and how it can be improved, while he's showing Firebase the same applies for any system, more so ones with a CDN

@patrickmichalina
Copy link
Contributor

Right now we are using Varnish to cache the output of each page. This works great, but is definitely a more advanced setup considering we need to have varnish cluster setup and implement an X-Cache-Tag system based on all the API's used to render the page. As well as needing to bust the cache when a tag is updated in the CMS

More documentation or a caching layer would be a nice addition to the Universal platform

@naveedahmed1
Copy link
Author

Thank you @Toxicable and @patrickmichalina .

@Toxicable I completely agree that for output cache we already have different options; some already built in the platform for example for .net we have Outputcache, we can also use other options such as Varnish as suggested by @patrickmichalina. Similarly CDN is another options for content caching.

But, like in browser when the Angular app (without ssr) is initialized the subsequent navigation between different pages is really very quick, almost instant; reason being that for subsequent navigation, the same app instance is being used and we don't have to go through the bootstrap process again and again. I have absolutely no idea if this is achievable or not, but what if when on server and app is bootstrapped for first request, we could somehow cache that instance and then use that for subsequent requests.

@patrickmichalina
Copy link
Contributor

patrickmichalina commented Oct 14, 2017

@naveedahmed1 @Toxicable I thought I'd circle back and share some code that allows HTTP caching based on pages drawn with 1...N http requests. The HttpInterceptor linked below captures any API response that returns an entity with a "Cache-Tag" header.

As an example, lets say you hit https://my-cool-server/api/books/1 and it returned the book object with a header Cache-Tag: Book-1. The resulting page will be returned with the Cache-Tag: Book-1 header. Moreover, if multiple entities are returned, even from different endpoints, this will work. An example multi-entity page would look something like Cache-Tag: Book-1,Book-2,Blog-123,Article-43. In order to bust an HTTP cache, we would need to invalidate the endpoint by tag "Book-1" (or whatever entities in your database have been updated. The invalidation would be outside of angular of course.

https://github.com/patrickmichalina/fusebox-angular-universal-starter/tree/master/src/client/app/shared/http-cache-tag

@elwynelwyn
Copy link

+1 on the request from OP. Caching as a separate layer seems good, but the initial Angular bootstrap, on every incoming request, adds a lot of overhead. For very dynamic / realtime content caching is not always an option, causing many / all requests to end up in renderModuleFactory.

My ideal solution would possibly involve bootstrapping the app once, and then using that same app instance for multiple requests.

pseudocode:

const ngApp = bootstrapModuleFactory(....);

async function onRequest(ctx) {
    const state = {
        url: ctx.url,
        // somehow get other state into the app? e.g. StateTransferModule
    };

    const renderedHtml = await ngApp.render(state);
    ctx.body = renderedHtml;
}

This has the issue where the ngApp is potentially stateful, so it would only work if building the app in a particular way (e.g. with @ngrx/store you could just set the entire store state to your known good initialState).

@aescarcha
Copy link

I've played around renderModule function for a while and it looks like the performance would be really great if the module bootstrapping was done only once. Bootstrapping takes like 80% of the response time for me (measuring platform.bootstrapModule(module) promise resolution)

@naveedahmed1
Copy link
Author

@vikerman @CaerusKaru any progress on this?

@marcosybarraa
Copy link

This is an interesting point to keep in mind, did someone find any workaround?

@naveedahmed1
Copy link
Author

Does IVY helps in this regard in any way?

@patrickmichalina
Copy link
Contributor

@aescarcha were you using AOT when benchmarking?

@aescarcha
Copy link

@patrickmichalina no I wasn't, I built with

ng build --deploy-url='/' --prod --output-hashing none

@patrickmichalina
Copy link
Contributor

I would try it with AOT - this means less CPU cycles during a render since the component templates are already ready for output.

@naveedahmed1
Copy link
Author

I think '--prod' already has AOT enabled.

@nauraizmushtaq
Copy link

Hi,
I'm using Angular SSR with ASP.Net using SPA Services. Application became irresponsive when i pass 1K concurrent request using apache JMeter or WebSurg. Most of the time connection timeout shows up or application took more then 120 secs to load the home page.

It would be very helpful if someone could suggest a possible solution

@alan-agius4
Copy link
Collaborator

Closing as providing caching is not really in the roadmap of this project. Caching is a complex subject and there are already already a number of services that provide good caching such as CDNs.

@alan-agius4 alan-agius4 closed this as not planned Won't fix, can't repro, duplicate, stale Jun 7, 2023
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jul 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants