MongoDB主从复制与分片技术,和运维技术的状态查询
主从复制
我们知道sql server能够做到读写分离,双机热备份和集群部署,当然MongoDB也能做到,实际应用中我们不希望数据库采用单点部署,
如果碰到数据库宕机或者被毁灭性破坏那是多么的糟糕。
一:主从复制
1: 首先看看模型图
2: 从上面的图形中我们可以分析出这种架构有如下的好处:
<1> 数据备份。
<2> 数据恢复。
<3> 读写分离。
3:下面我们就一一实践
实际应用中我们肯定是多服务器部署,限于自己懒的装虚拟机,就在一台机器上实践了。
第一步:我们把mongodb文件夹放在D盘和E盘,模拟放在多服务器上。
第二步:启动D盘上的mongodb,把该数据库指定为主数据库,其实命令很简单:>mongodb --dbpath='XXX' --master,
端口还是默认的27017.
第三步:同样的方式启动E盘上的mongodb,指定该数据库为从属数据库,命令也很简单,当然我们要换一个端口,比如:8888。
source 表示主数据库的地址。
>mongod --dbpath=xxxx --port=8888 --slave --source=127.0.0.1:27017
第四步:从图中的红色区域我们发现了一条:“applied 1 operations"这样的语句,并且发生的时间相隔10s,也就说明从属数据库每10s
就向主数据库同步数据,同步依据也就是寻找主数据库的”OpLog“日志,可以在图中红色区域内发现”sync_pullOpLog“字样。
接下来我们要做的就是测试,惊讶的发现数据已经同步更新,爽啊。
4: 如果我还想增加一台从属数据库,但是我不想在启动时就指定,而是后期指定,那么mongodb可否做的到呢?答案肯定是可以的。
我们的主或者从属数据库中都有一个叫做local的集合,主要是用于存放内部复制信息。
好,那么我们就试一下,我在F盘再拷贝一份mongodb的运行程序,cmd窗口好多啊,大家不要搞乱了。
看上面的log,提示没有主数据库,没关系,某一天我们良心发现,给他后期补贴一下,哈哈,再开一个cmd窗口,语句也就是
在sources中add一个host地址,最后发现数据也同步到127.0.0.1:5555这台从属数据库中....
5: 读写分离
这种手段在大一点的架构中都有实现,在mongodb中其实很简单,在默认的情况下,从属数据库不支持数据的读取,但是没关系,
在驱动中给我们提供了一个叫做“slaveOkay"来让我们可以显示的读取从属数据库来减轻主数据库的性能压力,这里就不演示了。
二:副本集
这个也是很牛X的主从集群,不过跟上面的集群还是有两点区别的。
<1>: 该集群没有特定的主数据库。
<2>: 如果哪个主数据库宕机了,集群中就会推选出一个从属数据库作为主数据库顶上,这就具备了自动故障恢复功能,很牛X的啊。
好,我们现在就来试一下,首先把所有的cmd窗口关掉重新来,清掉db下的所有文件。
第一步: 既然我们要建立集群,就得取个集群名字,这里就取我们的公司名shopex, --replSet表示让服务器知道shopex下还有其他数据库,
这里就把D盘里面的mongodb程序打开,端口为2222。指定端口为3333是shopex集群下的另一个数据库服务器。
第二步: 既然上面说3333是另一个数据库服务器,不要急,现在就来开,这里把E盘的mongodb程序打开。
第三步: ok,看看上面的日志红色区域,似乎我们还没有做完,是的,log信息告诉我们要初始化一下“副本集“,既然日志这么说,那我也就
这么做,随便连接一下哪个服务器都行,不过一定要进入admin集合。
第四步: 开启成功后,我们要看看谁才能成为主数据库服务器,可以看到端口为2222的已经成为主数据库服务器。
第五步:我们知道sql server里面有一个叫做仲裁服务器,那么mongodb中也是有的,跟sql server一样,仲裁只参与投票选举,这里我们
把F盘的mongodb作为仲裁服务器,然后指定shopex集群中的任一个服务器端口,这里就指定2222。
然后我们在admin集合中使用rs.addArb()追加即可。
追加好了之后,我们使用rs.status()来查看下集群中的服务器状态,图中我们可以清楚的看到谁是主,还是从,还是仲裁。
不是说该集群有自动故障恢复吗?那么我们就可以来试一下,在2222端口的cmd服务器按Ctrl+C来KO掉该服务器,立马我们发现
在3333端口的从属服务器即可顶上,最后大家也可以再次使用rs.status()来看下集群中服务器的状态。
分片技术
在mongodb里面存在另一种集群,就是分片技术,跟sql server的表分区类似,我们知道当数据量达到T级别的时候,我们的磁盘,内存
就吃不消了,针对这样的场景我们该如何应对。
一:分片
mongodb采用将集合进行拆分,然后将拆分的数据均摊到几个片上的一种解决方案。
下面我对这张图解释一下:
人脸: 代表客户端,客户端肯定说,你数据库分片不分片跟我没关系,我叫你干啥就干啥,没什么好商量的。
mongos: 首先我们要了解”片键“的概念,也就是说拆分集合的依据是什么?按照什么键值进行拆分集合....
好了,mongos就是一个路由服务器,它会根据管理员设置的“片键”将数据分摊到自己管理的mongod集群,数据
和片的对应关系以及相应的配置信息保存在"config服务器"上。
mongod: 一个普通的数据库实例,如果不分片的话,我们会直接连上mongod。
二: 实战
首先我们准备4个mongodb程序,我这里是均摊在C,D,E,F盘上,当然你也可以做多个文件夹的形式。
1:开启config服务器
先前也说了,mongos要把mongod之间的配置放到config服务器里面,理所当然首先开启它,我这里就建立2222端口。
2: 开启mongos服务器
这里要注意的是我们开启的是mongos,不是mongod,同时指定下config服务器,这里我就开启D盘上的mongodb,端口3333。
3:启动mongod服务器
对分片来说,也就是要添加片了,这里开启E,F盘的mongodb,端口为:4444,5555。
4: 服务配置
哈哈,是不是很兴奋,还差最后一点配置我们就可以大功告成。
<1> 先前图中也可以看到,我们client直接跟mongos打交道,也就说明我们要连接mongos服务器,然后将4444,5555的mongod
交给mongos,添加分片也就是addshard()。
这里要注意的是,在addshard中,我们也可以添加副本集,这样能达到更高的稳定性。
<2>片已经集群了,但是mongos不知道该如何切分数据,也就是我们先前所说的片键,在mongodb中设置片键要做两步
①:开启数据库分片功能,命令很简单 enablesharding(),这里我就开启test数据库。
②:指定集合中分片的片键,这里我就指定为person.name字段。
5: 查看效果
好了,至此我们的分片操作全部结束,接下来我们通过mongos向mongodb插入10w记录,然后通过printShardingStatus命令
查看mongodb的数据分片情况。
这里主要看三点信息:
① shards: 我们清楚的看到已经别分为两个片了,shard0000和shard0001。
② databases: 这里有个partitioned字段表示是否分区,这里清楚的看到test已经分区。
③ chunks: 这个很有意思,我们发现集合被砍成四段:
无穷小 —— jack0,jack0 ——jack234813,jack234813——jack9999,jack9999——无穷大。
分区情况为:3:1,从后面的 on shardXXXX也能看得出。
运维技术
这一篇我们以管理员的视角来看mongodb,作为一名管理员,我们经常接触到的主要有4个方面:
1. 安装部署
2. 状态监控
3. 安全认证
4. 备份和恢复,
下面我们就一点一点的讲解。
一:安装部署
我之前的文章都是采用console程序来承载,不过在生产环境中这并不是最佳实践,谁也不愿意在机器重启后满地找牙似找mongodb,
在mongodb里面提供了一个叫做“服务寄宿”的模式,我想如果大家对wcf比较熟悉的话很容易听懂。好了,我们实践一下,这里我开一下D盘
里面的mongodb。
这里要注意的有两点:
<1> logpath: 当我们使用服务寄宿的时候,用眼睛都能想明白肯定不会用console来承载日志信息了。
<2> install: 开启安装服务寄宿,很happy啊,把管理员的手工操作降低到最小,感谢mongodb。
好了,console程序叫我看log日志,那我就看看,发现mongodb已经提示我们如何开启mongodb,接着我照做就是了。
还要提醒大家一点的就是,这些命令参数很多很复杂也就很容易忘,不过没关系,数据库给我们提供了一个help方法,我们可以
拿mongod和mongo说事。
mongod:
mongo:
二:状态监控
监控可以让我们实时的了解数据库的健康状况以及性能调优,在mongodb里面给我们提供了三种方式。
1:http监视器
这个我在先前的文章中也提到了,这里就不赘述了。
2:serverStatus()
这个函数可以获取到mongodb的服务器统计信息,其中包括 :全局锁,索引,用户操作行为等等这些统计信息,对管理员来说非常
重要,具体的参数含义可以参考园友:http://www.cnblogs.com/xuegang/archive/2011/10/13/2210339.html
这里还是截个图混个眼熟。
3:mongostat
前面那些统计信息再牛X,那也是静态统计,不能让我观看实时数据变化,还好,mongodb里面提供了这里要说的mongodstat
监视器,这玩意会每秒刷新,在实际生产环境中大有用处,还是截张图,很有意思,是不是感觉大军压境了。
三: 安全认证
作为数据库软件,我们肯定不想谁都可以访问,为了确保数据的安全,mongodb也会像其他的数据库软件一样可以采用用户
验证的方法,那么该怎么做呢?其实很简单,mongodb提供了addUser方法,还有一个注意点就是如果在admin数据库中添加
将会被视为“超级管理员”。
上面的admin用户将会被视为超级管理员,“jack”用户追加的第三个参数表示是否是“只读用户”,好了,该添加的我们都添加了,
我们第一次登录时不是采用验证模式,现在我们使用--reinstall重启服务并以--auth验证模式登录。
好了,我们进入test集合翻翻数据看看情况,我们发现jack用户始终都是没有写入的权限,不管是授权或者未授权。
四:备份和恢复
这玩意的重要性我想都不需要我来说了吧,这玩意要是搞不好会死人的,mongodb里面常用的手段有3种。
1: 直接copy
这个算是最简单的了,不过要注意一点,在服务器运行的情况下直接copy是很有风险的,可能copy出来时,数据已经遭到
破坏,唯一能保证的就是要暂时关闭下服务器,copy完后重开。
2:mongodump和mongorestore
这个是mongo给我们提供的内置工具,很好用,能保证在不关闭服务器的情况下copy数据。
为了操作方便,我们先删除授权用户。
好了,我们转入正题,这里我先在D盘建立一个backup文件夹用于存放test数据库。
快看,数据已经备份过来了,太爽了,现在我们用mongorestore恢复过去,记住啊,它是不用关闭机器的。
提一点的就是 drop选项,这里是说我将test数据恢复之前先删除原有数据库里面的数据,同样大家可以通过help查看。
3:主从复制
这个我在上上篇有所介绍,这里也不赘述了。
其实上面的1,2两点都不能保证获取数据的实时性,因为我们在备份的时候可能还有数据灌在内存中不出来,那么我们
想说能不能把数据暴力的刷到硬盘上,当然是可以的,mongodb给我们提供了fsync+lock机制就能满足我们提的需求。
fsync+lock首先会把缓冲区数据暴力刷入硬盘,然后给数据库一个写入锁,其他实例的写入操作全部被阻塞,直到fsync
+lock释放锁为止。
这里就不测试了。
加锁: db.runCommand({"fsync":1,"lock":1})
释放锁: db.$cmd.unlock.findOne()
驱动技术实践
http://www.cnblogs.com/huangxincheng/archive/2012/03/09/2386054.html
MongoDB集群分片安装与配置
软件准备
下载mongoDB(mongoDB下载地址),笔者使用的是mongoDB 2.0.4的Linux 64-bit版本。
解压:tar xzf mongo.tgz
默认情况下,mongoDB将数据存储在/data/db目录下,但它不会自动创建该目录,所以我们需要手动创建它:
$ sudo mkdir -p /data/db/
$ sudo chown `id -u` /data/db
也可以使用--dbpath参数来指定别的数据库目录。
如果只是想在单机上测试一下mongoDB的话,非常简单,首先启动MongoDB server,
$ ./mongodb-xxxxxxx/bin/mongod
在另外一个终端,连接到我们启动的server:
$ ./mongodb-xxxxxxx/bin/mongo
> db.foo.save( { a : 1 } )
> db.foo.find()
Sharding Cluster介绍这是一种可以水平扩展的模式,在数据量很大时特给力,实际大规模应用一般会采用这种架构去构建monodb系统,其构架图如下:
要构建一个 MongoDB Sharding Cluster,需要三种角色:
Shard Server:每个Shard可以是一个mongod 实例,也可以是一组mongod实例,用于存储实际的数据分片,实际生产环境中一个shard server角色可由几台机器组个一个relica set承担,防止主机单点故障。
Config Server:为了将一个特定的collection存储在多个Shard中,需要为该collection指定一个Shard key,决定该记录属于哪个chunk。mongod 实例,存储了整个 Cluster Metadata,其中包括 chunk 信息。具体来说,配置服务器可以存储以下信息:
每个chunk的Shard key范围
chunk在各Shard的分布情况
集群中所有DB和collection的Sharding配置信息
Route Server:mongos 实例,前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。路由首先询问配置服务器需要到哪个Shard上查询或保存记录,然后连接相应的Shard执行操作,最后将结果返回给客户端。
整体配置概览首先说一下笔者的分片搭建环境,三台服务器,操作系统都是Ubuntu 11.04 Server 版,64位。IP分别为192.168.56.191、192.168.56.168、192.168.56.169,具体如下表所示:
主机 |
IP |
服务及端口 |
---|---|---|
server1 |
192.168.56.191 |
mongod shard11:27017 mongod shard12:27018 mongod config1:20000 mongs1:30000 |
server2 |
192.168.56.168 |
mongod shard12:27017 |
server3 |
192.168.56.169 |
mongod shard13:27017 |
这样我们集群包含了:
2个shard(mongod)、3个replica
shard1:192.168.56.191:27017、192.168.56.168:27017、192.168.56.169:27017
shard2:192.168.56.191:27018、192.168.56.168:27018、192.168.56.169:27018
3个config server:192.168.56.191:20000、192.168.56.168:20000、192.168.56.169: 20000
3个mongos:192.168.56.191:30000、192.168.56.168:30000、192.168.56.169: 30000
步骤1)创建文件夹
在各台server上创建shard文件目录
Server1:
mkdir -p data/db/shard11
mkdir -p data/db/shard21
mkdir -p data/db/shard12
mkdir -p data/db/shard22
mkdir -p data/db/shard13
mkdir -p data/db/shard23
创建完毕后,请确保当前用户对该文件夹拥有读写权限(使用chown命令),否则之后会报错。
2) 在三台机器上分别启动mongod进程
Server1:
./bin/mongod --shardsvr --replSet shard1 --port 27017 --dbpath /data/db/shard11/ --oplogSize 100 --logpath /data/db/shard12.log --logappend --fork --rest
./bin/mongod -shardsvr -replSet shard2 -port 27018 -dbpath /data/db/shard21/ -oplogSize 100 -logpath /data/db/shard22.log -logappend -fork
Server2:
./bin/mongod --shardsvr --replSet shard1 --port 27017 --dbpath /data/db/shard11/ --oplogSize 100 --logpath /data/db/shard12.log --logappend --fork --rest
./bin/mongod -shardsvr -replSet shard2 -port 27018 -dbpath /data/db/shard21/ -oplogSize 100 -logpath /data/db/shard22.log -logappend -fork
Server3:
./bin/mongod --shardsvr --replSet shard1 --port 27017 --dbpath /data/db/shard13/ --oplogSize 100 --logpath /data/db/shard12.log --logappend --fork --rest
./bin/mongod -shardsvr -replSet shard2 -port 27018 -dbpath /data/db/shard23/ -oplogSize 100 -logpath /data/db/shard22.log -logappend -fork
3) 初始化两组Replica Set
确认第2步没有报错之后,我们开始配置Replica Set。 通过mongo连接到shard1的一个mongod:
./bin/mongo 192.168.56.191:27017
执行如下命令:
config = {_id: 'shard1', members: [{_id: 0, host: '192.168.56.191:27017'}, {_id: 1, host: '192.168.56.168:27017'}, {_id: 2, host: '192.168.56.169:27017'}]};
rs.initiate(config);
同样方法,配置shard2用到的replica set:
./bin/mongo 192.168.56.191:27018
config = {_id: 'shard2', members: [{_id: 0, host: '192.168.56.191:27018'}, {_id: 1, host: '192.168.56.168:27018'}, {_id: 2, host: '192.168.56.169:27018'}]};
rs.initiate(config);
4) 启动Config Server
在三台机器上分别启动并配置一台Config Server。命令如下:
./bin/mongod --configsvr --dbpath /data/db/config/ --port 20000 --logpath /data/db/config.log --logappend --fork
5)启动Routing Server
部署并配置三台Routing Server
./bin/mongos --configdb 192.168.56.191:20000,192.168.56.168:20000,192.168.56.169:20000 --port 30000 --chunkSize 100 --logpath /data/db/mongos.log --logappend --fork
6)添加分片
连接到mongs服务器,并切换到admin
./bin/mongo 192.168.56.191:30000/admin
db.runCommand({addshard:"shard1/192.168.56.191:27017,192.168.56.168:27017,192.168.56.169:27017",name:"shard1",maxsize:2048, allowLocal:true });
注意:
如果在上述操作中抛出类似如下的错误信息:
in seed list shard1/192.168.56.191:27017,192.168.56.168:27017,192.168.56.169:27017, host 192.168.56.191:27017 does not belong to replica set shard1
那么将“192.168.56.191:27017”去掉再试试,笔者试过,可以成功,但原因目前还不太清楚。
db.runCommand({addshard:"shard2/192.168.56.191:27018,192.168.56.168:27018,192.168.56.169:27018", name:"shard2",maxsize:2048, allowLocal:true });
db.runCommand( { listshards : 1 } );
如果列出(sharding)了以上二个你加的shards,表示shards已经配置成功。笔者测试的输出如下:
mongos> db.runCommand( { listshards : 1 } );
{
"shards" : [
{
"_id" : "shard1",
"host" : "shard1/192.168.56.168:27017,192.168.56.169:27017,192.168.56.155:27017"
},
{
"_id" : "shard2",
"host" : "shard2/192.168.56.168:27018,192.168.56.169:27018,192.168.56.191:27018"
}
],
"ok" : 1
}