I’m considering MongoDB right now. Just so the goal is clear here is what needs to happen:
In my app, Finch (finchformac.com for details) I have thousands and thousands of entries per day for each user of what window they had open, the time they opened it, the time they closed it, and a tag if they choose one for it. I need this data to be backed up online so it can sync to their other Mac computers, etc.. I also need to be able to draw charts online from their data which means some complex queries hitting hundreds of thousands of records.
Right now I have tried using Ruby/Rails/Mongoid in with a JSON parser on the app side sending up data in increments of 10,000 records at a time, the data is processed to other collections with a background mapreduce job. But, this all seems to block and is ultimately too slow. What recommendations does (if anyone) have for how to go about this?
You’ve got a complex problem, which means you need to break it down into smaller, more easily solvable issues.
Problems (as I see it):
store that data somewhere locally until it gets sync’d to the
server.
into the database fast enough so that it doesn’t slow down.
You probably want to write this as some sort of API, for simplicity (and since you’ve got loads of spare processing cycles on the clients) you’ll want these chunks of data processed on the client side into JSON ready to import into the database. Once you’ve got JSON you don’t need Mongoid (you just throw the JSON into the database directly). Also you probably don’t need rails since you’re just creating a simple API so stick with just Rack or Sinatra (possibly using something like Grape).
Now you need to solve the whole “this all seems to block and is ultimately too slow” issue. We’ve already removed Mongoid (so no need to convert from JSON -> Ruby Objects -> JSON) and Rails. Before we get onto doing a MapReduce on this data you need to ensure it’s getting loaded into the database quickly enough. Chances are you should architect the whole thing so that your MapReduce supports your reporting functionality. For sync’ing of data you shouldn’t need to do anything but pass the JSON around. If your data isn’t writing into your DB fast enough you should consider Sharding your dataset. This will probably be done using some user-based key but you know your data schema better than I do. You need choose you sharding key so that when multiple users are sync’ing at the same time they will probably be using different servers.
Once you’ve solved Problems 1 and 2 you need to work on your Reporting. This is probably supported by your MapReduce functions inside Mongo. My first comment on this part, is to make sure you’re running at least Mongo 2.0. In that release 10gen sped up MapReduce (my tests indicate that it is substantially faster than 1.8). Other than this you can can achieve further increases by Sharding and directing reads to the the Secondary servers in your Replica set (you are using a Replica set?). If this still isn’t working consider structuring your schema to support your reporting functionality. This lets you use more cycles on your clients to do work rather than loading your servers. But this optimisation should be left until after you’ve proven that conventional approaches won’t work.
I hope that wall of text helps somewhat. Good luck!