MongoDB学习笔记(五)- MongoDB复制集读写事务
文章目录
内容来自唐建法(TJ)老师的MongoDB 高手课 (geekbang.org)
单机版三节点副本集搭建
在一台Ubuntu机器上,通过配置文件的方式启动三个mongod
实例。各个参数的说明请参考Configuration File Options — MongoDB Manual。示例配置文件和说明如下:
1systemLog:
2 destination: file
3 path: /data/dbx/mongod.log # x替换成1,2,3对应三个不同的mongod实例
4 logAppend: true
5storage:
6 dbPath: /data/dbx # x替换成1,2,3对应三个不同的mongod实例
7net:
8 bindIp: 0.0.0.0 # 允许远程连接
9 port: xxxx # 三个实例使用端口依次为28017,28018,28019
10replication:
11 replSetName: jonlimxrs # rs的名字,可根据需要命名
12processManagement:
13 fork: true
启动三个mongod实例:
1mongod -f /data/db1/mongod.conf
2mongod -f /data/db2/mongod.conf
3mongod -f /data/db3/mongod.conf
4
5➜ ~ ps -ef | grep mongod
6root 1719 1 0 Feb16 ? 00:10:13 mongod -f ./mongod.conf
7root 1771 1 0 Feb16 ? 00:10:18 mongod -f ../db2/mongod.conf
8root 1823 1 0 Feb16 ? 00:10:13 mongod -f ../db3/mongod.conf
9ability 5595 5477 0 10:20 pts/0 00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox mongod
连接第一个实例,然后在第一个实例上初始化副本集:
1➜ ~ mongo --port 28017
2> rs.initiate({
3 _id: "jonlimxrs",
4 members: [{_id: 0,host: "192.168.50.27:28017" },
5 {_id: 1,host: "192.168.50.27:28018" },
6 {_id: 2,host: "192.168.50.27:28019" }]}) // 这里我使用的IP,生产环境应该使用DNS而不是IP
初始化完毕后,需要在所有的SECONDARY节点上启用读操作:
1jonlimxrs:SECONDARY> db.test.find()
2Error: error: {
3 "topologyVersion" : {
4 "processId" : ObjectId("620cb55a0e2488713ea2053f"),
5 "counter" : NumberLong(4)
6 },
7 "ok" : 0,
8 "errmsg" : "not master and slaveOk=false",
9 "code" : 13435,
10 "codeName" : "NotPrimaryNoSecondaryOk", // 默认不允许读操作
11 "$clusterTime" : {
12 "clusterTime" : Timestamp(1645066026, 4),
13 "signature" : {
14 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
15 "keyId" : NumberLong(0)
16 }
17 },
18 "operationTime" : Timestamp(1645066026, 4)
19}
20
21jonlimxrs:SECONDARY> rs.secondaryOk() // 启用读操作
writeConcern介绍
1{ w: <value>, j: <boolean>, wtimeout: <number> }
在插入、更新和删除操作的时候可以指定writeConcern
,意义在意该操作在个w
节点上完成才算成功,否则操作被阻塞。
参数 | 说明 |
---|---|
w | 节点的个数。可以指定具体的数,但是不能超过总的节点数。通常指定为majority ,有投票资格的节点个数的一半(向下取整)加1 |
j | 如果是true 说明操作需要落盘(journal文件) |
wtimeout | 操作超时时间,单位是毫秒。如果不指定该参数,或者值设置为0,那么在正常返回之前,相应的操作将一直阻塞 |
详细介绍请参看Write Concern — MongoDB Manual
现在通过设置SECONDARY的延时来模拟异常情况,来观察writeConcern
的作用:
1jonlimxrs:PRIMARY> conf=rs.conf()
2jonlimxrs:PRIMARY> conf.members[1].secondaryDelaySecs=5 // 设置数据同步延迟时间,单位秒
3jonlimxrs:PRIMARY> conf.members[1].priority=0 // 设置为0是的不能被选举成为Primary
4jonlimxrs:PRIMARY> rs.reconfig(conf)
5{
6 "_id": 1,
7 "host": "192.168.50.27:28018",
8 "arbiterOnly": false,
9 "buildIndexes": true,
10 "hidden": false,
11 "priority": 0,
12 "tags": {},
13 "secondaryDelaySecs": 5,
14 "votes": 1
15}
16
17jonlimxrs:PRIMARY> db.test.insertOne({count:1000},{writeConcern:{w: 3}})
18// 大约5秒后返回
19{
20 "acknowledged" : true,
21 "insertedId" : ObjectId("620f5fad9a5fd7bf5a122785")
22}
readPreference和readPreferenceTags
readPreference决定了从哪一个节点读取数据,可配置的值如下表。根据场景的不同选择从不同的节点读取数据。
选项 | 说明 |
---|---|
primary | 只从主节点读取 |
primaryPreferred | 优先从主节点读取,如果不可用就从从节点读取 |
secondary | 只从从节点读取 |
secondaryPreferred | 优先从从节点读取,如果不可用就从主节点读取 |
nearest | 从时延最小的节点读取 |
关于readPreference的更多介绍请参考:Read Preference — MongoDB Manual
readPreferenceTags与readPreference类似,通过对节点打上特定的标签,读取的时候可以选择从具有特定标签的节点读取。详见:Read Preference Tag Sets — MongoDB Manual
连接字符串上设置这两个参数的方式:Connection String URI Format — MongoDB Manual
现在通过db.fsyncLock()
锁定从节点写入来模拟从节点不可用的情况:
1// 分别在两个从节点执行db.fsyncLock()
2// 192.168.50.27:28018
3jonlimxrs:SECONDARY> db.fsyncLock()
4// 192.168.50.27:28019
5jonlimxrs:SECONDARY> db.fsyncLock()
6jonlimxrs:PRIMARY> db.test.insertOne({a:1001},{wtimeout:1000}) // 主节点插入
7// 从节点上查不到数据
8jonlimxrs:SECONDARY> db.test.find({a:1001}).readPref("secondary")