-
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
Performance logging causes extra unnecessary queries to the database after a request has finished #550
Comments
I believe the error where DEBUG logs are still being evaluated is coming from
Since I don't have an Airbrake logger configured I'm getting this default logger that should throw away all logs. The README says that the default log level is Created a new standard library Logger with just one argument defaults to log-level
Note:
This matches the docs for Ruby 2.4, 2.5, 2.6, and 2.7:
To get a
|
Quick response: are you running airbrake-ruby |
Issue #550 mentions that README states that our default logger is `Logger::WARN`, however the code never sets that level. The default value is `Logger::DEBUG`, which is unwanted, since it generates a lot of clutter.
Issue #550 mentions that README states that our default logger is `Logger::WARN`, however the code never sets that level. The default value is `Logger::DEBUG`, which is unwanted, since it generates a lot of clutter.
Issue #550 mentions that README states that our default logger is `Logger::WARN`, however the code never sets that level. The default value is `Logger::DEBUG`, which is unwanted, since it generates a lot of clutter.
Yeah, that was a bug/mishap. I dealt with it in #551, thanks! As for the other issue, something doesn't sound right to me. As mentioned in #550 (comment) commit 6cb2bc9 is not a part of any release yet. My assumption is that you are running airbrake-ruby from Next, you say that we print This is not true. On master We print airbrake-ruby/lib/airbrake-ruby/performance_notifier.rb Lines 155 to 167 in ce9ba7a
In airbrake-ruby v4.13.0 (and v4.12.0 as well) we do print airbrake-ruby/lib/airbrake-ruby/performance_notifier.rb Lines 155 to 159 in 628c77e
Please clarify this bug report. As of now I see a few major inconsistencies, which complicate understanding of the issue. My current understanding is that there's a bug present in the current release, which was resolved on |
We also noticed a catastrophic increase in resource consumption recently when updating the |
Thank you for the quick response! And sorry for the confusion on my part -- I got myself turned around in git history. I can see that the git tag for What I should have said was that in my local testing applying the later commit 6cb2bc9 solves the issue because it only logs Reverting from |
Ok, I think I understand now why we weren't seeing the extra queries and resource usage in In
In
And from I don't think f2726a6 is wrong by any means. It just had an unintended side-effect when combined with the default log level being DEBUG. |
Thanks for the extra details and pinning down this bug. It makes sense that the class conversion is the culprit. It was hard to predict, though, as it seemed to be a harmless change. In theory we could define a custom inspect on model classes such as I am going to close this issue and release a new version of the library. |
At work we started noticing a huge increase in our Rails app's memory usage in production. The kernel would OOM-kill our ruby processes as they seemed to use more and more memory over time without bound.
Short version: I believe 6cb2bc9 is the cause and I believe there are at least two bugs here:
payload
is causing instance variables in Controllers that are ActiveRecord relations that haven't actually "instantiated" or "resolved" to query the database. This behavior is the root cause of the increase in memory usage for us. This behavior isn't present when I revert 6cb2bc9.logger.debug
would not execute. It appears that the block is eagerly executing regardless of the log level.Long version:
After putting in some mitigations, configuration changes, code changes, and analyzing the slow query log for inefficient queries, we discovered that some of these expensive DB requests were being made after a response had already been rendered and served to the client. Furthermore, the expensive queries coming from the slow query log didn't appear to correspond to an incoming request. We were also seeing queries that didn't correspond to any direct uses in our app. But there would be the queries generated from ActiveRecord relations stored in Controller or Pundit policy instance variables. Our app would
LIMIT
, paginate, filter, or otherwise restrict the base query but our code would never call the expensive ActiveRecord query itself.Further investigation demonstrated that reverting the Gems
airbrake
10.0.1 &&airbrake-ruby
4.13 toairbrake
10.0.0 &&airbrake-ruby
4.12 solved the extra expensive queries and solved our memory issue problems. We've since deployed that revert everywhere in production and haven't seen any more memory issues.I was able to reproduce this in my local development environment by enabling Airbrake and performance stats gathering. I'd hit a simple app endpoint that would render a JSON response and a few seconds later would see additional queries from both the Rails server logs and from the MySQL general log. The MySQL general log would show these queries coming seconds later on a completely separate connection than the queries to generate the original response. For example:
The rails server log showed the same thing -- queries coming after the response had rendered:
We have configuration to attach a UUID to the Rails logger for each request. What made debugging this very difficult is that there is no UUID attached to these logs, the queries trigger after a request-response pair, and Airbrake does not report the queries. In my development environment these queries are fast since I've emptied my tables but in production these were killing performance and eating tons of memory.
Walking through the
airbrake
andairbrake-ruby
code I determined this was coming from Airbrake'sActionControllerPerformanceBreakdownSubscriber
. Since performance stats are enqueued after a response is complete and sent asynchronously this explains the behavior we were seeing -- the DB connections would sometimes come from another Ruby thread and they were not directly associated with any incoming request, so no UUID.Delving a bit further, I found that this was coming from
airbrake-ruby
and eventually fromlib/airbrake-ruby/performance_notifier.rb
's private methodsend
.By the time we're in this method
payload
is aHash
that contains references to the Controller objects that handled the request which themselves contain references to the instance variables that were set during the request.I confirmed that by commenting out the
logger.debug
line I no longer saw the extra DB queries trigger. I also don't see the extra DB queries by completely reverting 6cb2bc9 we only log outresource_hash
. That explains why reverting toairbrake
10.0.0 /airbrake-ruby
4.12 fixed our memory issues.While I was debugging here I believe it is the act of
string
-ifyingpayload
that causes the ActiveRecord relation objects to "resolve" and query the database.I was surprised that the block given to
logger.debug
was triggering because the whole purpose of the block is to defer the expensive computation or avoid it entirely if our debug log level wouldn't print it out.So I think there are at least two bugs here --
logger.debug
call is still executing the code in the block.payload
hash is incidentally causing other ActiveRecord relation objects to resolve.(Note: we've also seen for this first time a
can't add a new key into hash during iteration
reported in #545. I suspect this might be related if in a separate thread the performance stats notifier is trying to iterate over objects in a Controller that might be handling other requests simultaneously.)More notes:
In my example
payload
has 11 keys, the first 9 of which areAirbrake::Query
, the tenth is anAirbrake::Request
, and the last is anAirbrake::PerformanceBreakdown
. I can verify that it's string-ifying this last one that is causing the queries to trigger.None of the fields marked
attr_accessor
onAirbrake::PerformanceBreakdown
appear to be problematic. It's the@stash
instance variable that holds a reference to both therequest
and theuser
. Theuser
hash is only a single level and not a problem. So it's coming fromrequest
which is anActionDispatch::Request
. The request has an@env
which has a keyaction_controller.instance
which has references to every instance variable on the controller. Trying to turn these instance variables in to strings causes the ActiveRecord relation to "resolve" and query the DB.In my opinion I don't think we should be logging this at all -- the
request
has references to the top-levelRails.application
, every piece of middleware, and all configuration settings. I don't think this will be too useful during debugging and could potentially trigger other ActiveRecord queries to resolve.The text was updated successfully, but these errors were encountered: