meteor-feature-requests icon indicating copy to clipboard operation
meteor-feature-requests copied to clipboard

Use Meteor user data from MergeBox to fill Meteor.userId(), thus bypassing the need to query the database for every request

Open msavin opened this issue 7 years ago • 9 comments

Buy two facts, get one opinion free:

Fact: Every Meteor connection makes a subscription for the Meteor.user() document

Fact: Every subscription is cached to the server that the client is connected to into the server-side cache (MergeBox).

Opinion: Instead of querying the database every time that Meteor.user() is used, we should first try to retrieve it from the server-side cache (MergeBox).


The implementation can be really simple. If the document is in MergeBox, we can use that first. If not, we can query the database. Additionally, we can pass an argument into Meteor.user() to tell it to get the real document instead of the cache. Alternatively, for improved backwards compatibility, we could inverse this design, where Meteor.user(true) would get us the cached document instead of querying the database.

One situation where I could see this greatly improving performance is roles-based authorization and similar. We can attach roles information to the user document, publish that to the client, and then easily verify it for every Method call.

That can be a really good argument for Meteor's stateful design, and for an application that has say 10,000 concurrent users, it can cut down on thousands of database requests per second.

msavin avatar Aug 24 '18 10:08 msavin

Update: Proof of concept

https://github.com/msavin/userCache

msavin avatar Aug 24 '18 10:08 msavin

To me it seems like a very interesting idea. In my app this is exactly the case. Recently needed to switch over to more fine grained roles and therefore switched from userId() to user() checks inside most methods to check for role booleans inside the user document. Seemed like rather wasteful to pound the DB for the same doc all the time with each method call, especially since in most apps the roles data will change very infrequently, if at all.

If this can be done based on existing server side caching, then perhaps the magic trifecta is in reach - (1) with not too much work get (2) potentially big performance benefits while (3) remaining backwards compatible. Caching always introduces strange quirks, but @msavin 's suggestions seems to address this well - having the default option be a call to the DB, as it is now, and users needing to opt in to caching.

jkasevits avatar Aug 26 '18 11:08 jkasevits

Woot - setting up the POC was way easier than I expected, and given the package's tiny size, I think it should work just fine.

Having played with it some more - I think this can be fine as a third party package, and I would be happy to maintain it and promote it.


@vooteles thanks for the positive words. It would be great to see if you can implement Meteor.userCache into a few method calls and see how it works. Indeed - it sounds like this can help you cut down maybe even on half of your database calls.

The only thing that you might need to look out for is ensuring that the data you are trying to retrieve from the cache is being pushed up to the client.

msavin avatar Aug 26 '18 16:08 msavin

Wow. Very fast work I must say. I can try it out, but unfortunately not very quickly (and the app is not in production and not APM is set up, so there should be much better sources of data in the community). But regardless of that, would be interesting to see what the fine folks at MDG think about this. Especially since I do have a rather strong allergy towards third party packages. Yes it is only a few lines of code, but that should be exactly the reason why it could be (barring any issues that I might not be seeing here) a good candidate for Meteor's core.

jkasevits avatar Aug 26 '18 16:08 jkasevits

New version is up - it now monkey-patches the Meteor.user field and provides some new options.

There's also a new discussion on the forums: https://forums.meteor.com/t/introducing-meteor-usercache-the-one-simple-trick-that-can-save-you-millions-of-database-requests/45336/6

msavin avatar Aug 26 '18 22:08 msavin

I agree, a PR to OEM would be more acceptable.

Shying away from 3rd party libs these days.

aadamsx avatar Aug 26 '18 22:08 aadamsx

Are you sure mergebox is the best place for this? Why not observe demultiplexer's _cache which also contains documents?

mitar avatar Sep 09 '18 08:09 mitar

@mitar I've not come across it. Can you make a sample of how it might work?

msavin avatar Sep 22 '18 11:09 msavin

See here.

So I think you can get this from observe's handle: handle._multiplexer._cache.

mitar avatar Sep 23 '18 04:09 mitar