Skip to the content.

目标

本次向副本集添加一个新的节点,主要是为了扩充单个节点的存储空间,同时也提升服务器的配置。如果只是为了添加一个新的节点,以使得副本集更健壮,可以忽略本文中关于磁盘分区方面的内容。

思路

在MongoDB的集群中,服务器之间采用oplog的机制进行数据同步。添加一个新的服务器节点的基本思路,就是复制一个当前的活跃节点(比如某个Secondary),将复制产生的节点加入集群配置。集群随后将通过oplog将变化的数据同步至新的数据节点,使得新节点生效。

准备工作

了解集群oplog配置

oplog并不是无限的,而是只保留了一定范围内的数据变更记录。在MongoDB中,通过设置replication.oplogSizeMB,可以控制oplog的大小。默认情况下,oplog的大小是剩余磁盘空间的5%(不超过50GB),详细说明可参考官方文档
oplog的大小,决定了新增节点加入集群时,可以有多“陈旧”(stale)。可以通过以下方法了解当前的oplog从什么时间开始:

rs.printReplicationInfo()

返回结果如下例所示:

configured oplog size:   80000MB
log length start to end: 165287secs (45.91hrs)
oplog first event time:  Sun Jun 07 2020 16:53:43 GMT+0800 (CST)
oplog last event time:   Tue Jun 09 2020 14:48:30 GMT+0800 (CST)
now:                     Tue Jun 09 2020 14:48:30 GMT+0800 (CST)

在上述结果中,oplog配置的大小是80GB,当前的时间约45.91小时,起始时间是2020年6月7日16:53:43。如果新加入的节点的数据更新时间,晚于2020年6月7日16:53:43,那么这个节点就可以通过oplog同步至最新的状态。反之,则新节点过于“陈旧”(stale),不能同步至最新状态。

调整oplog大小

如果考虑oplog的大小不足以支持迁移时间的需要,那么可以增加oplog的空间,使得oplog的持续时间更长。方法如下:

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

其中size的单位为MB。

是否可以热备份

MongoDB 4.2版本开始可以支持热备份,在不停机的状态下复制的文件,仍可进行恢复。在4.2版本之前,并不支持。本例中使用的MongoDB是4.0版本,不可以进行热备份。当然,是否支持热备份的差别,也仅在与复制文件时的mongod进程状态。支持热备份的情况,可以在mongod运行情况下复制数据文件,反之则需要先停止mongod进程。

数据文件大小和文件系统类型

本次向集群添加服务器的原因在于原服务器的磁盘(2TB)使用率超过了75%,为避免磁盘使用率过高,需要对磁盘扩容。然而原来的磁盘使用的是MBR分区,不支持2T以上容量,需要替换为GPT分区。因此,采用的方式是,新增一个GPT分区的服务器,并将原服务器移除。
还有一种方式是,使用LVM管理分区,已获得分区可扩展性,不过在阿里云服务存在的条件下,LVM和GPT分区的最终效果差别并没有差异。

如何制作GPT分区的存储

fdisk并不支持GPT分区存储管理,需要使用parted工具。

  1. 确认存储的空间大小
    通过fdisk -l可以查看服务器的存储配置。
    Disk /dev/vdb: 3221.2 GB, 3221225472000 bytes
    255 heads, 63 sectors/track, 391625 cylinders, total 6291456000 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk identifier: 0x00000000
    
  2. 进行分区操作
    执行parted /dev/vdb
    进入后先创建label
    (parted) mklabel                                            
    New disk label type? gpt    
    

    随后创建分区

    (parted) mkpart primary 2048s 100%
    

    注意这里的起始位置是2048s(2048 sector),而不是0,为了对齐分区以获得更优的性能。这个具体的取值,可以根据以下方法获得:

    cat /sys/block/vdb/queue/optimal_io_size
    cat /sys/block/vdb/queue/minimum_io_size
    cat /sys/block/vdb/alignment_offset
    cat /sys/block/vdb/queue/physical_block_size
    

    通过计算

    (optimal_io_size + alignment_offset) / <physical_block_size>
    

    即可得到起始扇区的位置。

  3. 检查扇区对齐并退出
    执行(parted) print可以查看分区情况,例如: ``` (parted) print
    Model: Virtio Block Device (virtblk) Disk /dev/vdb: 3221GB Sector size (logical/physical): 512B/512B Partition Table: gpt

Number Start End Size File system Name Flags 1 1049kB 3221GB 3221GB ext4 primary

通过```align-check optimal 1```可以检查扇区是否对齐,其中1为分区的Number值。  

**注意:是否对齐对于GPT分区磁盘而言,性能影响程度非常大。笔者尝试,在对齐情况下的磁盘复制速率约为130MBps,而未对齐时的速率只有10MBps。**
4. 制作文件系统  
可以根据需要制作ext4文件系统或者xfs文件系统。


## 操作步骤
### 1. 找到一台Secondary服务器   
请注意以下问题:
1. 服务器最好不要承担过多业务功能,以免影响在线业务。如果有隐藏节点,建议使用隐藏节点。
2. 如果确实找不到适合的隐藏节点,可以先将在线应用配置为PrimaryPreferred,以尽量降低对业务的影响。

### 2. 停止Secondary服务,并制作文件镜像
如果是4.2版本以上,可以不停止,直接制作文件镜像。镜像制作好后,即可恢复Secondary的运行。

### 3. 通过镜像生成新的节点
将镜像拷贝到新的服务器,并生成新的存储磁盘,挂载到服务器上,即可作为新服务器的数据存储使用。  
对于本例而言,由于文件系统类型不同,在挂载后,还需要将数据文件复制到GPT文件系统的磁盘中,这个过程可能较长。请保证oplog的大小足以支撑整个镜像制作和文件复制的过程。  

### 4. 启动新节点mongod服务
启动新节点monogd服务,并在集群中加入新节点。

rs.add({ host: “yourhost.domain.com:27017”, hidden: true, priority: 0, votes: 0, })

为避免对在线服务产生产生影响,添加新节点时,建议将节点设为隐藏节点,并且priority和votes都可以设置为0。  
新节点加入后,将开启数据恢复过程(状态为RECOVERING),如果oplog足够大,那么数据恢复会很快完成,新节点状态变更为Secondary。如果oplog不足以恢复,新节点可能会一直处于RECOVERING状态,而无法完成同步。

### 5. 取消隐藏节点属性并提升优先级
通过以下方法可以将节点的隐藏属性取消,并且配置优先级,使其成为有效的Secondary节点,并可能被选举为Primary。

cfg = rs.conf() cfg.members[x].priority = 5 cfg.members[x].hidden = false rs.reconfig(cfg) ``` 其中,x代表新节点的配置编号(数组索引),请根据实际情况选择。优先级具体设定为多少,也请根据副本集的配置决定。