栏目头部广告

MongoDB事务开发之写操作事务writeConcern

一、什么是writeConcern ?

writeConcern 决定一个写操作落到多少个节点上才算成功。writeConcern 的取值包括:

  • 0:发起写操作,不关心是否成功;
  • 1~集群最大数据节点数:写操作需要被复制到指定节点数才算成功;
  • majority:写操作需要被复制到大多数节点上才算成功。发起写操作的程序将阻塞到写操作到达指定的节点数为止。

1.1 默认行为

  • 3 节点复制集不作任何特别设定(默认值):

1635426773450_80.png

1.2 w: "majority"

  • 大多数节点确认模式

1635426803723_81.png

1.3 w: "all"

1635426843638_82.png

1.4 j: true

writeConcern 可以决定写操作到达多少个节点才算成功,journal则定义如何才算成功。取值包括:

  • true: 写操作落到 journal(日志)文件中才算成功;
  • false: 写操作到达内存即算作成功。

1635426869552_83.png

二、writeConcern 的意义

对于5个节点的复制集来说,写操作落到多少个节点上才算是安全的?

  • 1
  • 2
  • 3 ✓
  • 4 ✓
  • 5 ✓
  • majority ✓

三、writeConcern 实验

3.1  在复制集测试writeConcern参数

rs0:PRIMARY> db.test.insert( {count: 1})                                   # 默认
WriteResult({ "nInserted" : 1 })

rs0:PRIMARY> db.test.insert( {count: 1}, {writeConcern: {w: "majority"}})  # 大多数节点
WriteResult({ "nInserted" : 1 })

rs0:PRIMARY> db.test.insert( {count: 1}, {writeConcern: {w: 3 }})          # 三个节点
WriteResult({ "nInserted" : 1 })

rs0:PRIMARY> db.test.insert( {count: 1}, {writeConcern: {w: 4 }})          # 由于集群只有三个节点,所以当要求数据落到4个节点才返回成功时,会报错
WriteResult({
    "nInserted" : 1,
    "writeConcernError" : {
        "code" : 100,
        "codeName" : "UnsatisfiableWriteConcern",
        "errmsg" : "Not enough data-bearing nodes"
    }
})

# 查看插入成功记录
rs0:PRIMARY> db.test.find()
{ "_id" : ObjectId("60cefe0e651d9ab31c945d0c"), "count" : 1 }
{ "_id" : ObjectId("60cefe16651d9ab31c945d0d"), "count" : 1 }
{ "_id" : ObjectId("60cefe1c651d9ab31c945d0e"), "count" : 1 }
{ "_id" : ObjectId("60cefe23651d9ab31c945d0f"), "count" : 1 }

3.2  配置延迟节点,模拟网络延迟(复制延迟)

(1)将副本集节点配置存入conf参数

rs0:PRIMARY> conf=rs.conf()
{
    "_id" : "rs0",
    "version" : 3,
    "protocolVersion" : NumberLong(1),
    "writeConcernMajorityJournalDefault" : true,
    "members" : [
        {
            "_id" : 0,
            "host" : "10-27-0-224:28017",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {
            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 1,
            "host" : "10-27-0-224:28018",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {
            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        },
        {
            "_id" : 2,
            "host" : "10-27-0-224:28019",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1,
            "tags" : {
            },
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }
    ],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {
        },
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("60ce02f5209133abd12c1175")
    }
}

(2)查看获取的属组信息

rs0:PRIMARY> conf.members
[
    {
        "_id" : 0,
        "host" : "10-27-0-224:28017",
        "arbiterOnly" : false,
        "buildIndexes" : true,
        "hidden" : false,
        "priority" : 1,
        "tags" : {
        },
        "slaveDelay" : NumberLong(0),
        "votes" : 1
    },
    {
        "_id" : 1,
        "host" : "10-27-0-224:28018",
        "arbiterOnly" : false,
        "buildIndexes" : true,
        "hidden" : false,
        "priority" : 1,
        "tags" : {
        },
        "slaveDelay" : NumberLong(0),
        "votes" : 1
    },
    {
        "_id" : 2,
        "host" : "10-27-0-224:28019",
        "arbiterOnly" : false,
        "buildIndexes" : true,
        "hidden" : false,
        "priority" : 1,
        "tags" : {
        },
        "slaveDelay" : NumberLong(0),
        "votes" : 1
    }
]

(3)设置延迟节点

rs0:PRIMARY> conf.members[2].slaveDelay = 5    # 设置第三个节点延迟5s
5
rs0:PRIMARY> conf.members[2].priority = 0      # 取消第第三个节点参与选举的权利
0

(4)保存配置

rs0:PRIMARY> rs.reconfig(conf)
{
    "ok" : 1,
    "$clusterTime" : {
        "clusterTime" : Timestamp(1624178758, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    },
    "operationTime" : Timestamp(1624178758, 1)
}

(5)观察复制延迟下的写入,以及timeout参数

rs0:PRIMARY> db.test.insert( {count: 1}, {writeConcern: {w: 3}})
rs0:PRIMARY> db.test.insert( {count: 1}, {writeConcern: {w: 3, wtimeout:3000 }})

四、注意事项

  • 虽然多于半数的 writeConcern都是安全的,但通常只会设置majority,因为这是等待写入延迟时间最短的选择;
  • 不要设置 writeConcern 等于总节点数,因为一旦有一个节点故障,所有写操作都将失败;
  • writeConcern 虽然会增加写操作延迟时间,但并不会显著增加集群压力,因此无论是否等待,写操作最终都会复制到所有节点上。设置 writeConcern 只是让写操作等待复制后再返回而已;
  • 应对重要数据应用 {w: “majority”},普通数据可以应用 {w: 1} 以确保最佳性能。

作者:UStarGao
链接:https://www.starcto.com/mongodb/296.html
来源:STARCTO
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处

UCloud云平台推荐


UCloud新用户专属注册连接

UCloud CDN超值特惠专场

UCloud全球云主机(UHost/VPS)大促页面

UCloud快杰云主机大促页面

文章页广告

随便看看

栏目底部广告
`