Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve plugin bundle load time #55241

Closed
joshdover opened this issue Jan 17, 2020 · 10 comments
Closed

Improve plugin bundle load time #55241

joshdover opened this issue Jan 17, 2020 · 10 comments
Assignees
Labels
Feature:New Platform performance Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc

Comments

@joshdover
Copy link
Contributor

When auditing the startup performance of the New Platform Core on the client, I noticed that the bulk of the time is spent loading plugin bundles (~1.5s locally).

Currently, plugin bundles are not loaded until the PluginsService#setup method is called, which reads the list of enabled plugins from injected metadata and then adds <script> tags to the page for each plugin that needs to be loaded. This has two problems:

  • It delays loading these scripts until after the vendor, common, and core chunks have been loaded.
  • It requires a separate connection for each plugin bundle, which is capped by the browser to 6 connections at a time. For many reasons, Kibana cannot use http2 at this time, so we'll need to do something more clever to optimize this.

This could be made faster by:

  • Loading these bundles eagerly. We already know ahead of time which bundles will need to be loaded based on the currently enabled plugins. We should be able to embed this information into the bootstrap script itself so that these plugins are already available by the time CoreSystem is invoked.
  • Loading these bundles in a single request, rather than one request per-plugin. We should be able to concatenate all of the plugin bundles into a single file that can be loaded at once, on a single connection. This concatenated bundle is something that will need to be produced at runtime rather than at optimize time, since the new optimizer will not ship in production. We may be able to optimize this a bit by producing this file when Kibana starts up based on the enabled UI plugins.
@joshdover joshdover added Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc Feature:New Platform performance labels Jan 17, 2020
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-platform (Team:Platform)

@mshustov
Copy link
Contributor

mshustov commented Jan 19, 2020

We already know ahead of time which bundles will need to be loaded based on the currently enabled plugins. We should be able to embed this information into the bootstrap script itself so that these plugins are already available by the time

Just a side note: we will have the same problem with CSS files. The solution should work for both types.

I noticed that the bulk of the time is spent loading plugin bundles (~1.5s locally).

Should we measure delays for the prod bundle after minification and gzip to understand how critical the problem is?

Kibana cannot use http2 at this time

it looks like a correct way. HTTP2 issue #7104

@pgayvallet
Copy link
Contributor

Loading these bundles eagerly. We already know ahead of time which bundles will need to be loaded based on the currently enabled plugins. We should be able to embed this information into the bootstrap script itself so that these plugins are already available by the time CoreSystem is invoked.

I this a significant gain though? What is the delay between dom-ready and pluginService.setup() ? Also by adding them all in the initial dom, won't we be trading loading time with a proper loading screen with 'dom-ready' delay, therefor degrading actual user experience?

Loading these bundles in a single request, rather than one request per-plugin

Sure is an improvement

@mshustov
Copy link
Contributor

mshustov commented Apr 2, 2020

In 7.7 Kibana performs 145 requests on bootstrap (as per #62263 (comment)). There are some quick wins that we can do to reduce the number of downloaded artifacts:

  • 37 CSS files. Can we concatenate them?
  • 86 js files. of which:
    • 54 plugin bundles. Should not have runtime dependencies on each other. Can it be concatenated as well?
    • 25 icon files. Can be inlined?

@spalger
Copy link
Contributor

spalger commented Apr 3, 2020

the icon files are now bundled into the @kbn/ui-shared-deps in #62364 (comment), it was an accident at first but I think I'll keep it.

@joshdover
Copy link
Contributor Author

37 CSS files. Can we concatenate them?

This will be dramatically cut down by #61011 so probably not worth revisiting right now. When we render NP apps, we will no longer load CSS files from DLLs or legacy uiExports.

@joshdover
Copy link
Contributor Author

54 plugin bundles. Should not have runtime dependencies on each other. Can it be concatenated as well?

This seems like a prime target for optimization right now. These shouldn't have any problems being concatenated, though you may need to be careful with the new shared bundles with esUiShared and kibanaUtils.

The tricky part is figuring out the right approach. Can we get away with reading all of these files at request time or is this too slow do we need to pre-concatenate these? If we need to pre-concatenate at server boot time, we'll need to either 1) always re-run this process on every startup; or 2) only re-run when the list of enabled plugins changes.

I took a quick try at this a few weeks back and ran into issues in development with serving a file that was over 25MB. The server would stop streaming the bytes to the client after it hit a certain number. I didn't go deep into figuring out why this was happening, but I did rule out the public path replacement logic we have. Increasing the stream buffer size also did not fix.

Though that issue on its own may not be worth solving because we probably will need to chunk this concatenated file out anyways. We've encountered bugs in the past where browsers won't cache files over a certain size in incognito/private mode. Chunking into smaller files helps.

This feels like a goldilocks problem...not too small, not too big, juuuust right 😄

@pgayvallet
Copy link
Contributor

The tricky part is figuring out the right approach. Can we get away with reading all of these files at request time or is this too slow do we need to pre-concatenate these?

As it only depends on the enabled plugins, I don't see any reason not to do it at startup?

we'll need to either 1) always re-run this process on every startup; or 2) only re-run when the list of enabled plugins changes.

Either is fine, even if imho this is not going to really be resource consuming and therefor probably way simpler to do with option 1)

I took a quick try at this a few weeks back and ran into issues in development with serving a file that was over 25MB. The server would stop streaming the bytes to the client after it hit a certain number.

One option would be to define a limit on how big a file can be, and then generate multiple files, by switching to a new aggregated file once we hit the limit. This still is a little more complex than generating only one file, as the client needs to have the information of the names / number of files to fetch them, so the info will need to be sent from the server or present somewhere in the html template.

@mshustov
Copy link
Contributor

This will be dramatically cut down by #61011 so probably not worth revisiting right now. When we render NP apps, we will no longer load CSS files from DLLs or legacy uiExports.

That's true. However, most apps are still in LP for a release or two, so this improvement still could be beneficial.

@mshustov
Copy link
Contributor

superseded by cache busting in #64414

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:New Platform performance Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc
Projects
None yet
Development

No branches or pull requests

5 participants