-
Notifications
You must be signed in to change notification settings - Fork 68
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
Increase in CPU usage when performance_stats = true #488
Comments
https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+log+a+message > The block form allows you to create potentially complex log messages, but to > delay their evaluation until and unless the message is logged. This should help with troubleshooting #488 (Increase in CPU usage when performance_stats = true). PerformanceNotifier has a debug statement that we calculate each time we send a request. It builds a complex object and quite likely makes performance worse.
In #488 a lot of users mentioned that they see performance slowdown when they enable APM. My theory is that this is due to the fact that we log debug output. Converting `payload` to string is expensive. The Logger library offers another way to log: https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+log+a+message > The block form allows you to create potentially complex log messages, but to > delay their evaluation until and unless the message is logged. This should help with performance. I dropped a `binding.pry` in the context of the debug statement and ran benchmarks to verify this (logger level is `Logger::ERROR`): ``` [7] pry(#<Airbrake::PerformanceNotifier>)> ::Benchmark.ips do |ips| [7] pry(#<Airbrake::PerformanceNotifier>)* ips.report('inline') do [7] pry(#<Airbrake::PerformanceNotifier>)* logger.debug("#{LOG_LABEL} #{signature}: #{payload}") [7] pry(#<Airbrake::PerformanceNotifier>)* end [7] pry(#<Airbrake::PerformanceNotifier>)* ips.report('block') do [7] pry(#<Airbrake::PerformanceNotifier>)* logger.debug { "#{LOG_LABEL} #{signature}: #{payload}" } [7] pry(#<Airbrake::PerformanceNotifier>)* end [7] pry(#<Airbrake::PerformanceNotifier>)* end Warming up -------------------------------------- inline 3.006k i/100ms block 101.266k i/100ms Calculating ------------------------------------- inline 31.775k (± 2.3%) i/s - 159.318k in 5.016549s block 1.341M (± 6.4%) i/s - 6.684M in 5.001161s ``` This is a huge difference. Production apps usually don't debug production, so they shouldn't be suffering this performance hit. That said, the issue with slow debug output is not completely solved since apps that do use the `debug` severity, still suffer a performance hit. This should be resolved separately.
In #488 a lot of users mentioned that they see performance slowdown when they enable APM. My theory is that this is due to the fact that we log debug output. Converting `payload` to string is expensive. The Logger library offers another way to log: https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+log+a+message > The block form allows you to create potentially complex log messages, but to > delay their evaluation until and unless the message is logged. This should help with performance. I dropped a `binding.pry` in the context of the debug statement and ran benchmarks to verify this (logger level is `Logger::ERROR`): ``` [7] pry(#<Airbrake::PerformanceNotifier>)> ::Benchmark.ips do |ips| [7] pry(#<Airbrake::PerformanceNotifier>)* ips.report('inline') do [7] pry(#<Airbrake::PerformanceNotifier>)* logger.debug("#{LOG_LABEL} #{signature}: #{payload}") [7] pry(#<Airbrake::PerformanceNotifier>)* end [7] pry(#<Airbrake::PerformanceNotifier>)* ips.report('block') do [7] pry(#<Airbrake::PerformanceNotifier>)* logger.debug { "#{LOG_LABEL} #{signature}: #{payload}" } [7] pry(#<Airbrake::PerformanceNotifier>)* end [7] pry(#<Airbrake::PerformanceNotifier>)* end Warming up -------------------------------------- inline 3.006k i/100ms block 101.266k i/100ms Calculating ------------------------------------- inline 31.775k (± 2.3%) i/s - 159.318k in 5.016549s block 1.341M (± 6.4%) i/s - 6.684M in 5.001161s ``` This is a huge difference. Production apps usually don't debug production, so they shouldn't be suffering this performance hit. That said, the issue is not completely solved since apps that do use the `debug` severity still suffer a performance hit. This should be resolved separately.
In #488 a lot of users mentioned that they see performance slowdown when they enable APM. My theory is that this is due to the fact that we log debug output. Converting `payload` to string is expensive. The Logger library offers another way to log: https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+log+a+message > The block form allows you to create potentially complex log messages, but to > delay their evaluation until and unless the message is logged. This should help with performance. I dropped a `binding.pry` in the context of the debug statement and ran benchmarks to verify this (logger level is `Logger::ERROR`): ``` [7] pry(#<Airbrake::PerformanceNotifier>)> ::Benchmark.ips do |ips| [7] pry(#<Airbrake::PerformanceNotifier>)* ips.report('inline') do [7] pry(#<Airbrake::PerformanceNotifier>)* logger.debug("#{LOG_LABEL} #{signature}: #{payload}") [7] pry(#<Airbrake::PerformanceNotifier>)* end [7] pry(#<Airbrake::PerformanceNotifier>)* ips.report('block') do [7] pry(#<Airbrake::PerformanceNotifier>)* logger.debug { "#{LOG_LABEL} #{signature}: #{payload}" } [7] pry(#<Airbrake::PerformanceNotifier>)* end [7] pry(#<Airbrake::PerformanceNotifier>)* end Warming up -------------------------------------- inline 3.006k i/100ms block 101.266k i/100ms Calculating ------------------------------------- inline 31.775k (± 2.3%) i/s - 159.318k in 5.016549s block 1.341M (± 6.4%) i/s - 6.684M in 5.001161s ``` This is a huge difference. Production apps usually don't debug production, so they shouldn't be suffering this performance hit. That said, the issue is not completely solved since apps that do use the `debug` severity still suffer a performance hit. This should be resolved separately.
Hopefully fixes #488 (Increase in CPU usage when performance_stats = true) I noticed that dumping TDigest is very slow. Here's performance payload with TDigests: ``` Warming up -------------------------------------- 1.553k i/100ms Calculating ------------------------------------- 15.906k (± 3.0%) i/s - 80.756k in 5.082704s ``` And here's the same payload but without TDigests. ``` Warming up -------------------------------------- 4.443k i/100ms Calculating ------------------------------------- 45.498k (± 1.8%) i/s - 231.036k in 5.079495s ``` It makes sense to not dump TDigests because it's mostly clutter and it makes performance much worse.
Thanks for the useful info. I addressed these performance hits in #490 and #491. I don't have 100% confidence that this will resolve all the performance issues that you spotted on the graph but it is a significant improvement. I also suspect that you may run your app in the debug mode (debug logger severity). If that's the case, try to use In other news (unrelated to this issue but also about logging), check this out: https://github.com/airbrake/airbrake#logging P.S. We do mention the |
@kyrylo thanks for taking a look at this. We are not running our app in debug mode. I checked our log level and it is the default from Rails, which is "info". It makes me think that the severity of the message we saw in our logs is "info" or "error". |
Hey @lenon. Could you please check out airbrake v9.4.3? It contains a significant performance improvement. I would really appreciate if you could share how it impacts your app. |
Hi,
Last week we upgraded
airbrake
from 9.2.2 to 9.3.0 andairbrake-ruby
from4.4.0
to4.5.0
. After the deploy of this upgrade, we had an increase in CPU usage and latency times in our app which was fixed by settingperformance_stats
tofalse
. Here's our latency metrics:And CPU usage metrics from one of our VMs:
These metrics are from DataDog and are reported by
ddtrace
gem.We also had
**Airbrake: Your account does not accept APM data
logged hundreds of times per minute. Maybe that's because we need to decrease our log level, but I'm not sure.Everything looks normal in our app now, but I'm still opening this issue so you folks can check if there are some improvements that can be done to reduce CPU usage. I also think that would be good to mention something about
performance_stats
inairbrake
changelog.Additional info:
The text was updated successfully, but these errors were encountered: