复制集模式 MongoDB 从2.2升级到3.0

到目前最新 Release 版本的 Mongodb 已经是3.2了,对于比2.2更高的版本 2.4、2.6、3.0 来说,无论是支持更多的新特性还是在性能、安全、bug 修复方面也都有着巨大的改进。但也正是因为这些变动就会给升级工作带来困难和风险,比如兼容性问题。而我们必须遵守整个升级过程是数据要绝对安全,线上服务不能受影响的原则,这就需要在前期做好充足的准备工作。整个版本升级过程会逐步推进,从2.2到2.4,从2.4到2.6,php驱动升级,从2.6到3.0,升级3.0引擎为 WiredTiger。

当前生产环境介绍

系统环境
Linux x86_64

MongoDB:
当前生产环境 Mongodb 版本为2.2.1。采用复制集方式,共3个节点。

host角色
db0PRIMARY
db1SECONDARY
db2SECONDARY

PHP 驱动:
mongo 1.5.8

配置(以 db0 为例):

rest = true
port = 27017
dbpath = /data/mongodb/27017
logpath = /data/mongodb/27017/mongod.log
logappend = true
pidfilepath = /data/mongodb/27017/mongod.pid
fork = true
oplogSize = 20480
replSet = rs_0
quiet = true

官方版本介绍及升级方案

升级过程注意项

  • 每次升级完成后不要立即使用该版本的新特性,而应该待该版本稳定后再使用;
  • 每次升级完一个版本后要对数据一致性进行校验;
  • 升级时尽量选择在流量低峰期;

版本介绍

2.4

  • 新加入了两种索引类型:2dsphere 和 text;
  • 使用新的模块化安全验证机制,支持 Kerberos;
  • JavaScript 默认引擎由SpiderMonkey 转为 V8,V8 不支持的特性
  • 支持“等长队列”功能;
  • map-reduce、group、$where 这些功能、命令或表达式不再支持全局的函数或属性,比如 db;
  • 默认写关注write concern 设置由 {w:0} 变更为 {w:1};
  • 其他细节改动;

2.6

  • 重写了整个查询执行引擎,以提升可扩展性;
  • 引入索引交集(index intersection),这是 MongoDB 构建复杂的查询计划的第一步;
  • MongoDB管理服务(MMS),提供了备份和按时间点恢复功能,使得开发者可以在云端或本地更方便地管理 MongoDB;
  • 安全性增强:新引入了LDAPx.509验证机制以及TLS 加密
  • 分析功能增强;
  • 代码库更易维护,更容易实现新的功能;
  • 优化了地理位置的 2dsphere 索引;
  • 改善了 aggregation 功能,存在兼容性问题需要注意;
  • 正式整合了 Text Search;
  • 优化了 insert、update 方法;
  • 新加了 Bulk() 方法;
  • 优化了索引构建;
  • 开始支持 YAML 格式配置文件;
  • db.collection.remove() 命令使用 db.collection.remove({}) 代替;
  • RPM 和 DEB 包的配置文件中默认配置了 bindIp 项;
  • 修改了 Write Concern(写关注)验证,当使用 {j:true} 时而 mongodb 启动使用了 --nojournal 项,那么会报错,历史版本会忽略 {j:true};
  • 索引字段名称合法性验证更严格
  • 创建已存在的索引验证更严格
  • db.collection.insert(), db.collection.update(), db.collection.save() 和 db.collection.remove() 已将Write Concern(写关注)集成进去了,而不是像更早版本那样通过独立的 getLastError() 方法进行确认正确性,之前版本是 fire-and-forget(发射后不管);
  • “$in”、“$nin” 不再接受关联数组作为值,必须为索引数组;
  • 修复在 secondary server 中即使使用 background 方式建立索引,secondary 还是会以 foreground 方式建立索引,从而导致 secondary 同样引发数据库阻塞的问题。SERVER-13589 and SERVER-13620
  • 其他细节改动;

3.0

mongodb3.0-performance (1).jpg

1、降低运营开销95%;
2、复制集节点数最大支持数由以前版本的12个增长到50个(但能够投票的最大成员个数依然为7个);
3、写入性能提高7-10倍(使用 WiredTiger 时);
4、数据通过压缩可以缩减80%的存储(使用 WiredTiger 时);

  • 引入了新的 WiredTiger 引擎(是一个高性能、可扩展性、支持压缩和文档级锁的 NoSQL 存储引擎),同时也支持原先的 MMAP引擎(改进版 MMAPv1),WiredTiger 和 MMAPv1 共存。MMAPv1 为3.0的默认引擎,同时该版本引擎(MMAPv1)支持了集合级锁并且更好地充分利用存储空间;
  • 提供更强大的运维管理功能;
  • 配置文件选项改动
  • WiredTiger 不再支持 db.fsyncLock(),touch(MMAPv1 支持 touch);
  • 更严格的复制集配置设置验证
  • 移除了 local.slaves 集合;
  • 复制集的 FATAL 状态不再存在;
  • mongodump, mongorestore, mongoexport, mongoimport, mongofiles, 和 mongooplog 这些工具命令必须连接的是运行中的 mongodb 实例;
  • 一些选项已移除
  • 移除了 db.addUser()方法,改用 db.createUser();
  • TLS/SSL Configuration 选项有改变;
  • SSLv3 密码不再可用;
  • createIndex(), ensureIndex(), and createIndexes 不再支持 dropDups 选项;
  • 克隆(cloneCollection)到已经存在的集合将会报错;
  • 服务器状态(serverStatus)输出不再返回 workingSet, indexCounters 和 recordStats;
  • Date 与 Timestamp 类型在做比较、排序时策略有所改变,建议先修复好数据为统一类型再升级;
  • closeAllDatabases,getoptime,text,indexStats, db.collection.getIndexStats(), db.collection.indexStats() 这些命令或方法已移除;
  • diagLogging,eval,db.eval(),db.collection.copyTo() 不建议使用;
  • 不建议运行在32位操作系统,仅二进制包可以在32位 OS 上安装,且 WiredTiger 只支持64位
  • 对集合名称的合法性验证更严格,比如长度;
  • 不建议直接访问 system.indexes 和 system.namespaces 集合,建议使用 createIndexes 和 listIndexes 命令来代替;
  • findAndModify数据返回规则有变动
  • 当在 _id 后有点的查询(eg. "_id.name": "name",)作为条件时使用“upsert:true”规则有改动
  • 复制集模式下 Primary 节点 StepDown 处理方式做了变化;
  • 优化 explan 函数,可以支持 count,find,group,aggregate,update,remove等操作的查询计划显示,结果更全面更详细;
  • 重写 mongodb 工具,所有 mongodb 自带工具均使用 Go 语言重写,特别是在 mongodump 和 mongorestore 添加了并行机制,这样可以大大加快数据的导出和导入;
  • 日志输出控制,将日志分为不同的模块,其中包括 ACCESS、COMMAND、CONTROL、GEO、INDEX、NETWORK、QUERY、REPL、SHARDING、STORAGE、JOURNAL 和 WRITE 等。用户可以动态调整每个模块的日志级别,更方便于系统问题诊断;
  • 索引构建优化,后台索引建立过程中,不能进行删库删表删索引操作,且后台索引建立过程不会因此自动中断。另外,使用 createIndexes 命令可以同时建立多个索引,并且只扫描一遍数据,提升了建索引的效率;
  • Journal数据默认不会即时刷盘,系统宕机会丢失最多 100MB Journal 数据;
  • 不再兼容2.2.1以前版本写入的 oplog;
  • 如果使用 WiredTiger 引擎则可以设置 mongodb 最大可使用内存大小;
  • 其他细节改动。

下载地址

驱动兼容性

