We need a community resource for well known, and maybe not so well known performance bottlenecks that are specific to Meteor that may not be familiar to people outside of Meteor or even who just haven’t tried to scale.
I have an application that has roughly 50 users on at a time, with occasionally up to 160.
I’m running this application on a small server but it normally has no problems. That is until a recent update brought the entire thing down. There were no errors to speak of during this time, so the only explanation was performance problems.
It turned out that I was trying to store a very deep object (multiple arrays within many more arrays) in Mongo. I was going on the principle of I can store anything I want in there and only sanitize in my publications (using fields selectors).
In reality however, the rate at which I was trying to update this object brought my app to it’s knees. Repeatedly.
Filtering off that very deep object (which I only need for another purpose and server side only) before ever trying to put it in the database solved my problem.
Some of the other performance gotchas that I’m familiar with (some from bulletproof meteor)
- Low observer reuse. Making your Mongo finds too fine grained can be helpful since it keeps your client from having too dang many records, it hurts in that it increases both ram and cpu usage as each client ends up creating another observer on your database.
- Reactivity everywhere. Some things don’t benefit from reactivity. Other things reactivity would have to be too well coordinated. Reactivity also costs because each change causes every function that depended on the changed value to re-run.
- Bulk writes. This is in the pipe to be cleaned up. Right now, Meteor triggers all affected observers on EVERY write, but also has to traverse every observer. It causes writes to run very slow and to make observers take forever if there are a lot of writes happening when they start. This could really prevent your “ready” from being called
- Excessive publications. Is every client who subscribes to subscription A going to need subscription B? Or at the very least is subscription B a cheap add-on to subscription A? If so, COMBINE THEM. One Subscription to rule them all!
- Side effects in subscriptions. It is very tempting to have publications go off and do other things when they are setting up (for example make calls to another application/api make a bunch of log entries, indicate in some database where that user has been). Don’t. Subscriptions are simply ways to coordinate data between server and client. Use methods where you want side effects.
- Excessive use of this.unblock. Unless your methods are waiting a long time on a lot of async processes, this.unblock is not ideal. It has a tendency to pollute the event loop and can lead to at least some race conditions. Also, this.unblock used in bulk can allow a single connection to trigger a large number of operations on your server filling up the event loop and keeping other connections from getting through.
What are your biggest performance gotcha’s that you’ve had to work through?