Mongodb中的oplog

395次阅读
没有评论

共计 3664 个字符,预计需要花费 10 分钟才能阅读完成。

Mongodb中的oplog

在学习mongodb时,会遇到两个mongodb日志,oplog和journal log。这两者有点类似mysql的binlog和redo log,而此处则记录下oplog的一些知识

什么是oplog?

oplog是mongodb用来提供副本集群复制功能的集合,它位于local库下,是一个定长集合(capped col),Secondary就是通过查看Primary的oplog集合来进行复制的,当然每个角色节点都有oplog,记录着同步过来的数据信息,这样就可以每个节点都可以作为同步源给其他节点使用,减轻Primary的压力

shard03:PRIMARY> use local
switched to db local
shard03:PRIMARY> show collections;
oplog.rs
replset.election
replset.initialSyncId
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id

oplog数据大小

oplog因为是一个定长集合,所以只能保存特定数量的操作日志,默认是当前节点磁盘的5%(默认最小为1G,最大为50G),可以通过在mongodb.conf中的oplogSize参数来设置

shard03:PRIMARY> db.getReplicationInfo()
{
        "logSizeMB" : 1576.527099609375,
        "usedMB" : 1410.88,
        "timeDiff" : 253290,
        "timeDiffHours" : 70.36,
        "tFirst" : "Fri Nov 11 2021 00:06:26 GMT+0800 (CST)",
        "tLast" : "Sun Nov 12 2021 22:27:56 GMT+0800 (CST)",
        "now" : "Sun Nov 12 2021 22:28:06 GMT+0800 (CST)"
}

对于oplogSize该如何设置?因为定长集合是一个环状结构,数据超过设定大小,新数据则会覆写最老的数据,如果我们Secondary节点来不及同步,数据就被覆写了,那Secondary节点就会处于RECOVERING状态。如果设置过大,则必然浪费空间~~~

oplog的增长速度

上面我们知道oplog的过大浪费空间,过小容易造成Secondary节点RECOVERING,怎么设置,需要根据实际情况进行选择,这里就可以通过业务场景来判断。首先我们需要知道oplog是如何产生的?

当Primary进行写操作的时候,会将这些写操作记录写入到Primary的oplog中,而后Seconday才会从oplog中复制同步。一般情况下,Primary每分钟写入1KB数据,则oplog也是1KB写入每分钟。但是如果写操作是批量写或删,则会产生多条oplog,比如一次性增加或删除10条,那么oplog则会产生10条日志分别记录每条的操作

shard03:PRIMARY> db.users.insertMany([{"name":"张三","age":NumberInt(10),"sex":"男"},{"name":"李四","age":NumberInt(11),"sex":"男"}])
{
        "acknowledged" : true,
        "insertedIds" : [
                ObjectId("640de5e8ebbeb231f23dcd5d"),
                ObjectId("640de5e8ebbeb231f23dcd5e")
        ]
}

上面一次插入两条,查下此时oplog被拆成两条

shard03:PRIMARY> db.oplog.rs.find({"ns": "xadocker.users"})
{ "op" : "i", "ns" : "xadocker.users", "ui" : UUID("a41a19d2-137e-4e48-954a-22b96d557256"), "o" : { "_id" : ObjectId("640de5e8ebbeb231f23dcd5d"), "name" : "张三", "age" : 10, "sex" : "男" }, "ts" : Timestamp(1678632424, 2), "t" : NumberLong(2), "v" : NumberLong(2), "wall" : ISODate("2023-03-12T14:47:04.455Z") }
{ "op" : "i", "ns" : "xadocker.users", "ui" : UUID("a41a19d2-137e-4e48-954a-22b96d557256"), "o" : { "_id" : ObjectId("640de5e8ebbeb231f23dcd5e"), "name" : "李四", "age" : 11, "sex" : "男" }, "ts" : Timestamp(1678632424, 3), "t" : NumberLong(2), "v" : NumberLong(2), "wall" : ISODate("2023-03-12T14:47:04.455Z") }

如果是更新呢?

shard03:PRIMARY> use xadocker
switched to db xadocker
shard03:PRIMARY> db.users.update({"sex":"男"},  {"$inc":{"age":NumberInt(1)}}, false, true)
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })


shard03:PRIMARY> db.oplog.rs.find({"ns": "xadocker.users", "op":"u"}).pretty()
{
        "op" : "u",
        "ns" : "xadocker.users",
        "ui" : UUID("a41a19d2-137e-4e48-954a-22b96d557256"),
        "o" : {
                "$v" : 1,
                "$set" : {
                        "age" : 11
                }
        },
        "o2" : {
                "_id" : ObjectId("640de5e8ebbeb231f23dcd5d")
        },
        "ts" : Timestamp(1678632798, 1),
        "t" : NumberLong(2),
        "v" : NumberLong(2),
        "wall" : ISODate("2021-11-12T14:53:18.515Z")
}
{
        "op" : "u",
        "ns" : "xadocker.users",
        "ui" : UUID("a41a19d2-137e-4e48-954a-22b96d557256"),
        "o" : {
                "$v" : 1,
                "$set" : {
                        "age" : 12
                }
        },
        "o2" : {
                "_id" : ObjectId("640de5e8ebbeb231f23dcd5e")
        },
        "ts" : Timestamp(1678632798, 2),
        "t" : NumberLong(2),
        "v" : NumberLong(2),
        "wall" : ISODate("2021-11-12T14:53:18.522Z")
}

从上面可以可以看到批量更新操作,最后也是追条生成oplog,而且在oplog中被记录为$set,所以oplog的replay是可以多次执行的,具有幂等性。

到这里估计你就能想到,该参考什么去设置oplogSize的大小了,对于参数的调整不是设置完后就结束了,在博主的运维生涯来看是持续的,因为业务是会一直改变的~~~,没有单一的读,也没有单一的写~~

oplog数据结构

{
        "op" : "u",
        "ns" : "xadocker.users",
        "ui" : UUID("a41a19d2-137e-4e48-954a-22b96d557256"),
        "o" : {
                "$v" : 1,
                "$set" : {
                        "age" : 12
                }
        },
        "o2" : {
                "_id" : ObjectId("640de5e8ebbeb231f23dcd5e")
        },
        "ts" : Timestamp(1678632798, 2),
        "t" : NumberLong(2),
        "v" : NumberLong(2),
        "wall" : ISODate("2021-11-12T14:53:18.522Z")
}
  • ts: 8字节的时间戳,由4字节unix timestamp + 4字节自增计数表示。这个值很重要,在primary故障后选举primary时,会选择ts最大的那个secondary作为新primary
  • op:1字节的操作类型
    • “i”: insert
    • “u”: update
    • “d”: delete
    • “c”: db cmd
    • “db”:声明当前数据库 (其中ns 被设置成为=>数据库名称+ ‘.’)
    • “n”: no op,即空操作,其会定期执行以确保时效性
  • ns:操作所在的namespace
  • o:操作所对应的document,即当前操作的内容(比如更新操作时要更新的的字段和值)
  • o2: 在执行更新操作时的where条件,仅限于update时才有该属性

正文完
 
xadocker
版权声明:本站原创文章,由 xadocker 2021-11-13发表,共计3664字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)