fsync和锁

通过fsync和锁可以在MongoDB运行时,安全有效地使用复制数据目录的方式进行备份!fsync命令会强制服务器将所有缓冲区内容写入到磁盘!通过上锁,可以阻止数据库的进一步写入!下面演示具体做法:


[javascript]  view plain copy


1. > use admin;  
2. switched to db admin  
3. > db.runCommand({"fsync" : 1, "lock" : 1});  
4. {  
5. "info" : "now locked against writes, use db.fsyncUnlock() to unlock",  
6. "seeAlso" : "http://www.mongodb.org/display/DOCS/fsync+Command",  
7. "ok" : 1  
8. }  
9. >

注意运行fsync命令需要在admin数据库下进行!通过执行上述命令,缓冲区内数据已经被写入磁盘数据库文件中,并且数据库此时无法执行写操作(写操作阻塞)!这样,我们可以很安全地备份数据目录了!备份后,我们通过下面的调用,来解锁:


[javascript]  view plain copy



    1. > use admin;  
    2. switched to db admin  
    3. > db.$cmd.sys.unlock.findOne();  
    4. { "ok" : 1, "info" : "unlock completed" }  
    5. > db.currentOp();  
    6. { "inprog" : [ ] }  
    7. >


    在admin数据库下解锁。通过执行db.currentOp()来确认解锁成功!通过fsync和写入锁的使用,可以非常安全地备份实时数据,也不用停止数据库服务。但其弊端就是,在备份期间,数据库的写操作请求会阻塞!


    从属备份

    上面提到的备份技术已经非常灵活,但默认都是指直接在主服务器上进行!MongoDB更推荐备份工作在从服务器上进行!从服务器上的数据基本上和主服务器是实时同步的,并且从服务器不在乎停机或写阻塞!所以我们可以利用上述3种方式的任意一种在从服务器上进行备份操作!


    Master-Slave

    主从复制模式:即一台主写入服务器,多台从备份服务器。从服务器可以实现备份,和读扩展,分担主服务器读密集时压力,充当查询服务器。但是主服务器故障时,我们只能手动去切换备份服务器接替主服务器工作。这种灵活的方式,使扩展多如备份或查询服务器相对比较容易,当然查询服务器也不是无限扩展的,因为这些从服务器定期在轮询读取主服务器的更新,当从服务器过多时反而会对主服务器造成过载。

    我们以之前创建的端口为27017做为主服务器,再创建个端口为27018从服务器

    重新启动27017为主服务器 --master 主服务器



    1. ....bin>mongod  --dbpath "C:\Program Files\mongodb\data\dbs\master" --master


    创建27018为从服务器  --slave 从服务器  --source 指定主服务器



    1. ....bin>mongod --port 27018 --dbpath "C:\Program Files\mongodb\data\dbs\slave27018"   --slave --source localhost:27017


    主服务器可以通过自己local库的slave集合查看从服务器列表

    从服务器可以通过自己local库的source集合查看主服务器信息或维护多个主服务器。 (一个slave服务器可以服务多个master服务器)

    或者我们可以通过http console查看状态

    Replica Sets

    副本集模式:具有Master-Slave模式所有特点,但是副本集没有固定的主服务器,当初始化的时候会通过多个服务器投票选举出一个主服务器。当主服务器故障时会再次通过投票选举出新的主服务器,而原先的主服务器恢复后则转为从服务器。Replica Sets的在故障发生时自动切换的机制可以极时保证写入操作。

    创建多个副本集节点 --replSet   (注意要区分大小写,官方建议命名空间使用IP地址)


      1. ....bin>mongod --dbpath "C:\Program Files\mongodb\data\dbs\replset27017"   --port 27017 --replSet replset/127.0.0.1:27018  
      2.  
      3. ....bin>mongod --dbpath "C:\Program Files\mongodb\data\dbs\replset27018"   --port 27018 --replSet replset/127.0.0.1:27017  
      4.  
      5. ....bin>mongod --dbpath "C:\Program Files\mongodb\data\dbs\replset27019"   --port 27019 --replSet replset/127.0.0.1:27017


      首先建立3个是为了投票不会冲突,当服务器为偶数时可能会导致无法正常选举出主服务器。

      其次上面3个replset 节点没有全部串联起来,是因为replset 有自检测功可以自动搜索连接其它服务器。

      完成上面的工作后,要初始化副本集,随便连接一台服务器执行以下命令 (priority 0~1,被选为主服务器的优先级)


      1. >use admin  
      2.  
      3. >db.runCommand(  
      4.  
      5. {"replSetInitiate":{  
      6.  
      7.  "_id":"replset",  
      8.  
      9.  "members":[  
      10.  
      11. {  
      12.  
      13. "_id":1,  
      14.  
      15. "host":"127.0.0.1:27017",  
      16.  
      17. "priority":1  
      18.  
      19. },  
      20.  
      21. {  
      22.  
      23. "_id":2,  
      24.  
      25. "host":"127.0.0.1:27018",  
      26.  
      27. "priority":1  
      28.  
      29. },  
      30.  
      31. {  
      32.  
      33. "_id":3,  
      34.  
      35. "host":"127.0.0.1:27019",  
      36.  
      37. "priority":1  
      38.  
      39. }]}}  
      40.  
      41. )


      查看结果,可以看出127.0.0.1:27017 被自动选为replSet:Primary>


      mongodb 的内部锁机制 mongodb锁库_mongodb

      在增加一个从服务器节点


      1. ....bin>mongod --dbpath "C:\Program Files\mongodb\data\dbs\replset27020" --port 27020 --replSet replset/127.0.0.1:27017


      通过rs.add命令往system.replset添加新的从服务器成员

      1. rs.add("127.0.0.1:27020");   或者rs.add({"_id":4,"host":"127.0.0.1:27020"})


      这里在简单的介绍一下Master Slave/ Replica Sets 备份机制,这两种模式都是基于主服务器的oplog 来实现所有从服务器的同步。

      oplog记录了增删改操作的记录信息(不包含查询的操作),但是oplog有大小限制,当超过指定大小,oplog会清空之前的记录,重新开始记录。

      Master Slave方式主服备器会产生 oplog.$main 的日志集合。

      Replica Sets  方式 所有服务器都会产生oplog.rs 日志集合。

      两种机制下,所有从服务器都会去轮询主服务器oplog日志,若主服务器的日志较新,就会同步这些新的操作记录。但是这里有个很重要的问题,从服务器由于网络阻塞,死机等原因无法极时同步主服务器oplog记录:一种情况 主服务器oplog不断刷新,这样从服务器永远无法追上主服务器。另外一种情况,刚好主服务器oplog超出大小,清空了之前的oplog,这样从服务器就与主服务器数据就可能会不一致了,这第二种情况,我是推断的,没有证实。

      另外要说明一下Replica Sets 备份的缺点,当主服务器发生故障时,一台从服务器被投票选为了主服务器,但是这台从服务的oplog 如果晚于之前的主服务器oplog的话,那之前的主服务器恢复后,会回滚自己的oplog操作和新的主服务器oplog保持一致。由于这个过程是自动切换的,所以在无形之中就导致了部分数据丢失。





      【修复】

      做备份是为了以备不测,比如停电,或自然灾害等,不管怎样,数据是安全的!但总有一些意外情况:不测发生了,但我们还没来得及备份!这时数据目录中的数据可能出于损毁状态,如果在这样的数据目录上启动服务,MongoDB会给出特定的提示!MongoDB提供了修复数据目录的启动方式,就是在启动服务时使用选项--repair。修复过程就是,将所有的文档导出后立即导入,忽略无效的错误文档。并且需要将所有的索引重新建立!修复后,我们重新启动服务即可!

      对于大数据量的数据库,恢复是一个非常耗时的操作!因为所有数据都需要验证,并且所有索引都需要重新建立!

      Shell中通过调用db.repairDatabase()可以在数据库服务运行时修复特定的数据库(也可通过运行命令的方式进行,命令参数为:{"repairDatabase" :1})!

      修复数据库是万不得已才进行的,最佳实践是经常备份数据库,并且利用数据库的复制功能(马上会讲到)来实现故障恢复!