In this blog post, we will look at MongoDB replica set tag sets, which enable you to use customized write concern and read preferences for replica set members.
This blog post will cover most of the questions that come to mind before using tag sets in a production environment.
Now let’s answer all these questions one by one.
You can use tags:
Yes, these tag-sets work with all the read preferences — except “primary” mode. “Primary” preferred read preference mode doesn’t allow you to add any tag sets while querying.
|
1 |
replicaTest:PRIMARY> db.tagTest.find().readPref('primary', [{"specs" : "low","purpose" : "general"}])<br>Error: error: {<br> "ok" : 0,<br> "errmsg" : "Only empty tags are allowed with primary read preference",<br> "code" : 2,<br> "codeName" : "BadValue"<br>} |
Yes, you can use tag sets with a maxStalenessSeconds value. In that case, priority is given to staleness first, then tags, to get the most recent data from the secondary member.
You can configure tags by adding a parameter in the replica set configuration. Consider this test case with a five members replica set:
|
1 |
"members" : [<br> {<br> "_id" : 0,<br> "name" : "host1:27017",<br> "stateStr" : "PRIMARY",<br> },<br> {<br> "_id" : 1,<br> "name" : "host2:27017",<br> "stateStr" : "SECONDARY",<br> },<br> {<br> "_id" : 2,<br> "name" : "host3:27017",<br> "stateStr" : "SECONDARY",<br> },<br> {<br> "_id" : 3,<br> "name" : "host4:27017",<br> "stateStr" : "SECONDARY",<br> },<br> {<br> "_id" : 4,<br> "name" : "host5:27017",<br> "stateStr" : "SECONDARY",<br> }<br> ] |
For our test case, members specification of the host are “specs” and the requirement for the query as per the application is the “purpose,” in order to route queries to specific members in an optimized manner.
You must associate tags to each member by adding it to the replica set configuration:
|
1 |
cfg=rs.conf()<br><br>cfg.members[0].tags={"specs":"high","purpose":"analytics"}<br>cfg.members[1].tags={"specs":"high"}<br>cfg.members[2].tags={"specs":"low","purpose":"general"}<br>cfg.members[3].tags={"specs":"high","purpose":"analytics"}<br>cfg.members[4].tags={"specs":"low"}<br><br>rs.reconfig(cfg) |
After adding tags, you can validate these changes by checking replica set configurations like:
|
1 |
rs.conf()<br><br> "members" : [<br> {<br> "_id" : 0,<br> "host" : "host1:27017",<br> "tags" : {<br> "specs" : "high",<br> "purpose" : "analytics"<br> },<br> },<br> {<br> "_id" : 1,<br> "host" : "host2:27017",<br> "tags" : {<br> "specs" : "high"<br> },<br> },<br> {<br> "_id" : 2,<br> "host" : "host3:27017",<br> "tags" : {<br> "specs" : "low",<br> "purpose" : "general"<br> },<br> },<br> {<br> "_id" : 3,<br> "host" : "host4:27017",<br> "tags" : {<br> "specs" : "high",<br> "purpose" : "analytics"<br> },<br> },<br> {<br> "_id" : 4,<br> "host" : "host5:27017",<br> "tags" : {<br> "specs" : "low"<br> },<br> }<br> ] |
Now, we are done with the tag-set configuration.
No, custom read preferences and write concerns consider tag sets in different ways.
Read preferences routes read operations to a required specific member by following tag values assigned to it, but write concerns follows tag values only to check if the value is unique or not. It will not consider tag values while selecting replica members.
Let us see how to use tag sets with write concerns. As per our test case, we have two unique tag values (i.e., “analytics” and “general”) defined as:
|
1 |
cfg=rs.conf()<br>cfg.settings={ getLastErrorModes: {writeNode:{"purpose": 2}}}<br>rs.reconfig(cfg) |
You can validate these changes by checking the replica set configuration:
|
1 |
rs.conf()<br> "settings" : {<br> "getLastErrorModes" : {<br> "writeNode" : {<br> "purpose" : 2<br> }<strong><br> },</strong><br> } |
Now let’s try to insert a sample document in the collection named “tagTest” with this write concern:
|
1 |
db.tagTest.insert({name:"tom",tech:"nosql",status:"active"},{writeConcern:{w:"writeNode"}})<br>WriteResult({ "nInserted" : 1 }) |
Here, the write concern “writeNode” means the client gets a write acknowledgment from two nodes with unique tag set values. If the value set in the configuration exceeds the count of unique values, then it leads to an error at the time of the write:
|
1 |
cfg.settings={ getLastErrorModes: {writeNode:{"purpose": 4}}}<br>rs.reconfig(cfg)<br><br>db.tagTest.insert({name:"tom",tech:"nosql",status:"active"},{writeConcern:{w:"writeNode"}})<br><br>WriteResult({<br> "nInserted" : 1,<br> "writeConcernError" : {<br> "code" : 100,<br> "codeName" : "CannotSatisfyWriteConcern",<br> "errmsg" : "Not enough nodes match write concern mode "writeNode""<br> }<br>} |
You can perform read and write operations with tag sets like this:
|
1 |
db.tagTest.find({name:"tom"}).readPref("secondary",[{"specs":"low","purpose":"general"}])<br><br>db.tagTest.insert({name:"john",tech:"rdbms",status:"active"},{writeConcern:{w:"writeNode"}}) |
I hope this helps you to understand how to configure MongoDB replica set tag sets, how the read preferences and write concerns handle them, and where you can use them
Resources
RELATED POSTS
Nice Document!
(For writes) This is the case when we are writing directly to replica set using mongod but if we write to a cluster, tags can be used there to divert the writes to particular shards (zone based sharding).
Thank you Sumeet, yes for the cluster we write through mongos and Zones based sharding enables to segregate data as per shards.