Jan
28
2016
--

Setup a MongoDB replica/sharding set in seconds

MongoDB sharding

MongoDBIn the MySQL world, we’re used to playing in the MySQL Sandbox. It allows us to deploy a testing replication environment in seconds, without a great deal of effort or navigating multiple virtual machines. It is a tool that we couldn’t live without in Support.

In this post I am going to walk through the different ways we have to deploy a MongoDB replica/sharding set test in a similar way. It is important to mention that this is not intended for production, but to be used for troubleshooting, learning or just playing around with replication.

Replica Set regression test’s diagnostic commands

MongoDB includes a .js that allows us to deploy a replication set from the MongoDB’s shell. Just run the following:

# mongo --nodb
> var rstest = new ReplSetTest( { name: 'replicaSetTest', nodes: 3 } )
> rstest.startSet()
ReplSetTest Starting Set
ReplSetTest n is : 0
ReplSetTest n: 0 ports: [ 31000, 31001, 31002 ]	31000 number
{
	"useHostName" : true,
	"oplogSize" : 40,
	"keyFile" : undefined,
	"port" : 31000,
	"noprealloc" : "",
	"smallfiles" : "",
	"rest" : "",
	"replSet" : "replicaSetTest",
	"dbpath" : "$set-$node",
	"restart" : undefined,
	"pathOpts" : {
		"node" : 0,
		"set" : "replicaSetTest"
	}
}
ReplSetTest Starting....
[...]

At some point our mongod daemons will be running, each with its own data directory and port:

2133 pts/0    Sl+    0:01 mongod --oplogSize 40 --port 31000 --noprealloc --smallfiles --rest --replSet replicaSetTest --dbpath /data/db/replicaSetTest-0 --setParameter enableTestCommands=1
 2174 pts/0    Sl+    0:01 mongod --oplogSize 40 --port 31001 --noprealloc --smallfiles --rest --replSet replicaSetTest --dbpath /data/db/replicaSetTest-1 --setParameter enableTestCommands=1
 2213 pts/0    Sl+    0:01 mongod --oplogSize 40 --port 31002 --noprealloc --smallfiles --rest --replSet replicaSetTest --dbpath /data/db/replicaSetTest-2 --setParameter enableTestCommands=1

Perfect. Now we need to initialize the replicaset:

> rstest.initiate()
{
	"replSetInitiate" : {
		"_id" : "replicaSetTest",
		"members" : [
			{
				"_id" : 0,
				"host" : "debian:31000"
			},
			{
				"_id" : 1,
				"host" : "debian:31001"
			},
			{
				"_id" : 2,
				"host" : "debian:31002"
			}
		]
	}
}
 m31000| 2016-01-24T10:42:36.639+0100 I REPL     [ReplicationExecutor] Member debian:31001 is now in state SECONDARY
 m31000| 2016-01-24T10:42:36.639+0100 I REPL     [ReplicationExecutor] Member debian:31002 is now in state SECONDARY
[...]

and it is done!

> rstest.status()
{
	"set" : "replicaSetTest",
	"date" : ISODate("2016-01-24T09:43:41.261Z"),
	"myState" : 1,
	"members" : [
		{
			"_id" : 0,
			"name" : "debian:31000",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 329,
			"optime" : Timestamp(1453628552, 1),
			"optimeDate" : ISODate("2016-01-24T09:42:32Z"),
			"electionTime" : Timestamp(1453628554, 1),
			"electionDate" : ISODate("2016-01-24T09:42:34Z"),
			"configVersion" : 1,
			"self" : true
		},
		{
			"_id" : 1,
			"name" : "debian:31001",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 68,
			"optime" : Timestamp(1453628552, 1),
			"optimeDate" : ISODate("2016-01-24T09:42:32Z"),
			"lastHeartbeat" : ISODate("2016-01-24T09:43:40.671Z"),
			"lastHeartbeatRecv" : ISODate("2016-01-24T09:43:40.677Z"),
			"pingMs" : 0,
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "debian:31002",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 68,
			"optime" : Timestamp(1453628552, 1),
			"optimeDate" : ISODate("2016-01-24T09:42:32Z"),
			"lastHeartbeat" : ISODate("2016-01-24T09:43:40.672Z"),
			"lastHeartbeatRecv" : ISODate("2016-01-24T09:43:40.690Z"),
			"pingMs" : 0,
			"configVersion" : 1
		}
	],
	"ok" : 1
}

There are many more commands you can run, just type rstest. and then press Tab twice to get the list. Follow this link if you need more info:

http://api.mongodb.org/js/current/symbols/_global_.html#ReplSetTest

What about sharding? Pretty similar:

> var shtest = new ShardingTest({ shards: 2, mongos: 1 })

This is the documentation link if you need more info:

http://api.mongodb.org/js/current/symbols/_global_.html#ShardingTest

It is important to mention that if you close the mongo shell where you run the commands, then all the spawned mongod will also shut down.


Mtools

mtools is a collection of tools and scripts that make MongoDB’s DBA lives much easier. It includes mlaunch, which can be used to start replicate sets and sharded systems for testing.

https://github.com/rueckstiess/mtools

The mlaunch tool requires pymongo, so you need to install it:

# pip install pymongo

You can also use pip to install mtools:

# pip install mtools

Then, we can just start our replica set. In this case, with two nodes and one arbiter:

