top | item 6513778

(no title)

joecarpenter | 12 years ago

Interesting enough, I found that Meteor is not production ready, in both current implementation (not mature) and some design decisions. I was thinking about writing blog post about it, but no idea when I'll have time to do it, so I decided to stop by.

I have experience with Meteor in production and had some serious performance-related problems. Not that they're not solvable, but some solutions kill some core design decisions of Meteor. Just in case - I didn't pick Meteor for the project, I was asked to help with it.

Anyway, here's short list:

1. Collection synchronization does not really work even for relatively small amounts of data (say 10k records).

- It does not make much sense to send few MB of initial data to the client. Paging API was moved to some distant future and you end up writing REST-like API on top of Meteor, which breaks idea of collection synchronization, which contradicts statement on their website - "no need to write REST APIs anymore". I don't say it is not usable at all, you just need to be really-really careful about what you send to client and it is easy to fail at this.

- SockJS (transport protocol used by Meteor) does not have rate-limiting built-in. If client connects using one of the polling transports and payload is too large to be received in 30 (? - vanilla SockJS uses 5) seconds, server drops connection thinking that client timed out. Partially, it is SockJS problem and partially it is Meteor problem, as Meteor will just send all outgoing data without caring if client is on slow connection. But because of previous point, generally it is bad idea to send large amount of data anyway.

- Server-side subscription API is very limited. Official documentation has following sample: reactively count number of admins in collection. This is done by listening on collection changes and counting admins by incrementing (when admin is added) and decrementing (when admin is removed) single variable. If there are 10k admins in database, increment function will be called 10k times.

2. Minimongo is interesting concept, but fails on many levels:

- It is MongoDB written in JS, but slow

- Does not have indexes ("client won't handle amounts of data for indexes to be viable"), aggregation, map reduce, etc. There's no official API to create index on server-side either.

- Its reactive - whenever model is changed, Meteor figures out which fields were changed and broadcasts changes to all listeners. And this is _not_ fast. Inserting 10k items to collection will take around 2 minutes on AWS large instance with node executable using 100% CPU.

- Because MongoDB is not "reactive", Meteor just polls collections every 5 seconds to see if they changed by outside application. I really hope it only tracks addition/deletion of records and not scanning through all rows in database during each polling iteration

- Meteor API is hiding MongoDB handle, but there's a way to get it (through hack) and use it directly. And it takes 3 seconds to insert same 10k items

3. Client-side is not as convenient as current MV* frameworks

- Meteor is using non-reactive templating engines and attempts to make them reactive. And this might be performance bottleneck, especially on mobile devices. When single variable changes, Meteor will re-render whole template. If you have some 3rd party plugins (like WYSIWYG editor, which injects own DOM markup), you have to wrap it with special blocks, which prevent Meteor from re-rendering them.

- As a result of previous point, DOM is not stable.

- Unlike AngularJS/Ember/etc, Meteor does not track individual variables. AngularJS does it by checking if variable changed in digest loop, Ember uses property-like system, etc. Meteor has global, flat namespace called "Meteor.session", where application stores _all_ reactive variables that can be referenced by their name. `Meteor.session.set('mymodule.hello', 10)`. It is hard to structure application, when core reactive part is just a singleton dictionary.

- Once you get used to bidirectional data binding between forms and models, it is hard to get away with events. But that's minor.

4. Overall architecture (nitpicking):

- Meteor API likes singletons. `Meteor.session`, `Meteor.methods`, `Meteor.templates`, etc. Single, flat namespaces everywhere

- Even though code can be written in a way it can run on both client and server, there are subtle core API differences. Like it is not possible to use `HTTP.get` on the client without callback, but it works on the server, just blocks the fiber. If you use callback on the server, you need to block the fiber manually (using future or fiber API), etc.

- No server-side templates. Yes, there's crawlable package for Meteor, but it is just PhantomJS (WebKit) that runs on the server and renders pages for crawlers. Yikes.

This pretty much sums my experience with Meteor.

discuss

order

dgreensp|12 years ago

