写在前面
版本从2.6.6升级到3.0.7
环境描述
服务器相关信息
系统版本: centos6.5
内核版本: 2.6.32-358.6.2.el6.x86_64
数据库版本
升级前版本: 2.6.6
升级后版本: 3.0.7
数据库集群模拟环境:
二个mongos
三个config
三个分片,每个分片是一个一主,一从,一仲裁的副本集
为什么要升级
一方面,写这篇文章的时候mongodb已经3.4了,3.4的mongo有很多新的优秀特性,升级是一个趋势,就是时间早晚的问题。另一方面更加直接,3.0支持wiredtiger,压缩性能相对mmapv1高很多,在数据量大的情况下,能帮助攻击节省很多成本。
必备基础知识:
因为是药升级到3.0.7,所有以下官方文档全部是3.0版本的
相关官方文档:
这几篇文章一定要看明白,看仔细,尤其是最后一篇,前两个是帮助理解mongodb集群,最后一篇是详细的升级步骤
mongodb升级相关博客:
- mongodb升级到3.0.2(2.6.9到3.0.2) 除了官网之外,我主要参考了这个文章
升级演练方案
就算明白升级的大概流程原理,也需要构建一个可用的测试环境测试一下。当然,这里比较简单的方案就是找一台环境相同的服务器,然后在这个机器上启动相应的mongodb进程,构建集群
如果没有可用的服务器,使用的是mac,也可以使用mac代替服务器(不推荐)
但是这两种方案都有一定的问题,因为是测试所以很有可能因为操作错误,需要干掉当前集群,重新起来一个然后再测试,或者是需要部署一个新版本的集群,这样前面两个方法问题就比较大,目前我采用的方式是使用docker搭建mongo集群,通过docker-compose可以一键启动和删除,非常方便,下面重点说下我使用的这个方法(当然,缺点是相对比较麻烦)
基础环境
docker version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Client:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 21:15:28 2016
OS/Arch: darwin/amd64
Server:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 23:54:00 2016
OS/Arch: linux/amd64
docker-compose version
1
2
3
4docker-compose version 1.8.0, build f3628c7
docker-py version: 1.9.0
CPython version: 2.7.9
OpenSSL version: OpenSSL 1.0.2h 3 May 2016
项目结构
1 | ├── LICENSE |
使用说明
1 | ./run.sh |
注意
startup-mongo-cluster-2.6.9.sh
可能会出现个别节点没有起来的情况,如果发现节点没有完全起来,可以在执行一次。因为为了快速搭建起来集群,这个方案中还有一些细节没有处理好,见谅。
升级前注意事项
降级限制
一旦升级到mongo3.0,则mongo集群就不能再降级到2.6.8以下的版本了
authSchema要求
3.0支持的最低的authSchema版本是3,低于3mongos将无法启动。(authSchema更新)
数据备份
任何版本的升级前,一定要线备份config server
中的数据
升级时间选择
最好在业务量比较小的时候进行升级,这个好处多多,大家都明白
具体升级步骤
根据升级过程时间的消耗,建议将升级分为两个阶段(我们是这么处理的)。第一阶段:升级mongos和config,第二阶段:升级所有分片
关闭负载均衡器
注意这里的负载均衡是mongo自身用于均衡各个分片数据量的,关闭负载均衡是为了阻止数据chunk移动,放置因为升级过程因为数据迁移带来问题
代码示例
1 | 连接mongos |
分析
- 安全性:这一步是比较安全的,没有安全隐患
- 会滚方案:很简单,
sh.setBalancerState(true)
,就能重新打开负载均衡器了 - 热升级保障: 这个操作不会影响在线业务
升级元数据,升级mongos server
原理
- 升级元数据
- 升级mongos
安全性
元数据升级目前我没有找到简单的方式去回滚,所以这个操作基本是不可逆的。但是,幸运的是,我在升级整个测试环境的mongo集群的时候,元数据升级成功,但是3.0的mognos却无法启动,当时测试环境出现故障,情急之下,使用2.6的mongos启动,成功了,也没有遇到什么其他问题,所以万一元数据升级之后出现问题,还是有临时方案解决的。
上面说到了升级元数据之后新的mongos无法启动,是因为遇到了这样的错误:1
Failed to authenticate *** with mechanism MONGODB-CR: AuthenticationFailed AuthSchemaIncompatible Authorization data schema version 1 not support
这个问题概括来说就是authSchema版本过低导致的,3.0.7支持的authSchema最低版本是3,但是当前版本是1,事实上,2.6.6默认的authSchema版本是3。出现这种问题,是因为我们的2.6.6版本的数据库是升级过来的。经过我的测试,2.4.3版本默认的authSchema版本就是1,所以这个历史遗留问题。如果你系统刚好也有这种情况,升级前最好先参考下这里解决,以下是升级authSchema命令:
1 | use admin |
注意上面那个命令是比较危险的,原因有以下两点:
- authSchema升级之后如果对程序没有影响,那么无所谓,如果有影响,这个要降级到之前的版本,会比较麻烦参考这里
- 如果authSchema升级之后,再将整个集群升级至3.0,此时如果再想降级到2.6,那么启动mongos,mongod实例的时候,不能使用
--auth
参数,因为authSchema
已经不兼容了(除非有所备份) - 以上命令,作用域mongos的同时也会作用于所有的分片上,如果你不想在分片上也生效,那么可以这么做:
db.getSiblingDB("admin").runCommand({authSchemaUpgrade: 1, upgradeShards: false })
回滚方案
回滚authSchema
参考这里
回滚mongos版本,直接使用2.6的二进制文件启动mongos实例就可以了
回滚元数据,这个我没有做过,目前也没有好的方案,通常情况下,2.6元数据升至3.0是没有问题的(没有操作失误)
热升级保障
如果下游有负载均衡,或者使用多个mongos实例连接方式,那么重启单个mongos实例带来的影响是可以容忍的(如果不是金融等业务的话)。如果是连接的单点mongos,重启肯定会带来一定影响,这个术语程序设计的问题了,不在这里讨论。
我们采用的方式是mongos之上搭建负载均衡器,选择在业务量小的时候做升级,没有太大问题
代码示例
1 | 升级元数据 |
这里只是升级了一个mongos
,同理其他所有mongos
升级config server
原理
- 备份
config server
的数据 - 关闭就版本节点
- 使用原来的配置打开新版本节点(不使用wiredtiger引擎)
注意事项
- 升级之前一定要备份
config server
数据,因为config server
的数据是保证整个集群正常运转的关键 - 升级
config server
的过程中,一定要保证只要处在升级过程中,都至少有一个config server
是shutdown状态,同时至少有一个config server
是up状态。因为,有一个shutdown的,就能保证所有config server
数据都无法被修改,有一个up的,就能保证集群可用。这个非常关键,一旦config server
数据不一致,集群将无法运转 - 3.0支持wiredtiger存储引擎,如果使用的话,
config server
的dbpath
需要修改,不能使用原来的数据目录(这里其实推荐不要改变存储引擎,因为config server
占用的磁盘空间相对来说很小,升级过程中我们没有修改存储引擎)
安全性
只要按照正确的步骤操作,安全性没有问题,因为升级并不会影响到数据
热升级保障
只要保障有一个以上的config server
正常运行,服务就没有问题
回滚方案
使用原来的mongo二进制文件重新启动mongod服务即可
代码示例
1 | 导出数据 |
升级分片
原理
因为每一个分片都是一个副本集,所有分片的升级就相当于是副本集的升级,升级副本集按照以下步骤:
- 升级arbit
- 升级secondary
- primary stepDown(stepDown会造成一定量的数据读写失败)
- 升级primary
注意事项
因为2.6升级至3.0还有一个特性地方在于如果使用wiredtiger,必须重新同步一次数据,因为原来的dbpath是无法使用的。所以我们的做法是先给副本集添加一个新的(3.0)secondary节点,让数据以副本集的内部机制复制一份到新添加的节点上,确认没有问题之后,再升级原来的副本集,最后干掉新添加的节点。
这里有两点需要注意:
- 集群中允许存在不同版本的mongod实例
- 主从复制的过程会给主节点带来一定的压力,所以最好不要选择在业务繁忙的时候进行升级(最好在正常人都睡觉的时候,哈哈)
- 主从复制的时间相对较长,这也是上面为什么建议升级分为两个阶段的原因
安全性
数据分片的升级相对于mongos, config
的升级安全性更高了,一个方面因为一个分片不会影响到整个集群,另外一个方面,完善的副本集机制为升级提供了保障。这步非常轻松(但是工作量非常大)
回滚方案
副本集的升级和降级的步骤基本一样,可以参考升级的步骤降级
热升级保障
这个又副本集的高可用机制保证,但是同步数据的时候是有可能导致系统负载过高的,这里最好多观察。
升级代码示例
1 | 升级arbit |
打开负载均衡器
最后,一定不要忘记打开负载均衡
1 | sh.setBalancerState(true) |
线上升级按照上述步骤遇到的问题
首先明确的是,上面的升级过程本身是没有问题的,然后,请一定要看看这篇文章
我遇到了一模一样的问题,mongodb进程的内存占用会持续走高,一直到跑满内存,然后被系统干掉。
我采用的任何限制内存的方案的结果都是一样的,因为只要是通过外部限制内存使用,要么根本没法限制,要么就会在到达限制的时候干掉mongodb进程。
最开始的时候我们使用为机器添加内存的方式,最终的结果是将内存变为原来的8倍,依然会有这种问题
最终的解决方案是,重新替换为mmapv1寸处引擎,wiredtiger这名起起的却是生动,有令人期待的吞吐量和更高的数据压缩比,但是却难以控制(目前)
一下是我们解决问题过程中查阅的文档:
内存限制相关:
cgroups方式
Easy Steps to Limit Mongodb Memory Usage,照着这个实践过
相关的讨论
Limit the RAM memory usage in MongoDB
Is there any option to limit mongodb memory usage?
Mongod start with memory limit
MongoDB limit memory
mongodb - wiredtiger memory usage growing
mongodb memory usage is going high even if only insertions are made
Mongodb - > 90% Memory Usage Of Mongod
Mongodb 3.0 wiredTiger storage engine memory usage too high.
mongodb memory leak or big collection?
mongodb - wiredtiger memory usage growing
FAQ: MongoDB Storage
how to release the caching which is used by Mongodb?
mongodb状态查询详解
MongoDB状态查询db.serverStatus()详解
MongoDB状态查询详解:db.serverStatus()
确定内存增长不是因为索引导致的
查看wiredtiger cache size1
2
3
4
5
6status=db.serverStatus()
memory = 0
Object.keys(status.wiredTiger.cache).forEach(function(key){
memory += status.wiredTiger.cache[key]
})
memory = memory / 2014 / 1024 / 1024