Mongodb Top Design Considerations

Having worked with mongodb for a while now I have come to know a few things about how exactly mongodb works and some things to consider as you come up with the design of your mongodb implementation. Here is a list of things to keep in mind as you start to decide how you are going to design your mongodb implementation.

  • Document padding. Mongo adaptively learns if documents in a collection tend to grow, and if they do, it adds some padding so that the document has room to grow. This helps to prevent excessive movements on subsequent writes. This statistic is tracked separately for each collection.When designing a schema its important to understand how your document is going to grow. Lets look at a blog example. Lets say you run a very successful blog and some blogs receive 1000s of comments while others receive little to no comments. In this example you don’t want to embed your comments in the single json document you want to make a separate collection of comments and reference the blog by ID.
  • Indexes. By default all indexes should be created with background:true. Replica sets running version 1.8.x its important to remember the slaves ignore background:true and the index operation is a blocking operation, this is a concern only when secondary nodes are used to offload reads from the PRIMARY.
  • Write Concern. By default development should not code write concern into the application, it should be the operations team responsibility to work with the development team on the write concern requirement and implement it at the operations level (driver config file). The issue with write concern is that when improperly implemented all writes to a replica set could fail under maintenance conditions.
  • Schema Design Considerations. One company I worked for allowed for users to add “tags” to tasks, well tags could also be managed and renamed from the administrative interface. Well lets say you use the tag “red” in 1000s of tasks and you want to rename “red” to “blue” well you don’t want to update 1000s of documents you want to make a collection called tags and reference the collection and update the identifier associated to the red tag to be blue, this will be a single update vs 1000s of updates.
  • OpLog. The oplog is a queryable collection in the database “local”. In the /etc/mongodb.conf file there is an option “dbpath” mongodb will allocate 5% of the partition where dbpath lives for the oplog. The oplog size is configurable, and one big thing to remember about the oplog. If a delayed secondary is leveraged the oplog needs to be big enough to support transactions older then the configured delayed secondary time. So if the delayed secondary is one hour the oplog needs to be able to store atleast an hours worth of data so the delayed secondary can stay in sync.
  • Backup And Recovery. mongoexport doesn’t export the indexes.
  • Collections vs Databases. At one company I worked for we had something like 30,000 customers on the trial side of our application. During the design phase we discussed giving each “company / customer” their own database  because on the production side we had much fewer companies like 2,000. We had a big discussion about collections or databases per customer. Here are some things to think about if you encounter the same situation:
    • One set of datafiles. By leveraging a single database you will only have one set of data files. Why is this important you ask? Well in mongodb when a database is created an initial 64MB file is created called database_name.1 as the dataset grows more datafiles are created database_name.2 (128MB), database_name.3(512MB), database_name.4(1024MB), database_name.5(2046) the issue with a single database per customer is that there is a chance you will fill up to the 64MB limit pretty quickly and you don’t want to be in a situation where you are growing datafiles for multiple databases multiple times a day. It isn’t efficient from a performance standpoint or from a disk utilization standpoint.
    • Data Deletion. If a large customer requires data to be deleted and the customer has their own database the db files for that customer can simple be deleted, the database dropped and there is no impact to the rest of the data set. In a situation where there is a single database with multiple customers a disk compaction might need to be run to clean up any unused space in the data files.
    • db.stats(). If per customer it becomes easy to identify quickly stats can be easily pulled on a case by case basis. On the other hand it makes it hard to pull that information into a monitoring system if there are 10s of thousands of databases.
    • It might not make sense to split out customers per database or even collection at all for sharding purposes. Sharding happens per collection and If your craigslist lets say you would want to have similar entities (like a post and a user) in their own collection since that is going to be the bulk of your data. In my previous companies example it might make sense to have a “tasks” collection and have all companies tasks in the same collection then it becomes a lot easier to shard that collection without having to worry about how you are going to shard a collection in company A’s database or a collection in company B’s collection.
    • Another consideration is security. Uses are created per database so if you want to leverage security and have hundreds or thousands of databases it will become a nightmare to actually manage users for each db.
  • Rolling Data File Compaction. In mongodb when a record is deleted from the database or even moved due to document padding issues there is empty space left in the data file. While mongodb does attempt to reuse this empty disk space it isn’t always efficient at it.You will want to either add the following to a monitoring solution or run every so offten to check how efficiently mongodb is reusing disk space. This will report per database dataSize and storageSize. storageSize should always be bigger then dataSize but the difference should be less then 2GB when the difference between the two numbers grows larger then 2BG a rolling database compaction should be run.
     db._adminCommand("listDatabases").databases.forEach(function (d) {mdb = db.getSiblingDB(d.name); printjson(mdb.stats())})
Tags:

Add a Comment

Your email address will not be published. Required fields are marked *