Replica Sets with Differing Indexes
This is not a normal setup & may be best used for few use-cases, particularly serving unique data-reading needs separate from the "primary" application needs:
- getting particular analytics from secondary nodes
- getting reports on delayed consistency data
- performing complex text searches
Prep for this rare setup:
- don't allow secondary nodes that will be read from to become primary
- priority = 0
- hidden
- delayed secondary
If a primary steps down, the main app will not be setup to leverage these specific use-case secondaries.
Preparing Secondary Nodes for Special Cases
Set the node to have priority 0
. This will make it so that the node can not vote.
Set the node to be hidden.
Setup the replica set so that if the primary goes down, the secondary node in use will not be able to become the primary in a vote.
Quick Build of a Replica Set
Consider this as a template config for a mongo node. This can be re-used for 2 other almost identical nodes. The only difference between this config and the others would be
- the port, increment by 1
- the systemLog path with incrementing
r
- the dbPath with incrementing
r
net:
port: 27000
processManagement:
fork: true
systemLog:
destination: 'file'
path: 'mongo-data/r0/log'
logAppend: true
storage:
dbPath: 'mongo-data/r0'
wiredTiger:
engineConfig:
cacheSizeGB: 0.5
replication:
oplogSizeMB: 10
replSetName: M201
run them with
mongo -f conf1.conf
Validate that the mongod services are running through the cli
ps -ef | grep mongod
Connect to a member & set some config on it, assuring 1 secondary node has priority 0.
mongo --port 27000
var c = {
"_id": "M201",
"members": [
{"_id": 0, "host": "localhost:27000"},
{"_id": 1, "host": "localhost:27001"},
{"_id": 2, "host": "localhost:27002", priority: 0}
]
}
rs.initiate(c)
Load some data
mongoimport --host M201/localhost:27001,localhost:27002,localhost:27000 -d m201 -c restaurants restaurants.json
reconnect to the replica set
validate that the db & collection has been uploaded.
Create an index on the name field.
mongo --host M201/localhost:27001,localhost:27002,localhost:27000
use m201
show collections
db.restaurants.findOne()
db.restaurants.createIndex({"name": 1})
Process and Setup Summary
- connect to secondary node
- shut it down
- reconnect in a non-repl-set connection
- add new indexes
- shutdown server
- relaunch the server
- connected to the replSet
connect to secondary node
While connected to the primary node, the same shell session can connect to a secondary node.
Validate that the index, that was applied on the primary, is now on the secondary.
# switch node
db = connect("localhost:27002/m201")
# allow reading from secondary
db.setSlaveOk()
db.restaurants.find({name: "Perry Street Brasserie"}).explain()
# should return...
...
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN"
...
allow system to run analytics on secondary node
Some queries do not ever need to be run on the primary.
shutdown the server
use admin
db.shutdownServer()
Reconnect instance as a stand-alone instance, without the replica set config in place
mongod --port 27002 --dbpath mongo-data/r2 --logpath mongo-data/r2/standalone.log --fork
connect to the server & create indexes specifically for some analytics
mongo --port 27002
# validate no replica set setup
rs.status()
# setup analytics-focused indexes
db.restaurants.createIndex({cuisine: 1, "address.street": 1, "address.city":1, "address.state":1, "address.zipcode":1})
# run an example explain query
db.restaurants.find({cuisine: /^Medi/, "address.zipcode": /^6/}).explain()
# this should show that the new indexes are supporting the query
shutdown the server & relaunch the same server connected to the replica set.
NOTE: running the same query against the primary will NOT utilize the indexes that are only set on the secondary node.
# shutdown the server
use admin
db.shutdownServer()
# relaunch secondary node using replica-set config file
mongod -f r2.cfg
# reconnect to replica set primary and see non-applied index
mongo --host M201/localhost:27001,localhost:27002,localhost:27000
use m201
db.restaurants.find({cuisine: /^Medi/, "address.zipcode": /^6/}).explain()
# see that the indexes are NOT used
switch to the secondary node & run the query, leveraging the indexes on the secondary nodes
db = connect("localhost:27002/m201")
# enable reading from secondaries
db.setSlaveOk()
# see that the indexes are being used
db.restaurants.find({cuisine: /^Medi/, "address.zipcode": /^6/}).explain()