PHP DriverMongoDB 2.4MongoDB 2.6MongoDB 3.0MongoDB 3.2
PHPLIB 1.0 + mongodb-1.1
mongodb-1.1
mongodb-1.0
mongo-1.6
mongo-1.5

数据备份

通过在复制集中加入一个备份的 SECONDARY 节点的方式进行备份。备份节点的版本选择和升级前的其他节点保持一致,在升级前把备份节点从复制集中移除。

数据完整性校验

简单的对每个库下的集合的文档数量在升级前后进行比对来做校验,数量在预期之类即通过。也可以做一些比如抽样检查手段。

MongoDB 数据丢失问题

MongoDB 的数据安全包括以下几个概念:

  • 写关注(Write Concern)
  • 恢复日志(Journal)
  • WiredTiger checkpoints

Write Concern

写关注级别含义描述
w=0不确认立即返回,不管是否写入成功,安全性差
w=1确认需当前服务器确认写入内存成功
w=N复制集确认需要主节点和 N-1 个从节点确认写成功
w=majority大多数确认需要包括主节点的大多数的节点确认写成功
w=<tag set>复制集标签确认需要被整个表情集的成员确认写成功
j=true确认已写入 journal 文件需要主节点并且 journal 已刷盘确认写成功

Journal & checkpoints

MongoDB 为了在发生故障时保证数据的持久性,引入了类似于 Oracle 的 Redo 日志:预写事务日志 Journal,解决因系统断电或者崩溃时导致内存数据丢失的问题。

MMAP引擎

打开 Journal,写数据会先写入到 private view(用于写入到 Journal 文件)里然后间隔每 100ms(默认)进行落盘操作,再将数据写入到 shared view(用于写入到数据文件中)中。如果不能接受 100ms 的数据丢失可以写关注选项设置 {j:1},此时最多丢失 30ms Journal 数据(因为 mongodb 为提高并发性会累积到 30ms 再批量处理)。但这种方式不能解决 30ms 的数据丢失和硬盘损坏情况导致的数据丢失问题。注:也可以通过“storage.syncPeriodSecs(生产环境不建议修改)”和“storage.journal.commitIntervalMs”来设定数据文件和 Journal 日志文件的 fsync 的频率。

相比 MMAP MMAPv1 刷盘机制有些不同,如果 Journal 文件和数据文件不是放在“同一块磁盘”上(比如,不同物理盘,RAID盘,LVM 卷),则默认的 Journal 提交间隔时间是 30ms,另外如果写时加上 {j:1} 选项,那么 mongod 会降低提交间隔时间到设置值的1/3;

WiredTiger 引擎

引入了 checkpoint 概念,它会对数据做快照并持久化到磁盘上,并且数据可以从最后一个 checkpoint 中恢复。如果MongoDB 非正常退出,通过 checkpoint 和 Journal 配合,可以先从最后一个 checkpoint 中恢复数据,并且通过Journal数据恢复最近一次 checkpoint 的数据到系统退出间丢失的数据。MongoDB 默认配置每隔60秒或者 Journal 等待写入的数据达到 2G 时,会创建一个新的 checkpoint。

对于写操作,首先被写入 Journal,然后在内存中保存变更数据,条件满足后提交一个新的检测点,即检测点之前的数据只是在Journal 中持久存储,但并没有在 MongoDB 的数据文件中持久化,延迟持久化可以提升磁盘效率。Journal 日志同 MMAP 默认每隔100毫秒刷盘一次,每 100M 数据生成一个新的 Journal 文件,Journal 默认使用了 snappy 压缩,检测点创建后,此前的Journal 日志即可清除。这种情况下最多丢失 100ms(写时如果设置 {j:1} 选项则会立即同步到 Journal文件)或100M的Journal数据。注:同上 commitIntervalMs 时间可配置

getLastError()