# mlaunch --replicaset --nodes 2 --arbiter --name "replicaSetTest" --port 3000
launching: mongod on port 3000
launching: mongod on port 3001
launching: mongod on port 3002
replica set 'replicaSetTest' initialized.
# ps -x | grep mongod
10246 ?        Sl     0:03 mongod --replSet replicaSetTest --dbpath /root/data/replicaSetTest/rs1/db --logpath /root/data/replicaSetTest/rs1/mongod.log --port 3000 --logappend --fork
10257 ?        Sl     0:03 mongod --replSet replicaSetTest --dbpath /root/data/replicaSetTest/rs2/db --logpath /root/data/replicaSetTest/rs2/mongod.log --port 3001 --logappend --fork
10274 ?        Sl     0:03 mongod --replSet replicaSetTest --dbpath /root/data/replicaSetTest/arb/db --logpath /root/data/replicaSetTest/arb/mongod.log --port 3002 --logappend --fork

Done. You can also deploy a shared cluster, or a sharded replica set. More information in the following link:

https://github.com/rueckstiess/mtools/wiki/mlaunch


Ognom Toolkit

“It is a set of utilities, functions and tests with the goal of making the life of MongoDB/TokuMX administrators easier.”

This toolkit has been created by Fernando Ipar and Sveta Smirnova, and includes a set of scripts that allow us to deploy a testing environment for both sharding and replication configurations. The main difference is that you can specify what storage engine will be the default, something you cannot do with other to methods.

https://github.com/Percona-Lab/ognom-toolkit

We have the tools we need under “lab” directory. Most of the names are pretty self-explanatory:

~/ognom-toolkit/lab# ls
README.md  start_multi_dc_simulation  start_sharded_test  stop_all_mongo    stop_sharded_test
common.sh  start_replica_set	      start_single	  stop_replica_set  stop_single

So, let’s say we want a replication cluster with four nodes that will use PerconaFT storage engine. We have to do the following:

Set a variable with the storage engine we want to use:

# export MONGODB_ENGINE=PerconaFT

Specify where is our mongod binary:

# export MONGOD=/usr/bin/mongod

Start our 4 nodes replica set:

# ./start_replica_set
Starting 4 mongod instances
2016-01-25T12:36:04.812+0100 I STORAGE  Compression: snappy
2016-01-25T12:36:04.812+0100 I STORAGE  MaxWriteMBPerSec: 1024
2016-01-25T12:36:04.813+0100 I STORAGE  Crash safe counters: 0
about to fork child process, waiting until server is ready for connections.
forked process: 1086
child process started successfully, parent exiting
[...]
MongoDB shell version: 3.0.8
connecting to: 127.0.0.1:27001/test
{
	"set" : "rsTest",
	"date" : ISODate("2016-01-25T11:36:09.039Z"),
	"myState" : 1,
	"members" : [
		{
			"_id" : 0,
			"name" : "debian:27001",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 5,
			"optime" : Timestamp(1453721767, 5),
			"optimeDate" : ISODate("2016-01-25T11:36:07Z"),
			"electionTime" : Timestamp(1453721767, 2),
			"electionDate" : ISODate("2016-01-25T11:36:07Z"),
			"configVersion" : 4,
			"self" : true
		},
		{
			"_id" : 1,
			"name" : "debian:27002",
			"health" : 1,
			"state" : 5,
			"stateStr" : "STARTUP2",
			"uptime" : 1,
			"optime" : Timestamp(0, 0),
			"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
			"lastHeartbeat" : ISODate("2016-01-25T11:36:07.991Z"),
			"lastHeartbeatRecv" : ISODate("2016-01-25T11:36:08.093Z"),
			"pingMs" : 0,
			"configVersion" : 2
		},
		{
			"_id" : 2,
			"name" : "debian:27003",
			"health" : 1,
			"state" : 0,
			"stateStr" : "STARTUP",
			"uptime" : 1,
			"optime" : Timestamp(0, 0),
			"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
			"lastHeartbeat" : ISODate("2016-01-25T11:36:07.991Z"),
			"lastHeartbeatRecv" : ISODate("2016-01-25T11:36:08.110Z"),
			"pingMs" : 2,
			"configVersion" : -2
		},
		{
			"_id" : 3,
			"name" : "debian:27004",
			"health" : 1,
			"state" : 0,
			"stateStr" : "STARTUP",
			"uptime" : 1,
			"optime" : Timestamp(0, 0),
			"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
			"lastHeartbeat" : ISODate("2016-01-25T11:36:08.010Z"),
			"lastHeartbeatRecv" : ISODate("2016-01-25T11:36:08.060Z"),
			"pingMs" : 18,
			"configVersion" : -2
		}
	],
	"ok" : 1
}

Now, just start using it:

rsTest:PRIMARY> db.names.insert({ "a" : "Miguel"})
rsTest:PRIMARY> db.names.stats()
{
	"ns" : "mydb.names",
	"count" : 1,
	"size" : 36,
	"avgObjSize" : 36,
	"storageSize" : 16384,
	"capped" : false,
	"PerconaFT" : {
[...]


Conclusion

When dealing with bugs, troubleshooting or testing some application that needs a complex MongoDB infrastructure, these processes can save us lot of time. No need of set up multiple virtual machines, deal with networking and human mistakes. Just say “I want a sharded cluster, do it for me.”

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com