Joe, your criticisms are spot-on (I work at Meteor), though I feel you are not comparing Meteor to any existing framework, but rather to Meteor in a couple years. Most web developers are quite used to getting by without reactive templates, bidirectional binding, and server-side rendering (which are only just starting to be used together), and in what framework do efficient client-side database indexes (which we haven't implemented yet) come standard, let alone map-reduce? What's wrong with a better-than-REST protocol that is more or less like REST in the worst case?

If you're objecting to the principle of offering the Mongo API or HTTP.get on the client when it's not exactly the same API, we feel the benefits outweigh the costs. The client-side functionality will only get better over time, though there will always be some things you can only do on the server.

Since 3 touches on my area: We're fixing the unstable DOM problem with fine-grained DOM updates. Also, the flatness of Session is not related to how dependencies are tracked. Meteor has a better dependency-tracking system than Angular or Ember; it's more flexible and doesn't require annotations to tell the framework what's happening.

chandika|12 years ago

I'm running a Meteor production app myself and found similar performance bottlenecks.

However, the Meteor community has really done some great work in solving some core issues and others are on the 1.0 roadmap.

Some comments on this below based on our own experience.

> 1. Collection synchronization does not really work even for relatively small amounts of data (say 10k records).

The issues around polling and how the server side cursors/observe works is definitely not perfect. Started using the SmartCollections package which ditches polling altogether and goes with the MongoDB OPLOG for synchonization. Has been performing well for us so far and solved many issues around performance.

https://github.com/arunoda/meteor-smart-collections

>2. Minimongo is interesting concept, but fails on many levels:

Really depends on the usecase. I'am not sure if there is any other alternative to MiniMongo at the moment for other frameworks.

The key thing is you really shouldn't expect to do many MB's of client data storage in your app.

>3. Client-side is not as convenient as current MV* frameworks

The key issue here is the how the DOM is re-written with the current rendering engine.

The new 'Meteor UI' rendering engine and component architecture is promising to solve this issues with html element level reactive-rendering as well as an method for proper UI components delivering similar capability to what Angular offers.

---

The framework is still growing up, but we are hard pressed to find something that delivers similar developer productivity.

Once you understand the framework and IF it fits your needs, Meteor can work well for production.

joecarpenter|12 years ago

> Started using the SmartCollections package which ditches polling altogether and goes with the MongoDB OPLOG for synchonization.

Yes, I'm aware about this package. However, in my case, I had to reactively count number of items in collection. SmartCollections does not have `observe` for server-side cursors and core Collection implementation is slow, so I decided to use `setTimeout` to check collection size every few seconds, which turned out to be much faster than generic collection implementation.

> The key thing is you really shouldn't expect to do many MB's of client data storage in your app.

True, it just contradicts point 003 on http://www.meteor.com/

Plus, I was also referring server-side. Application does not work with node.js MongoDB driver, it still goes through thin minimongo layer, which hides most of the driver API. And it is not fast either (due to reactivity) - see insert performance example.

Overall, I don't say it is not possible to run Meteor app in production (I have one). It is just there are alot of different quirks and gotchas in Meteor that should be worked out manually or with help of community-created packages. And all this information is mostly scattered around StackOverflow, Meteor bugtracker or in Meteor source code itself.

It is quite unpleasant to stumble upon collection synchronization performance when you have most of the application in place.

akbar501|12 years ago

Joe, thanks for providing details...it's very helpful.

Would you be willing to share a sample of the document schema that was causing problems when syncing 10k documents? I'm very curious to know if these were large or small docs, single schema vs. varying schema, etc.

joecarpenter|12 years ago

It is mostly number of documents and their size. Single schema.

There are no indexes, so whenever client wants to find something in synchronized collection, it'll have to scan through all documents. With 10k documents it was locking up DOM (it was very noticable).

If documents are large, client won't be able to connect to the server with any of the polling transports - initial synchronization time exceeds 30 seconds and SockJS will drop connection. This is partially solvable by having reverse-caching proxy (i.e. nginx) forcibly compress all polling SockJS responses.