• mongodb基础整理篇————副本原理篇[外篇]


    前言

    简单介绍一下副本集的原理篇。

    正文

    下面是几个基本的原理:

    副本之间是如何复制的?

    mongodb 实现此功能的方式是保存操作日志,其中包含了主节点执行的每一次操作,这和mysql比较像。

    oplog 是存在于主节点local数据库中的一个固定集合。从节点通过查询此集合以获取需要复制的操作。

    每个从节点都维护自己的oplog,用来记录它从主节点复制的每一个操作。

    这使得每个成员都可以被用作其他成员的同步源。

    从节点从同步源获取操作,将其应用到自己的数据集上,然后再写入oplog。

    如果一个从节点由于某种原因而停止运行,那么当它重新启动后,就会从oplog中的最后一个操作开始同步。

    由于这些操作是先应用到数据上,然后再写入到oplog,因此从节点可能会重复已经应用到其数据上的操作。

    mongodb 在设计的时候就考虑到了这种情况:将oplog中的一个操作多次与只执行一次的效果一样的。

    oplog中的每个操作都是幂等的。

    一般来说主节点每分钟写入1kb的数据,那么oplog也是每分钟1kb数据。

    但是如果是删除的话,那就不一样,比如说用户删除10000文档,那么oplog 可能就有10000条记录了,而不是oplog产生一条记录。

    这样做是为了保障oplog 执行的幂等。

    因为opsize 也是有大小的,不可能无限的进行扩长。

    这个opsize 设置非常重要,比如说,如果opsize 设置太小的话,那么就一个问题,从节点来不及同步的话而oplog 被删除的话,那么同步就会中断。

    在mongod 进程创建oplog 之前,可以使用oplogSizeMB 选项指定其大小。然后,在第一次启动副本集成员后,只能使用"更改oplog大小" 这个流程来更改oplog的大小的。

    初始化同步

    一般来说,如果一个副本加入到副本集,他就会检查自身状态,如果没有问题,那么就会进行初始化同步。

    首先mongodb 会克隆除local数据库之外的所以数据库。mongod 会扫描源数据中的每个集合,并将所以数据插入目标成员上这些集合的对应副本。

    在开始克隆操作之前,目标成员上的任何现有数据都将会被删除。

    在克隆过程将会将同步源变得缓慢:某些数据的子集经常被访问,因而这部分数据总是存在内存中。

    执行初始化同步会强制将其所有数据分页加载到内存中,从而驱逐那些经常使用的数据。原本是可以通过在ram访问的数据,现在要在磁盘上访问自然就慢了。

    然后如果数据库很大的话,那么其实是通过备份数据库中来还原数据库,而不是从初始化中来同步。

    如果一个从节点远远落后于同步源当前的操作,那么这个节点就是过时的。

    那么这个节点会怎么做呢?这个节点会找一个拥有足够长的oplog的节点进行同步,如果找不到,那么就要重新初始化或者从备份中恢复。

    为了避免这种情况,那么oplog 必须覆盖两到三天的正常操作。

    客户端使用副本集的一些注意点

    客户端我们叫做驱动程序。

    驱动程序和mongodb 进行写操作的时候,因为是一个网络传输,那么如果保证网络传输的一个幂等性呢?

    一般来说,没有网络问题的情况下,直接成功了,这样是没有问题的。

    那么有下面几种情况: 1. 服务短暂不可以 2. 服务长时间不可用 3. 服务命令错误,返回错误码

    3 这种情况下肯定不进行重试的了。

    1 和 2是我们驱动程序不知道,到底是1还是2呢? 那么怎么样的重试策略是好的呢?

    如果出现了服务不可用,那么可能就是在故障转移,这个时候在重新进行选举。

    所以驱动程序,采用至多重试一次的策略,就是在服务不可用的情况下,等待一个选举时间(估计的时间),然后进行重试。

    当然这里有人会提出疑问,万一第一次成功了,第二次运行这样不就有问题了吗?

    这个是不用担心的,mongo 做了幂等的。

    在写入时等待复制

    这个跟kafka 有点像。

    是这样的机制,就是在副本集写入的时候,可以设置一些选项,比如大部分副本集同步到了,才返回成功结果。

    db.products.insertOne({
      "_id":0,
       "item":"envelopes"
    },
    {
       "writeConcern":
        {
          "w":"majority",
          "wtimeout":100
        }
    })
    

    这个writeConcern中的w设置副本集同步多少个。

    w 可以是数字,2表示同步了一个从节点。

    这里面还可以自定义规则,没用到过,所以这里就不介绍了。

    什么时候用副本集从节点读取

    这个问题前面也提及过,因为从节点是存在延迟的,如果不介意延迟的话,那么是可以的。

    同样,如果考虑到负载情况,从从节点读取的确可以负债压力。

    但是如果有你需要负载30000次每秒的读取,但是你主节点只有10000次。

    你采用这种方式的话,那么你可以需要4台机器,3台有选举权,1台没有。

    但是如果有一台挂了,那么每台机器负荷就是100%,如果有一台出现了问题,需要重新同步数据,那么负荷就会超过100%。

    所以这个时候还是建议分片。

    维护相关

    单机维护

    如果希望维护某个从节点,但是又不希望在主节点上维护,那么可以采用单机维护。

    使用 db.serverCmdLineOpts() 查看启动命令:

    mydb:SECONDARY> db.serverCmdLineOpts()
    {
    	"argv" : [
    		"mongod",
    		"--replSet",
    		"mydb",
    		"--dbpath",
    		"/root/data/rs2",
    		"--logpath",
    		"/root/logs/rs2/log",
    		"--port",
    		"27018",
    		"--smallfiles",
    		"--oplogSize=200"
    	],
    	"parsed" : {
    		"net" : {
    			"port" : 27018
    		},
    		"replication" : {
    			"oplogSizeMB" : 200,
    			"replSet" : "mydb"
    		},
    		"storage" : {
    			"dbPath" : "/root/data/rs2",
    			"mmapv1" : {
    				"smallFiles" : true
    			}
    		},
    		"systemLog" : {
    			"destination" : "file",
    			"path" : "/root/logs/rs2/log"
    		}
    	},
    	"ok" : 1,
    	"operationTime" : Timestamp(1665935221, 1),
    	"$clusterTime" : {
    		"clusterTime" : Timestamp(1665935221, 1),
    		"signature" : {
    			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
    			"keyId" : NumberLong(0)
    		}
    	}
    }
    
    

    然后将该服务停止。

    db.shutdownServer();

    然后再换另外一个端口启动:

    mongod --port 30000 -dbpath /root/data/rs2
    

    这个就相当于这个从节点脱机维护了。

    控制成员状态

    如果希望某个主节点不再为主节点:

    rs.stepDown(600)

    这样主节点就会变成从节点。

    如果希望主节点进行维护,同样维护阶段不希望其他从节点成为新的主节点:

    其他节点运行:

    rs.freeze(10000)
    

    当维护结束,运行:

    rs.freeze(0)
    

    副本是如何选择从哪里复制的呢?

    一般情况下由系统自动选择。

    那么是否可以手动,也是可以的:

    secondary.adminCommand({"replSetSyncFrom":"localhost:27018"})
    

    这样就可以设置。

    还有一点比较重要的是,要设置这个oplog大小。

    这个是很关键的,如果oplog不够,那么很有可能复制就会中断了。

    查看当前oplog 大小。

    那么需要我们设置一下。

    db.adminCommand({"replSetResizeOplog":1,size:16000})

    这个就是16G了。

    下一节分片。

  • 相关阅读:
    《Hadoop实战》第一章
    找工作必备技能
    范数的深刻解读(转自知乎)
    贝叶斯定理(贝叶斯分类)
    什么是机器学习?
    线性可分 与线性不可分
    正则化和归一化
    过拟合问题是什么?
    CVPR 2016 paper reading (6)
    CVPR 2016 paper reading (3)
  • 原文地址:https://www.cnblogs.com/aoximin/p/16796043.html
Copyright © 2020-2023  润新知