Replica Sets Part 1:
Master-Slave is so 2009

Replica sets are really cool and can be customized out the wazoo, so I’ll be doing a couple of posts on them (I have three written so far and I think I have a few more in there). If there’s any replica-set-related topic you’d like to see covered, please let me know and I’ll make sure to get to it.

This post shows how to do the “Hello, world” of replica sets. I was going to start with a post explaining what they are, but coding is more fun than reading. For now, all you have to know is that they’re master-slave with automatic failover.

Make sure you have version 1.5.7 or better of the database before trying out the code below.

Step 1: Choose a name for your set.

This is just organizational, so choose whatever. I’ll be using “unicomplex” for my example.

Step 2: Create the data directories.

We need a data directory for each server we’ll be starting:

$ mkdir -p ~/dbs/borg1 ~/dbs/borg2 ~/dbs/arbiter

Step 3: Start the servers.

We’ll start up our three servers:

$ ./mongod --dbpath ~/dbs/borg1 --port 27017 --replSet unicomplex/
$ ./mongod --dbpath ~/dbs/borg2 --port 27018 --replSet unicomplex/
$ ./mongod --dbpath ~/dbs/arbiter --port 27019 --replSet unicomplex/

Step 4: Initialize the set.

Now you have to tell the set, “hey, you exist!” Start up the mongo shell and run:

MongoDB shell version: 1.5.7
connecting to: test
> rs.initiate({"_id" : "unicomplex", "members" : [
... {"_id" : 0, "host" : "localhost:27017"}, 
... {"_id" : 1, "host" : "localhost:27018"}, 
... {"_id" : 2, "host" : "localhost:27019", "arbiterOnly" : true}]})
{
        "info" : "Config now saved locally.  Should come online in about a minute.",
        "ok" : 1
}

rs is a global variable that holds a bunch of useful replica set functions.

The message says it’ll be online in about a minute, but it’s always been ~5 seconds for me. Once you see the following line in one of the logs:

replSet PRIMARY

…your replica set is ready to go!

Playing with the set

One of the servers will be master, the other is a slave. You can figure out which is which by running the isMaster command in the shell:

> db.isMaster()
{
        "ismaster" : true,
        "secondary" : false,
        "hosts" : [
                "localhost:27017",
                "localhost:27018",
        ],
        "arbiters" : [
                "localhost:27019"
        ],
        "ok" : 1
}

If db isn’t primary, the server that is will be listed in the “primary” field:

> db.isMaster()
{
        "ismaster" : false,
        "secondary" : true,
        "hosts" : [
                "localhost:27017",
                "localhost:27018",
        ],
        "arbiters" : [
                "localhost:27019"
        ],
        "primary" : "localhost:27018",
        "ok" : 1
}

Now, try killing the primary server. Wait a couple seconds and you’ll see the other (non-arbiter) server be elected primary.

Once there’s a new primary, restart the mongod you just killed. You’ll see it join in the fray, though not become master (there’s already a master, so it won’t rock the boat). After a few seconds, kill the current master. Now the old master will become master again!

It’s pretty fun to play with this, bringing them up and down and watching the mastership go back and forth (or maybe I’m easily amused).

Inserting and querying data

By default, slaves are for backup only, but you can also use them for queries (reads) if you set the “slave ok” flag. Connect to each of the servers and set this flag:

> db.getMongo().setSlaveOk()
> borg2 = connect("localhost:27018/test")
connecting to: localhost:27018/test
test
> borg2.getMongo().setSlaveOk()

Now you can insert, update, and remove data on the master and read the changes on the slave.

On Monday: the “why” behind what we just did.

  • http://twitter.com/mardix Mardix

    Thanks. Good post!

    I got a question, how do you set Replica Set to make it work properly with PHP?

    Thanks Kristina.

  • kristina1

    Thanks! See example #1 at http://php.net/manual/en/mongo.construct.php.

    1.0.9 will be coming out in the next day or two.

  • http://twitter.com/mardix Mardix

    Kristina, thanx so much. I'm a big fan of yours…. Whoooo Ooooohhhhh!

  • kristina1

    Haha, thanks!

  • Mark

    It should be noted that it appears that you can’t have a / in your replica name. Everything looks alright until you try to initialize your set it and it always complains that it can’t find any servers (even if you’re on one of them as you try to configure it!)

  • Anonymous
  • Anonymous

    Hi,how to execute the queries below.
    MongoDB shell version: 1.5.7
    connecting to: test
    > rs.initiate({“_id” : “unicomplex”, “members” : [
    ... {"_id" : 0, "host" : "localhost:27017"},
    ... {"_id" : 1, "host" : "localhost:27018"},
    ... {"_id" : 2, "host" : "localhost:27019", "arbiterOnly" : true}]})
    Atleast one full execution of the query…Please…

  • Anonymous

    You’ll need to upgrade, I don’t think replica sets existed in 1.5.7. I think 1.8.0-rc0 is coming out today, give that a try!

  • Anonymous

    Thanks for your kind attention on my question…Thanks for your reply….I
    understood…

  • Anonymous

    Hi Kristina..U told that the version 1.8.0-rco will be get released I think its not yet release..Can u tel When it will be get releases?

  • Anonymous

    Hi kristina1,I am using 64-bit MongoDB and i had done testing with 64-bit MongoDB.The testing details as follows:- 1)I gave one million files as backup to my server using mongodb as my Database Storage. 2)My backup data size is “22.8-GB”. 3)The mongodb size is “1.95GB”. Now, my question, is there any settings available to compress the DB-Size Before configuring the backup to the server?.Please help me folks…Advance Thanks,

  • Sudhakar

    Hi,

    The above example works perfectly and its great when all the three nodes working on a single server.
    But having problem when nodes are in different servers, using above example while working with Python (http://api.mongodb.org/python/1.9%2B/examples/replica_set.html), I’m getting problem:

    Problem: When I kill mongo server from sf1:27017 [Primary] instance then my secondary [sf2:27017] should elect as Primary to overcome the failover which is not happening.

    Complete discussion:
    http://comments.gmane.org/gmane.comp.db.mongodb.user/27810

    Need help on this.

  • Anonymous

    Failover isn’t instantaneous, especially with network latency. You have to put a try/except around your database calls and wait (or keep retrying in a try/except) until a new master is elected.

  • http://ericklind.com Erick

    Hi,
    I tried to use your example above, buy I keep getting the following error on the initiate code:
    ‘couldn’t initiate : need all members up to initiate, not ok: localhost27018′

    I have also tried adding using rs.add, but that gave me the same error. I’m using 2.0.2 x64 version on Windows. Any ideas on what to do?

    Thanks.

  • Rakesh Sankar

    Please correct me if I am wrong, shouldn’t we start these mongo with “–journal” option.

  • kristina1

    In 2.0, journaling is on by default.  You can turn it of with –nojournal.  If you’re still using 1.8, yes, use –journal. When this was written, journaling didn’t exist, yet.

  • Cayden Liew

    Hi Erick, im having the same problem, are you able to solve that? thanks.

  • http://ericklind.com Erick

    Cayden,
    No I never did.  I’m just working with a single instance for now and figure I’ll attack the issue later.  But I was disappointed to not receive any help on this.

  • kristina1

    Hey guys, not sure why I didn’t see this comment before.  If you have questions, the mailing list (groups.google.com/d/topic/mongodb-user/) is a good place to get help.  @ericklind:disqus in the error you pasted, it looks like you’re missing a : in your host string: “localhost:27018″.

kristina chodorow's blog