elastic / elastic/logstash

Understanding the performance of bin/logstash-plugin install command

Open
#5,523 5 comments 0 reactions 0 assignees View on GitHub
performance improvements plugin manager
Dominant language
Java
Stars
14.9k
Forks
3.5k
Avg merge
19h 14m
Merged PRs (30d)
63

Description

One of the common comments and concerns about logstash is it's performance, in this issue we try to understand the performance concerns involved in installing a plugin.

Here is a sample execution trying to install the generator input.

```
skywalker% JRUBY_OPTS="--profile" ./bin/logstash-plugin install logstash-input-generator
Profiling enabled; ^C shutdown will now dump profile info
Validating logstash-input-generator
Installing logstash-input-generator
Installation successful

main profile results:
Total time: 17.12

total self children calls method
----------------------------------------------------------------
15.18 0.00 15.18 1 Clamp::Command.run
15.18 0.00 15.18 2 Clamp::Command#run
15.18 0.00 15.18 1 Clamp::Subcommand::Execution.execute
15.18 0.00 15.18 1 LogStash::PluginManager::Install#execute
14.51 0.06 14.45 26035 Array#each
9.39 0.00 9.39 1 LogStash::PluginManager::Install#install_gems_list!
9.39 0.00 9.39 1 LogStash::Bundler.invoke!
9.27 0.00 9.27 5093 Proc#call
9.27 0.00 9.27 1 LogStash::Bundler.execute_bundler_with_retry
9.27 0.00 9.27 1 LogStash::Bundler.capture_stdout
9.27 0.00 9.27 1 Kernel.loop
9.27 0.00 9.27 1 LogStash::Bundler.execute_bundler
9.27 0.00 9.27 1 Bundler::CLI.start
9.27 0.00 9.27 1 Bundler::Thor::Base::ClassMethods.start
9.27 0.00 9.27 1 Bundler::Thor.dispatch
9.26 0.00 9.26 1 Bundler::Thor::Invocation.invoke_command
9.26 0.00 9.26 1 Bundler::Thor::Command#run
9.26 0.00 9.26 73 BasicObject#__send__
9.26 0.00 9.26 1 Bundler::CLI#install
9.26 0.00 9.25 1 Bundler::CLI::Install#run
9.15 0.00 9.15 1 Bundler::Installer.install
9.15 0.00 9.15 1 Bundler::Installer#run
8.29 0.00 8.29 1 Bundler::Installer#install_sequentially
7.64 0.00 7.64 72 Bundler::SpecSet#each
7.54 0.00 7.54 64 Bundler::Installer#install_gem_from_spec
7.51 0.00 7.51 3 Bundler::Source::Path#install
7.51 0.00 7.51 3 Bundler::Source::Path#generate_bin
7.38 0.00 7.38 6 Bundler::SharedHelpers.chdir
7.38 0.00 7.38 12 MonitorMixin.mon_synchronize
7.38 0.00 7.38 12 Dir.chdir
7.36 0.00 7.35 9 Bundler::Source::Path#run_hooks
7.33 0.00 7.33 3 Jars::Installer#vendor_jars
7.33 0.00 7.33 1 Jars::Installer#do_install
7.32 0.00 7.32 1 Jars::Installer#install_dependencies
7.32 0.00 7.32 1 Jars::MavenExec#resolve_dependencies_list
7.31 0.00 7.31 1 Maven::Ruby::Maven#exec
7.31 0.00 7.31 1 RubyMaven.exec
7.31 0.00 7.31 1 Bundler.with_clean_env
7.31 0.00 7.31 1 Bundler.with_original_env
7.31 0.00 7.31 1 RubyMaven.launch
7.30 0.00 7.30 1 Maven.exec
7.30 7.30 0.00 1 Kernel.system
5.78 0.00 5.78 1 LogStash::PluginManager::Install#verify_remote!
5.78 0.00 5.78 1 LogStash::PluginManager::Install#validate_plugin
5.78 0.00 5.78 1 LogStash::PluginManager.logstash_plugin?
5.57 0.00 5.57 1 Gem::SpecFetcher#spec_for_dependency
5.09 0.00 5.09 1 Gem::SpecFetcher#search_for_dependency
4.76 0.01 4.75 10790 Kernel.send
4.68 0.00 4.68 1 Gem::SpecFetcher#available_specs
4.68 0.00 4.68 1 Gem::SourceList#each_source
```

we can see how the biggest offenders in terms of execution time are:
- `LogStash::PluginManager.logstash_plugin?` taking 5.78s over a total of 17.12s what means a 33.76%
- `Bundler::Source::Path#run_hooks` basically the executions of `jar-dependencies` installation hook, this takes around another 34% of execution time, thinking of having a zero time logstash plugin validation.

Performance impact re the jvm looks around taking 1.94s of a total of 17.12s, so around 11%.

This two as the bigger offenders in terms of performance might be related to #4971 where @wiibaa shared the performance penalties of using `net::http`. Possible strategies I see so improve the performance of this command are:
- Upgrade current bundler version to the latest one, this might have some performance benefits and let us manage bottlenecks easier.
- Implement an improved version of `LogStash::PluginManager.logstash_plugin?`, probably using manticore as the fastest way do request stuff from the web.
- Let the jar-dependency hook only be run when it makes sense, see the profile is for the generator input that does not require any jar.

This will highly benefit:
- Our current testing infrastructure as we're running the plugin installation many times.
- The improvement on bundler and the post install hooks might help also the package build time.
- Even if it's not a common operation, the end user as it will have a faster installation command.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.