Hi guys, certain users complain that our Meteor app is slow. Any tips for instrumenting, so we can answer
- how big is the issue (number of user affected)
- what is the average time that it take to load each page
- what is the lowest time?
- what is the longest time?
- What are the bottlenecks?
- How can we make these pages faster?
Thank you in advance,
2 Likes
I’m hoping someone can answer this more fully than I can, as we’ve had similar complaints on occasion, and debugging can be a challenge.
In general, we’ve enabled logging of all methods and publications outside of Kadira, so we can ensure we have a full record of every call, whether it completes successfully and how long it took - we needed similar for audit purposes, so the overhead was worthwhile. We’ve also enabled page level logging (as part of FlowRouter) though this is more for usage than for performance monitoring. Beyond that, high quality QA testing in a “production like” environment are beneficial.
To attempt to answer your questions in order:
-
Logging will help here, identify if the problem is all data to a specific view, or to a specific component. Then identify how many users and how frequently they access that component by logging each page view. If the problem is content specific you’ll need to merge this with a database query which identifies the content in question. For example: If you find that all users who view a post more than one year old experience the problem, you need to take the intersection of users who view a post, with those views where the post is more than one year old - most logging systems can’t do this with a single query.
-
This is incredibly subjective. Assuming you’re talking about a standard single page app, If all your subscriptions happen at the router level you can measure the time take from the triggersEnter
call (or equivalent) to the first time the subscriptions are ready. If you have component level subscriptions, this is much harder.
-
read above + logging
-
read above + logging
-
again, incredibly subjective - once you’ve identified the problem view (and potentially the problem data set), take a look at it, see how much time is spent waiting for subscriptions (and how many frames of data are sent across the websocket) - be sure to test in a production like environment, queries of a local server with a local database obscure the network delay between client -> server and server -> DB. Similarly, development environments often have small datasets, so the benefits of efficient indexes are masked. If you find the delay is with subscriptions (or method calls) check if the problem is with the DB queries, the processing on the server, or the amount of data sent over the websocket.
-
In general:
- Reduce reactivity - only recompute what needs to be.
- Do all of your blaze rendered items have
_id
? Blaze has efficiency improvements on this
- Do you over-utlise
ReactiveDict
? it’s comparison is based on EJSON, so serializing large arrays of complex objects takes a long time - it’s great for strings, numbers or dates, but otherwise, use a custom set of ReactiveVar
s, or use Tracker.Dependency
manually.
- How much data is being sent over the websocket (bonus, are all your clients even using websockets?)
- ensure you only subscribe to the fields you require on documents, and only return the documents you need (there are a few exceptions to this rule).
- are you reactively triggering method calls? Do you need to be. Consider something like
Tracker.guard
- How much work do your methods/publications do? Calling
Meteor.user()
will call the DB each time!
I highly recommend taking CPU profiles to understand performance problems: https://github.com/qualialabs/profile/
1 Like