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集群(分片)搭建与配置

要构建一个 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
mongod shard22:27018
mongod config2:20000
mongs2:30000

server3

192.168.56.169

mongod shard13:27017
mongod shard23:27018
mongod config3:20000
mongs3:30000

这样我们集群包含了:

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


Server2:
mkdir -p data/db/shard12
mkdir -p data/db/shard22



Server3:
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

}

猜你喜欢

转载自blog.csdn.net/ln152315/article/details/72637450