In the Terminator movies, an artificial intelligence called Skynet wages war on humans, chugging along for decades creating robots and killing off humanity. This is the dream of most ops people—not to destroy humanity, but to build a distributed system that will work long-term without relying on people carrying pagers. Skynet is still a pipe dream, unfortunately, because distributed systems are very difficult, both to design well and to keep running.
A single database server has a couple of basic states: it’s either up or down. If you add another machine and divide your data between the two, you now have some sort of dependency between the servers. How does it affect one machine if the other goes down? Can your application handle either (or both) machines going down? What if the two machines are up, but can’t communicate? What if they can communicate, but only very, very, slowly?
As you add more nodes, these problems just become more numerous and complex: what happens if entire parts of your cluster can’t communicate with other parts? What happens if one subset of machines crashes? What happens if you lose an entire data center? Suddenly, even taking a backup becomes difficult: how do you take a consistent snapshot of many terabytes of data across dozens of machines without freezing out the application trying to use the data?
If you can get away with a single server, it is much simpler. However, if you want to store a large volume of data or access it at a rate higher than a single server can handle, you’ll need to set up a cluster. On the plus side, MongoDB tries to take care of a lot of the issues listed above. Keep in mind that this isn’t as simple as setting up a single mongod (then again, what is?). This book shows you how to set up a robust cluster and what to expect every step of the way.
Sharding is the method MongoDB uses to split a large collection across several servers (called a cluster). While sharding has roots in relational database partitioning, it is (like most aspects of MongoDB) very different.
The biggest difference between any partitioning schemes you’ve probably used and MongoDB is that MongoDB does almost everything automatically. Once you tell MongoDB to distribute data, it will take care of keeping your data balanced between servers. You have to tell MongoDB to add new servers to the cluster, but once you do, MongoDB takes care of making sure that they get an even amount of the data, too.
Sharding is designed to fulfill three simple goals:
We want an application to have no idea that what it’s talking to is anything other than a single, vanilla mongod.
To accomplish this, MongoDB comes with a special routing process called mongos. mongos sits in front of your cluster and looks like an ordinary mongod server to anything that connects to it. It forwards requests to the correct server or servers in the cluster, then assembles their responses and sends them back to the client. This makes it so that, in general, a client does not need to know that they’re talking to a cluster rather than a single server.
There are a couple of exceptions to this abstraction when the nature of a cluster forces it. These are covered in Chapter 4.
A cluster can’t guarantee it’ll always be available (what if the power goes out everywhere?), but within reasonable parameters, there should never be a time when users can’t read or write data. The cluster should allow as many nodes as possible to fail before its functionality noticeably degrades.
MongoDB ensures maximum uptime in a couple different ways. Every part of a cluster can and should have at least some redundant processes running on other machines (optimally in other data centers) so that if one process/machine/data center goes down, the other ones can immediately (and automatically) pick up the slack and keep going.
There is also the question of what to do when data is being migrated from one machine to another, which is actually a very interesting and difficult problem: how do you provide continuous and consistent access to data while it’s in transit? We’ve come up with some clever solutions to this, but it’s a bit beyond the scope of this book. However, under the covers, MongoDB is doing some pretty nifty tricks.
As your system needs more space or resources, you should be able to add them.
MongoDB allows you to add as much capacity as you need as you need it. Adding (and removing) capacity is covered further in Chapter 3.
These goals have some consequences: a cluster should be easy to use (as easy to use as a single node) and easy to administrate (otherwise adding a new shard would not be easy). MongoDB lets your application grow—easily, robustly, and naturally—as far as it needs to.