查询上次操作结果是否出现错误。在2.6版本之前需要程序在执行完写操作后再自行去调用 getLastError() 方法来获取上次操作的结果,这个步骤一般都是驱动帮忙做了,对业务程序透明。2.6及之后版本 db.collection.insert(), db.collection.update(), db.collection.save() 和 db.collection.remove() 这些方法执行完后返回值自带有错误信息,这样就不用再多去调用一次 getLastError()。

fsync

由于 MongoDB 数据默认会每60秒进行一次刷盘,这样如果出现意外故障就可能导致60s内的数据丢失。驱动中在写方法中加入设置选项 {fsync: true} 表示要强制刷盘,会确认数据已刷盘。但这种方式也不能解决硬盘损坏情况导致的数据丢失问题,也严重影响性能!

单机问题

单机模式始终无法确保数据的绝对安全,但可以采用集群的模式(复制集、分片集群)并且写关注设置为 {w:majority} 来解决。

总结

1、在2.2版本下,默认 {w:0} 时系统崩溃出现数据丢失,可以通过升级到2.4并且写关注为 {w:1};
2、在3.0版本下,{j:0} 时系统崩溃出现数据丢失,可以通过设置写关注 {j:1};
3、在3.0版本下,复制集模式下 {w:1,j:1} 时系统崩溃出现数据丢失,可以设置写关注 {w:majority};

2.2.1升级到2.4

准备工作

准备项结果备注
安装2.4.14版本 mongodb 独立安装在一个目录
检查所有成员版本是否均为2.2.1 执行 db.version()
检查 authentication 方式为兼容项检查
检查 system.users 文档为兼容项检查
备份数据

概述

由于2.2与2.4的数据库数据是兼容的,升级过程可以单独地对每个成员进行升级。这样同时只会影响某一个成员而不影响整体服务。

步骤

编号步骤详细备注
1升级 SECONDARY 节点 db1停止 mongod 进程,再使用2.4的 mongod 启动服务,等待查看 rs.status(),状态恢复后即升级成功
2升级 SECONDARY 节点 db2同步骤1
3对 PRIMARY 节点 db0 调整为 SECONDARY 节点在该节点上执行 rs.stepDown() 方法,直到成功调整为 SECONDARY 节点并且确认其他某个 SECONDARY 被调整为 PRIMARY节点
4升级 SECONDARY 节点 db0同步骤1
5数据完整性校验

2.4升级到2.6

准备工作

准备项结果备注
安装2.6.12版本 mongodb 独立安装在一个目录
检查所有成员版本是否均为2.4.14 执行 db.version()
备份数据
检查 authentication 方式为兼容项检查
使用 db.upgradeCheckAllDBs() 检查是否能升级 使用2.6的 mongo 脚本去连接2.4的 mongod 进程,执行db.upgradeCheckAllDBs() 命令进行检查
检查业务程序中是否有使用 aggregate如果有需要进行兼容性修改
检查配置文件中的 bindIp 修改为正确的

概述

升级到2.6必须当前运行的 mongod 版本为2.4。从2.4升级到2.6过程是二进制兼容的“插入式”升级,停止2.4的 mongod 进程再使用2.6的 mongod 重启。2.4与2.6的数据库数据是兼容的。

步骤

假设此时的各个节点角色是最初的角色。

编号步骤详细备注
1升级 SECONDARY 节点 db1停止 mongod 进程,再使用2.6的 mongod 启动服务,等待查看 rs.status(),状态恢复后即升级成功
2升级 SECONDARY 节点 db2同步骤1
3对 PRIMARY 节点 db0 调整为 SECONDARY 节点在该节点上执行 rs.stepDown() 方法,直到成功调整为 SECONDARY节点并且确认其他某个 SECONDARY 被调整为 PRIMARY 节点
4升级 SECONDARY 节点 db0同步骤1
5数据完整性校验

php驱动升级

准备工作

准备项结果备注
PHP 扩展安装新版驱动 mongo-1.6

2.6升级到3.0

准备工作

