Optimizing Your Meteor App for Live Queries

Live Query support is one of the major features of Meteor. A new Live Query is normally created when you return a cursor from a publication. Meteor will then reactively watch the query and send changes to the client.

Monti APM also tracks live queries created inside publications with the cursor.observe and cursor.observeChanges api's. Those api's are used by many packages that help with publications, such as zodern:relay or peerlibrary:reactive-publish.

What is the difference between an observer and live query?
Observers are how you create live queries in Meteor. Meteor doesn't use the term live query as much anymore, though it is used as the name for similar features in other projects. You can consider it as another name for observers.

In order to detect these changes, Live Queries do some amazing work behind the scenes. This work requires cpu cycles and make live queries a major factor affecting your app’s CPU usage and scalability.

However, the number of Live Queries itself does not cause many issues. These are the factors affecting the CPU usage:

Fortunately, there are ways to optimize our apps for better-utilized Live Queries. Let’s take a look.

Try to fetch as little as possible

This is the rule of thumb you can apply for any app. But you can’t decide which publication to optimize until you go live or launch a load test. After that, you can use Monti to find out which publications fetch a lot of data from MongoDB. Here’s how to:

Publications

Now you can see a set of publications sorted by the number of documents they fetched from MongoDB. Here are some optimizations you can apply to them:

Reuse observers as much as possible

When you create a Live Query, it’ll create an observer internally. Observers are responsible for watching changes in the DB and notifying the Live Query. However, if there is an existing observer for a similar query, Meteor won’t create a new observer.

To be a similar query, both the query and the options passed to Collection.find() should be the same.

Now let’s try to find some Live Queries to optimize

There are few things you can do to increase your observer reuse ratio. Take a look at this guide.

Optimize busy Live Queries

Another key point is to identify busy subscriptions and try to optimize them. A busy subscription is a subscription that triggers a lot of events, such as added, changed or removed, after it is created.

To identify busy subscriptions, with “Observer Changes: Live Updates”. These are the busy publications in your app.

Sort publications

We calculate Live Updates by combining all the Observer Changes events except “Added (Initially)”.

Now that you know the busy publications in your app, try to see whether there is any chance to reduce the changes in those queries. Sometimes, you can add a field filter and try to avoid unnecessary changes, but it’s totally dependent on your app.

Prevent unwanted oplog notifications

Meteor watches the MongoDB oplog to see changes happening in the MongoDB. Whenever something changes in the database, Meteor will receive the change as a notification. The notification is attached to a collection. Then, Meteor will forward this notification to most of the observers created for that collection.

Now let’s try to see whether we are getting unwanted oplog notifications or not.

For this, look at the trends of observer changes with the trends of oplog notifications. If there is a big difference in trends (but not in the count), that means there are some unwanted notifications.

Observer and Oplog changes

This is how you can check trends

This is usually because of doing bulk write operations in the DB. In that case, Meteor will also get those operations and try to handle them, even if there are no observers related to those updates. There is no direct fix; the only option is to avoid those bulk updates.

There are a few ways to improve this:


These are just a couple of ways to optimize your app for Live Queries. Some of these fixes are very easy to implement. Always try to fix the subscriptions that are used frequently; otherwise this may lead to premature optimization.