准备项结果备注
安装3.0.12版本 mongodb 独立安装在一个目录
检查所有成员版本是否均为2.6.12 执行 db.version()
备份数据
检查 authentication 方式为兼容项检查
3.0不再兼容2.2.1以前版本写入的 oplog当前 oplog 是2.2.1版本生成的如果先于2.2.1版本有写入的 oplog 则需要等待其被完全覆盖后才能升级
配置文件合法性检查 为兼容项检查,3.0更严格

概述

升级到3.0必须当前运行的 mongod 版本为2.6。从2.6升级到3.0过程是二进制兼容的“插入式”升级,停止2.6的 mongod 进程再使用3.0的 mongod 重启。2.6与3.0(不使用WiredTiger情况下)的数据库数据是兼容的。已经升级到3.0那么将不可以降级到2.6.8以前的版本;

步骤

假设此时的各个节点角色是最初的角色。

编号步骤详细备注
1升级 SECONDARY 节点 db1停止 mongod 进程,再使用3.0的 mongod 启动服务,等待查看rs.status(),状态恢复后即升级成功
2升级 SECONDARY 节点 db2同步骤1
3对PRIMARY节点 db0 调整为 SECONDARY 节点在该节点上执行 rs.stepDown() 方法,直到成功调整为 SECONDARY 节点并且确认其他某个 SECONDARY 被调整为 PRIMARY 节点
4升级 SECONDARY 节点 db0同步骤1
5数据完整性校验

3.0升级引擎为 wiredtiger

准备工作

准备项结果备注
检查所有成员版本是否均为3.0
WiredTiger 版配置文件

WiredTiger 版配置文件(以 db0 为例):

systemLog:
   destination: file
   path: "/data/mongodb/27017/mongod.log"
   logAppend: true
   quiet: true
storage:
   dbPath: "/data/mongodb/27017"
   engine: "wiredTiger"
   journal:
      enabled: true
   wiredTiger:
       engineConfig:
           cacheSizeGB: 8
processManagement:
   fork: true
   pidFilePath: "/data/mongodb/27017/mongod.pid"
net:
   port: 27017
   http: 
       RESTInterfaceEnabled: true
replication:
    oplogSizeMB: 20480
    replSetName: rs_0

概述

MongoDB 复制集模式下支持不同节点使用不同的存储引擎。这样就可以逐步替换各个节点的引擎,从 SECONDARY 接口开始。但不同的存储引擎间数据是不相互兼容的,也就是说要存储在不同的目录下。

步骤

假设此时的各个节点角色是最初的角色。

编号步骤详细备注
1停止 SECONDARY 节点db1执行 db.shutdownServer()
2准备一个新目录 给将采用新引擎 WiredTiger 的 mongo 使用
3启动节点启动时使用新的已配置好(使用 WiredTiger)的配置文件启动后将自动从其他节点拉取数据。可以通过db.serverStatus()命令查看 storageEngine 信息检查是否使用的是 WiredTiger 引擎
4升级 SECONDARY 节点 db2 引擎同步骤1、2、3
5对 PRIMARY 节点 db0 调整为 SECONDARY 节点在该节点上执行 rs.stepDown() 方法,直到成功调整为 SECONDARY 节点并且确认其他某个 SECONDARY 被调整为 PRIMARY 节点
6升级 SECONDARY 节点 db0 引擎同步骤1、2、3
7数据完整性校验
//启动命令也可以动态指定小于 1G 的 cache_size
/data/src/mongodb3.0/bin/mongod --wiredTigerEngineConfigString="cache_size=512M" -f /data/src/mongodb3.0/conf/mongod.cnf

升级前测试环境测试

每次版本升级前建议在业务测试环境对新版本的 MongoDB、php MongoDB 驱动进行充分的测试。已检验是新版本否对当前业务会有兼容性问题产生。

升级前模拟演练

建议搭建一套类似生产环境的复制集模式 MongoDB 集群并且导入线上生产环境数据进行逐个版本升级演练,尤其是2.4升级到2.6及2.6升级到3.0要重点关注。

参考链接

添加新评论