柴少鹏的官方网站 技术在分享中进步,水平在学习中升华

Mongodb的副本集和权限(三)

http://blog.51niux.com/?id=159  在第二部分已经记录了副本集群的简单创建以及里面各种信息的意思。

一、副本集的组成与设计

1.1 设计副本集

副本集的架构影响集合的容量和能力。生产系统的标准副本集部署是一个三成员副本集。 这些集合提供冗余和容错,尽可能避免复杂性。

副本集中很重要的一个概念是“大多数(majority)”:选择主节点时需要由大多数决定,只有得到大多数的票的时候才能成为主节点。

官方文档:https://docs.mongodb.com/manual/core/replica-set-architectures/

一个副本集可以有多达50个成员,但只有7个投票成员。 如果副本已经有7名有投票权的成员,则其他成员必须是无投票权的成员。

确保副本集具有奇数个投票成员。 如果有偶数量的投票成员,请部署仲裁器,以使该集合拥有奇数个投票成员。仲裁器不存储数据副本并且需要更少的资源。 因此,您可以在应用程序服务器或其他共享进程上运行仲裁器。 没有数据副本,可能会将仲裁器放置在不会放置副本集的其他成员的环境中。一般来说,避免为每个副本集部署多个仲裁器。最多只使用一个仲裁器就好了。

怎么样才算大多数:

图片.png

#最左边是集群数量,中间是选择一个主节点需要多少节点支持,最右边是容错数。

#将成员添加到副本集并不总是增加容错。 然而,在这些情况下,额外的成员可以为专用功能(如备份或报告)提供支持。添加隐藏(hidden)或延迟(delayed )的成员以支持专用功能,如备份或报告。

比较推荐的配置方式:

第一种:将“大多数”成员放在同一个数据中心,如果有一个主数据中心,而且希望副本集的主节点总是位于主数据中心的话,这样配置只要主数据中心能够正常运转,就会有一个主节点。但是主数据中心不可用了,那么备份数据中心的成员无法选举出主节点。

第二种:在两个数据中心各自放置数量相等的成员,在第三个地方放置一个用于决定胜负的副本集成员。如果两个数据中心同等重要,那么这种配置会比较好。因为任意一个数据中心的服务器都可以找到另一台服务器以达到“大多数”。但是这样就需要服务器分散到三个地方。

#上面这两种方式就是为了避免,成员分散在两个地方,当主节点挂掉好或者访问不到主节点了,两边由于网络原因,两边或者另一端可能又选举出一个主节点,可能会出现多个主节点。

选举机制:

       当一个备份节点无法与主节点连通时,它就会联系并请其他的副本集成员将自己选举为主节点。其他成员会做几项理性的检查:自身是否能够与主节点连通?希望被选举为主节点的备份节点的数据是否最新?有没有其他更高优先级的成员可以被选举为主节点。

       如果要求被选举称为主节点的成员能够得到副本集中“大多数”成员的投票,它就会成为主节点。如果“大多数”成员中有一个人否决了本次选举,选举也会取消。希望成为主节点的成员(候选人)必须使用复制将自己的数据更新为最新,副本集的其他成员会对此进行检查。复制操作是严格按照时间排序的,所以候选人的最后一条操作要比它能连通的其他所有成员更晚(或者和其他成员相等)。

选举仲裁者:

仲裁者(arbiter)唯一作用就是参与选举,仲裁者不保存数据,也不会为客户端提供服务。

官网链接:https://docs.mongodb.com/manual/core/replica-set-architecture-three-members/

图片.png

首先在客户端上面的操作:

# /usr/local/mongodb/bin/mongod   --replSet repset  --fork   #用一个很普通的方式启动mongodb,但是要加上--replSet repset

然后再mongodb PRIMARY上面设置:

repset:PRIMARY> rs.addArb("192.168.1.122:27017")   #这就是设置一个仲裁者

然后我们查看一下:

repset:PRIMARY> db._adminCommand("replSetGetStatus");  
        {   #只粘贴了部分内容,在最下方发现多了一个192.168.1.122,它的stateStr提示它是一个仲裁者
            "_id" : 4,
            "name" : "192.168.1.122:27017",
            "health" : 1,
            "state" : 7,
            "stateStr" : "ARBITER",
            "uptime" : 19,
            "lastHeartbeat" : ISODate("2017-08-12T14:39:11.355Z"),
            "lastHeartbeatRecv" : ISODate("2017-08-12T14:39:08.357Z"),
            "pingMs" : NumberLong(0),
            "configVersion" : 14
        }

#成员一旦以仲裁者的身份添加到副本集中,它就永远只能是仲裁者:无法将仲裁者重新配置成非仲裁者。

仲裁者的缺点:

如果节点数量是奇数,那就不需要仲裁者。因为添加额外的仲裁者并不能加快选举速度也不能提供更好的数据安全性。比如你是奇数由于添加仲裁者,副本集就一共拥有偶数个成员,这样就可能出现两个成员票数相同的情况,仲裁者的目的是避免出现平票,而且会导致选举耗时变长,因为又多了一个成员投票。

小集群更不适合用仲裁者了,因为本身就不存放数据,如果主服务器挂掉了,那整个集群里面的数据成员本来就少这样就更少了,如果再上一个新的服务器还要数据同步,数据少还好,要数据多的话很影响性能。

 优先级

 rs.config()里面已经提到过优先级("priority"),默认是1,取值范围是0~100.设置为0的成员永远不能够成为主节点,这样的成员称为被动成员。

拥有最高优先级的成员会优先选举为主节点(只要它能够得到集合中“大多数”的赞成票并且数据是最新的)。优先级的值只会影响副本集成员间相对优先级的大小关系。改变副本中优先级的平衡将触发一次或多次选举。

隐藏成员

客户端不会向隐藏成员发送请求,隐藏成员也不会作为复制源,可以将配置不够好的服务器或者备份服务器隐藏起来,因为客户端链接副本集时,会调用isMaster()来查看可用成员,因此隐藏成员在isMater()里面隐藏了,也就不会接收到客户端的读请求了。

repset:PRIMARY> var config = rs.config()
repset:PRIMARY> config.members[2].hidden = true   #配置制定hidden:true
0
repset:PRIMARY> config.members[2].priority = 0  #只有优先级为0的成员才能被隐藏(不能将主节点隐藏)
0
repset:PRIMARY> rs.reconfig(config)
{ "ok" : 1 }
repset:PRIMARY> rs.isMaster()   #查看一下
{
    "hosts" : [  #hosts数组里面只有两个主机了,通过rs.config()或者rs.status()还是可以看到隐藏的成员的。
        "192.168.1.111:27017",
        "192.168.1.112:27017"
    ],
    "arbiters" : [
        "192.168.1.122:27017"
    ],

现在我们需要将隐藏的成员设置为非隐藏,只需要将配置中的hidden设置为false就可以了,或者删除hidden选项。

repset:PRIMARY> var config = rs.config()
repset:PRIMARY> config.members[2].hidden = false  #将节点从隐藏改变改变为非隐藏状态
false
repset:PRIMARY> rs.reconfig(config)
{ "ok" : 1 }
repset:PRIMARY> rs.isMaster()  #再次用查看
{
    "hosts" : [
        "192.168.1.111:27017",
        "192.168.1.112:27017"
    ],
    "passives" : [   #看到192.168.1.108了,但是现在是被动成员,因为priority还设置的是0没有改回来
        "192.168.1.108:27017"
    ]

延时备份

官网介绍文档:https://docs.mongodb.com/manual/core/replica-set-delayed-member/

数据可能会因为认为的错误而遭受毁灭性的破坏(不小心删除主数据库或者删除数据),因为默认复制是不延时的,这就会造成整个集群的数据都会问题了。为了防止这类问题,可以使用slaveDelay设置一个延迟的备份节点。

延迟备份数据的节点会比主节点延迟指定的时间(单位是秒),这样如果不小心造成了主集合的问题,还可以将数据从延迟节点上面恢复回来。

slaveDelay要求成员的优先级是0,所以要将延迟备份节点隐藏掉,以避免请求被路由到延迟备份节点。

图片.png

博文来自:www.51niux.com

1.2 副本集的组成与同步

数据库间的同步:

这就要涉及到Oplog的概念了:https://docs.mongodb.com/manual/core/replica-set-oplog/

Oplog介绍

MongoDB的复制功能是使用操作日志oplog实现的,操作日志包含了主节点的每一次写操作。oplog时主节点的local数据库中的一个固定集合。备份节点通过查询这个集合就可以知道需要进行复制的操作。

每个备份节点都维护着自己的oplog,记录着每一次从主节点复制数据的操作。这样,每个成员都可以作为同步源提供给其他成员使用。备份节点从当前使用的同步源中获取需要执行的操作,然后在自己的数据集上执行这些操作,最后再讲这些操作写入自己的oplog.如果遇到某个操作失败的情况(只有当同步源的数据损坏或者数据与主节点不一致时才可能发生),那么备份节点就会停止从当前的同步源复制数据。

如果 某个备份节点挂掉了,当它重新启动之后,就会自动从oplog中最后一个操作开始进行同步。由于复制操作的过程是先复制数据再写入oplog,所以备份节点可能会在已经同步过的数据上再次执行复制操作。mongodb考虑到这种情况,所以将oplog中的同一个操作执行多次与一次效果是一样的。

查看Oplog的信息

repset:SECONDARY> rs.printReplicationInfo()   #查看自己的Oplog的信息
configured oplog size:   990MB    #现在配置的oplog的大小
log length start to end: 67875secs (18.85hrs)  #日志从开始到结束的时间长度
oplog first event time:  Sat Aug 12 2017 15:34:05 GMT+0800 (CST)  #oplog开始的时间
oplog last event time:   Sun Aug 13 2017 10:25:20 GMT+0800 (CST)  #oplog最后活动的时间
now:                     Sun Aug 13 2017 10:25:20 GMT+0800 (CST)  #现在的时间

Oplog的大小怎么来的

>db.serverStatus()  #查看服务的状态
    "storageEngine" : {   #其中有这一段,查看当前使用的存储引擎000
        "name" : "wiredTiger",  #使用的是wiredTiger。MongoDB 3.2之后默认启动的是wiredTiger 引擎这个引擎和原来的引擎访问方式不一样。你用命令mongod  --storageEngine mmapv1 --dbpath 数据目录 这样启动的是原来的数据引擎在用MongoVE连接就可以了
         #mongodb自身拥有MMAPv1引擎,在3.0版本中加入了之前收购的WiredTiger的存储引擎技术。通过 WiredTiger,MongoDB 3.0 实现了文档级别的并发控制(Concurrency Control),因此大幅提升了大并发下的写负载。用户可以自己选择储存数据的压缩比例,MongoDB 3.0提供最高达80%的压缩率,不过压缩率越高数据处理的时间成本也越多,用户可以自行权衡应用。
        "supportsCommittedReads" : true,
        "readOnly" : false,
        "persistent" : true
    },

这里有个wiredTiger和In-Memory(内存存储)存储引擎的区别:http://www.cnblogs.com/ljhdo/archive/2016/10/30/4947357.html

官网链接:https://docs.mongodb.com/manual/core/storage-engines/

图片.png

在大多数情况下,默认的oplog大小就足够了。 例如,如果oplog是可用磁盘空间的5%,并在24小时的操作中填满,那么次级可以停止从oplog中复制条目长达24小时,而不会过时地继续复制。 然而,大多数复制集具有较低的操作量,并且它们的oplogs可以容纳更多的操作数。
在mongod创建oplog之前,您可以使用oplogSizeMB选项指定其大小。 但是,首次启动副本集成员后,只能使用更改Oplog过程的大小更改oplog的大小。更改Oplog的链接:https://docs.mongodb.com/manual/tutorial/change-oplog-size/

初始化同步:

副本集中的成员启动之后,就会检查自身状态,确定是否可以从某个其他成员那里进行同步。如果不行的话,它会尝试从副本集的另一个成员那里进行完整的数据复制。这个过程就是初始化同步(initial syncing)。

有几个步骤:

首先这个成员会做一些记录前的准备工作:选择一个成员作为同步源,在local.me中为自己创建一个标识符,删除所有已存在的数据库,以一个全新的状态开始进行同步。注意这个过程会将数据全部删除,如果数据有用的话这个节点的数据提前先备份好。

然后是克隆(cloning)就是将同步源的所有记录全部复制到本地。这通常是整个过程中最耗时的部分。

然后进入oplog同步的第一步,克隆过程中所有操作都会被记录到oplog中。如果有文档在克隆过程中被移动了,就可能会被遗漏,导致没有被克隆,对于这样的文档,可能需要重新进行克隆。

接下来是oplog同步过程的第二步,用于将第一个oplog同步中的操作记录下来。

然后本地数的数据应该与主节点在某个时间点的数据集完全一致了,可以开始创建索引了。如果集合比较大或者要创建的索引比较多会比较耗时。

如果当前节点的数据仍然远远落后于同步源,那么oplog同步过程的最后一步就是将创建索引期间的所有操作全部同步过来,以防止该成员称为备份节点。

然后成员完成了初始化同步,切换到普通同步状态,这时当前成员就可以称为备份节点了。

博文来自:www.51niux.com

二、应用管理

查看正在进行的操作:

repset:PRIMARY> db.currentOp()  #该函数会列出数据库正在进行的所有操作,输出的信息中有些重要的字段。
opid  #这是操作的唯一标识符(identifier),可通过它来终止一个操作。
active  #表示该操作是否正在运行。如这一字段的值是false,意味着此操作已交出或正等待其他操作交出锁。
secs_running  #表示该操作已经执行的时间,可通过它来判断是哪些查询耗时过长,或者占用了过多的数据库资源。
op  #表示操作的类型。通常是查询、插入、更新、删除中的一种。注意,数据库命令也被作为查询操作来处理。
desc #该值可与日志(log)信息联系起来。日志中与此连接相关的每一条记录都会以[conn3]为前缀,因此可以筛选相关的日志信息。
locks #描述该操作使用的锁的蕾西。其中"^表示全局锁"。
waitingForLock  #表示该操作是否因正在等待其他操作交出锁而处于阻塞状态。
numYields  #表示该操作交出锁(yield),而使其操作得以允许的次数。通常,进行文档搜索的操作(查询、更新和删除)可交出锁。只有其他操作队列等待该操作所持的锁时,它才会交出自己的锁。

终止操作的执行:

repset:PRIMARY> db.killOp(65143)  #上面用db.currentOp()查出来的所有操作,里面有opid,想关闭哪个opid,Juin作为参数替代前面()里面的数字

计算空间消耗

repset:PRIMARY> Object.bsonsize(db.user.findOne({"name":"csp"}))  #精确的查处了user集合里面的name:csp的这个第一个文档占用的字节数目。
49  #生成了49字节
repset:PRIMARY> db.user.stats()  #下面是部分信息
"size" : 104,  #集合里所有文档所占字节总和
"count" : 2,  #文档数量
"avgObjSize" : 52,  #平均每个文档所占的大小
"storageSize" : 32768,  #集合实际占用的磁盘空间,因为除了文档以外还会有其他的信息
repset:PRIMARY> db.user.stats(1024)  #输入比例因子。以后字节越来越大,增加易读性。1024就是KB显示,1024*1024就是MB显示,以此类推
"storageSize" : 32,  #就从字节转换成KB了
repset:PRIMARY> db.stats()  #跟上面类似,查看当前数据库的信息。也可以接收比例因子作为参数。
{
    "db" : "fbjtest",   #数据库名称
    "collections" : 1,   #集合数量
    "views" : 0,
    "objects" : 2,      #所有集合包含的文档总数
    "avgObjSize" : 52,  
    "dataSize" : 104,      #数据库中数据所占用的空间大小。该值不包含空闲列表中的空间
    "storageSize" : 32768,  #数据库正在使用的总空间大小
    "numExtents" : 0,
    "indexes" : 1,
    "indexSize" : 32768,
    "ok" : 1
}

db.runCommand( { serverStatus: 1 } )  #前面多次提到这个命令查看服务器的信息,输出很多:

官网链接:https://docs.mongodb.com/manual/reference/command/serverStatus/#dbcmd.serverStatus  #字段代表的意思都会有解释

各种查看命令在:https://docs.mongodb.com/manual/reference/command/nav-diagnostic/

三、安全

安全的官网文档:https://docs.mongodb.com/manual/security/

3.1 身份认证

身份验证介绍

验证是验证客户端身份的过程。 当启用访问控制(即授权)时,MongoDB要求所有客户端进行身份验证,以确定其访问。虽然认证和授权密切相关,认证与授权不同。 验证验证用户的身份; 授权确定验证的用户对资源和操作的访问。为了验证用户,MongoDB提供了db.auth()方法。对于mongo shell和MongoDB工具,您还可以通过从命令行传入用户身份验证信息来验证用户。MongoDB支持许多身份验证机制,客户端可以使用它们来验证身份。 这些机制允许MongoDB集成到您现有的身份验证系统中。MongoDB支持多种认证机制:

SCRAM-SHA-1
x.509证书认证
LDAP代理身份验证
Kerberos认证
内部认证

#除了验证客户端的身份之外,MongoDB还可以要求副本集和分片集群的成员对其各自的副本集或分片集群进行身份验证。

MongoDB中,每个数据库的实例都可拥有任意多个用户。安全检查开启后,只有通过身份验证的用户才能够进行数据的读写操作。

admin(管理员)和local(本地)是两个特殊的数据库,他们当中的用户可对任何数据库进行操作。这两个数据库中的用户可被看作是超级用户。经认证后,管理员用户可对任何数据库进行读写,同时能执行某些管理员才能执行的命令,如listDatabases和shutdown。

要在MongoDB中验证客户端,必须向MongoDB添加相应的用户。要添加用户,MongoDB提供了db.createUser()方法。 添加用户时,可以为用户分配角色以授予权限。在数据库中创建的第一个用户应该是具有管理其他用户的权限的用户管理员。 还可以更新现有用户,例如更改密码并授予或撤销角色。

创建用户

官网参考文档:https://docs.mongodb.com/manual/reference/command/createUser/

用户管理的命令:https://docs.mongodb.com/manual/reference/command/nav-user-management/

createUser  #在运行命令的数据库上创建一个新用户。 如果用户存在,则createUser命令将返回重复的用户错误。 createUser命令使用以下语法:

{ createUser: "<name>",    #新用户的名称。
  pwd: "<cleartext password>",   #用户的密码 如果在$external数据库上运行createUser来创建具有从MongoDB外部存储的凭据的用户,则不需要pwd字段。
  customData: { <any information> },  #可选的。 任意的信息。 此字段可用于存储管理员希望与此特定用户关联的任何数据。 例如,这可以是用户的全名或员工ID。
  roles: [
    { role: "<role>", db: "<database>" } | "<role>",  #数据形式。授予用户的角色。 可以指定一个空数组[]来创建没有角色的用户。
    ...
  ],  
  writeConcern: { <write concern> }}   #可选的。 编写关注级别的创建操作。 writeConcern文档采用与getLastError命令相同的字段。
  #另外还有一个digestPassword,后面是跟布尔值类型.可选的。 当为true时,mongod实例将创建用户密码的哈希值; 否则,客户端负责创建密码的哈希。 默认为true。

查看所有数据库的用户:

repset:PRIMARY> db.runCommand( { usersInfo: 1 } )  #查看数据库的所有用户
{ "users" : [ ], "ok" : 1 }  #现在还没有用户

创建一个管理用户:

repset:PRIMARY> use admin  # 只有在admin上才能创建高权限账户,即用于所有数据库管理权限的用户。

repset:PRIMARY>  db.createUser({user:"root",pwd:"51niux.com",roles:[{role:"root",db:"admin"}]})  
db.createUser({user:"admin",pwd:"admin",roles:[{role:"userAdminAnyDatabase",db:"admin"},{role:"dbAdminAnyDatabase",db:"admin"},{role:"readWriteAnyDatabase",db:"admin"}]})
repset:PRIMARY> db.auth("root","51niux.com")  #验证一下,输出一个结果值为1,说明这个用户匹配上了,如果用户名、密码不对,会输入0
1

roles信息都在这里:https://docs.mongodb.com/manual/reference/built-in-roles/

常用的roles:

read:允许用户读取指定数据库 
readWrite:允许用户读写指定数据库 
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile 
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户 
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。 
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限 
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限 
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限 
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。 
root:只在admin数据库中可用。超级账号,超级权限

#这些角色都只能创建在admin数据库上。去掉AnyDatabase后可以创建在普通数据库上。一旦执行过一次createUser,Localhost Exception立即消失,只能通过验证后才能进行创建操作

创建一个普通用户:

repset:PRIMARY> db.createUser({user:"test1",pwd:"51niux",roles:[{role:"read",db:"fbjtest"}]})  #创建一个test1用户,然后指定fbjtest库只有读权限
Successfully added user: {
    "user" : "test1",
    "roles" : [
        {
            "role" : "read",
            "db" : "fbjtest"
        }
    ]
}

mongodb开启身份验证并验证

mongodb关闭并用下面的命令启动:

# /usr/local/mongodb/bin/mongod --dbpath=/data/mongodb --logpath=/mongodb/logs/mongodb.log --logappend --replSet repset --auth --fork   #加入了--auth以安全认证方式启动

[root@shidc_web_192 ~]# /usr/local/mongodb/bin/mongo  #重新连接
MongoDB shell version v3.4.6
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.6
repset:SECONDARY> db.auth("test1","51niux")  #在默认的test的数据库下登录,是失败的
Error: error doing query: failed: network error while attempting to run command 'isMaster' on host '127.0.0.1:27017' 
0
repset:SECONDARY> use fbjtest  #切到有权限的数据库下
switched to db fbjtest
> db.auth("test1","51niux")  #再次auth登录授权返回1是成功了
2017-08-13T17:28:49.560+0800 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2017-08-13T17:28:49.561+0800 I NETWORK  [thread1] reconnect 127.0.0.1:27017 (127.0.0.1) ok
1 
repset:SECONDARY> db.user.find()  #是可以查询的
{ "_id" : ObjectId("598eb1fcc489fdbbcbc6e000"), "name" : "csp", "age" : 16 }
{ "_id" : ObjectId("598eb25ac489fdbbcbc6e001"), "name" : "xiaoqiang", "age" : 22 }
repset:PRIMARY> db.col.insert({"name":"chaishao"})    #尝试着插入,报错了因为这个用户没有写权限
2017-08-13T17:32:35.984+0800 I NETWORK  [thread1] DBClientCursor::init call() failed
2017-08-13T17:32:35.984+0800 E QUERY    [thread1] Error: Error: error doing query: failed :
DBCollection.prototype.insert@src/mongo/shell/collection.js:363:23
@(shell):1:1
2017-08-13T17:32:36.002+0800 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2017-08-13T17:32:36.002+0800 I NETWORK  [thread1] reconnect 127.0.0.1:27017 (127.0.0.1) ok

3.2 mongodb安全检查表

启用访问控制和执行身份验证

启用访问控制和指定身份验证机制。 你可以 使用默认的MongoDB或现有外部身份验证机制 框架。 认证要求所有客户端和服务器提供的 有效身份证件才能连接到系统。 在集群 部署,使每个MongoDB服务器的身份验证。

配置基于角色的访问控制

创建一个用户管理员第一个,然后创建额外的用户。 每个人创造一个独特的MongoDB用户和应用程序 访问系统。
创建角色定义的访问一组用户的需求。 遵循一个 最小特权原则。 然后创建用户,并分配他们只有 角色需要执行的操作。 一个用户可以是一个人或一个 客户机应用程序。

加密通信

MongoDB配置为使用TLS / SSL对所有传入和传出的 连接。 使用TLS / SSL加密之间的通信mongod和蒙戈MongoDB的组件 部署在所有应用程序之间以及MongoDB。

加密和保护数据
从MongoDB Enterprise 3.2开始,WiredTiger存储引擎 本机加密在休息可以配置为 加密数据存储层。
如果你不使用WiredTiger加密静止,MongoDB数据 应该在每个主机使用加密文件系统,设备,还是 物理加密。 保护数据MongoDB使用文件系统权限。 MongoDB数据包括数据文件、配置文件、审计日志, 和关键文件。
限制网络暴露

确保MongoDB运行在一个可信的网络环境和限制 MongoDB实例侦听传入的接口 连接。 只允许可信的客户访问网络 MongoDB实例可用的接口和端口。

审计系统活动

跟踪访问和修改数据库配置和数据。MongoDB企业包括一个系统审计工具,该工具可以记录 系统事件(例如用户操作、连接事件) MongoDB实例。 这些审计记录允许法医分析和 允许管理员验证适当的控制。

用专用的用户运行MongoDB

运行MongoDB进程和专用操作系统用户帐户。 确保账户有权限访问数据,但没有必要 权限。

用安全运行MongoDB配置选项

MongoDB支持执行某些服务器端操作的JavaScript代码:mapReduce,group和$ where。 如果不使用这些操作,请使用命令行上的--noscripting选项禁用服务器端脚本。
在生产部署中仅使用MongoDB线路协议。 不要启用以下功能,所有这些都启用了Web服务器界面:net.http.enabled,net.http.JSONPEnabled和net.http.RESTInterfaceEnabled。 保持这些禁用,除非向后兼容性要求。
自3.2版本以来已弃用:MongoDB的HTTP接口保持启用输入验证。 MongoDB默认通过wireObjectCheck设置启用输入验证。 这确保了mongod实例存储的所有文档都是有效的BSON。

博文来自:www.51niux.com

四、备份恢复

常用命令:https://docs.mongodb.com/manual/reference/program/

4.1 mongodb备份

官方文档:https://docs.mongodb.com/manual/reference/program/mongodump/

# /usr/local/mongodb/bin/mongodump  --help

Usage:
  mongodump <options>
  
一般选项:
--help   #帮助
--version  #版本
详细选项:
-v, --verbose=<level>  #更详细的日志输出(包括更多详细程度的多次,例如-vvvvv,或指定数值,例如--verbose = N)
--quiet       #隐藏所有日志输出
连接选项:
-h, --host=<hostname>   #mongodb主机连接
--port=<port>      #服务器端口(也可以使用--host hostname:port)
验证选项:
-u, --username=<username>  #认证用户名
-p, --password=<password>  #认证密码
    --authenticationDatabase=<database-name>  #保存用户凭据的数据库
    --authenticationMechanism=<mechanism>     #认证机制使用
命名空间选项:
-d, --db=<database-name>    #指定要备份的数据库。 如果不指定数据库,mongodump会将此实例中的所有数据库复制到转储文件中。
-c, --collection=<collection-name>  #指定要备份的集合。 如果不指定集合,则此选项将指定数据库或实例中的所有集合复制到转储文件。
uri选项:
--uri=mongodb-uri   #mongodb uri连接字符串
查询选项:
-q, --query=  #提供一个JSON文档作为查询,可以限制mongodump输出中包含的文档。
    --queryFile=   #版本3.2中的新功能。指定包含JSON文档的文件的路径作为限制mongodump输出中包含的文档的查询过滤器。 --queryFile允许您创建太大的查询过滤器,以适应终端的缓冲区。
    --readPreference=<string>|<json>   #指定首选项名称或首选项json对象
    --forceTableScan   #强制mongodump直接扫描数据存储:通常,mongodump会保存条目,因为它们出现在_id字段的索引中。 如果指定查询--query,mongodump将使用最适合的索引来支持该查询。
输出选项:   
-o, --out=<directory-path>   #输出目录,或对于stdout为' - '(默认为“转储”)
   --gzip     #使用Gzip压缩
   --repair    #除了转储数据库之外,还运行修复选项。 修复选项将mongodump的行为更改为仅写入有效数据,并排除由于不正确的关闭或mongod崩溃而可能处于无效状态的数据。--repair选项使用可能产生大量重复的攻击性数据恢复算法。
               #--repair仅适用于使用mmapv1存储引擎的mongod实例。 您无法使用mongos或与使用wiredTiger存储引擎的mongod实例一起运行--repair。 要在mongod实例中使用wiredTiger修复数据,请使用mongod --repair。
   --oplog     #使用oplog进行时间点快照
   --archive=<file-path>  #将输出写入单个归档文件或标准输出(stdout)。
   --dumpDbUsersAndRoles  #在特定数据库上执行mongodump时,包括数据库转储目录中的用户和角色定义。 此选项仅适用于在--db选项中指定数据库时。 当mongodump应用于整个实例而不仅仅是一个特定的数据库时,MongoDB总是包含用户和角色定义。
   --excludeCollection=<collection-name>  #从mongodump输出中排除指定的集合。 要排除多个集合,请多次指定--excludeCollection。
   --excludeCollectionsWithPrefix=<collection-prefix>   #从mongodump输出中排除具有指定前缀的所有集合。 要指定多个前缀,请多次指定--excludeCollectionsWithPrefix。
-j, --numParallelCollections=  #并行转储的集合数(默认为4)
     --viewsAsCollections         #指定时,mongodump将只读视图导出为集合。 对于每个视图,mongodump将生成包含视图中的文档的BSON文件。 如果您对生成的BSON文件进行mongoretore,则视图将作为集合进行还原。

# mongodump -u root -p 51niux.com --authenticationDatabase admin -o /backup/full_bak_`date +%F-%T`.bak   #备份所有的数据库

blob.png

# mongodump -u root -p 51niux.com --port 27017 --authenticationDatabase admin -d fbjtest -o /backup/fbjtest_bak_`date +%F-%T`.bak    #通过-d指定单个库fbjtest,备份单个库

blob.png

# mongodump -u root -p 51niux.com -h 127.0.0.1 --port 27017 --authenticationDatabase admin -d fbjtest -c user -o /backup/fbjtest_user_bak_`date +%F-%T`.bak   #通过-d指定库之后通过-c指定表名称,这里是备份单个表

blob.png

另外:备份所有库推荐使用添加--oplog参数的命令,这样的备份是基于某一时间点的快照,只能用于备份全部库时才可用,单库和单表不适用:

另外:还有一种cp备份的方式:

>db.fsyncLock()  #拷贝过程中必须阻止数据文件发送更改。因此需要对数据库加锁,以防止数据写入。
#上面的命令将阻塞写入操作,并将脏数据刷新到磁盘上,确保数据一致。然后拷贝整个数据库目录下的文件到备份目录下。
> db.fsyncUnlock() #文件复制完成后,对数据库进行解锁,允许写操作。注意: 在执行db.fsyncLock()和db.fsyncUnlock()时,不能关闭当前的shell窗口,否则可能无法连接而需要重新启动mongod服务。
#恢复时,确保mongod没有运行,清空数据目录,将备份的数据拷贝到数据目录下,然后启动mongod

4.2 mongodb恢复

官方链接:https://docs.mongodb.com/manual/reference/program/mongorestore/

# /usr/local/mongodb/bin/mongorestore --help   #好多参数的解释跟上面mongodump一致,这里就挑着不一致的列一下

命名空间选项:
-d, --db=<database-name>   #指定一个mongorestore数据库来还原数据。 如果数据库不存在,mongorestore会创建数据库。 如果不指定<db>,则mongorestore会创建新数据库,该数据库对应于数据源所在的数据库,数据可能被覆盖。 使用此选项将数据恢复到已经具有数据的MongoDB实例中。--db不能控制mongorestore恢复哪个BSON文件。 您必须使用mongorestore路径选项来限制恢复的数据。
-c, --collection=<collection-name>   #指定要将mongorestore还原的单个集合。 如果不指定--collection,mongorestore将从输入文件名中获取集合名称。 如果输入文件有扩展名,MongoDB会从集合名称中省略文件的扩展名。
    --nsExclude=<namespace-pattern>  #从还原操作中排除指定的命名空间。--nsExclude接受一个命名空间模式作为其参数。
    --nsInclude=<namespace-pattern>  #在还原操作中只包含指定的命名空间。 通过使您能够指定要还原的多个集合,--nsInclude提供了--collection选项功能的超集。
    --nsFrom=<namespace-pattern>     #重命名匹配命名空间,必须具有匹配的nsTo
    --nsTo=<namespace-pattern>       #重命名匹配的命名空间,必须具有匹配的nsFrom
输入选项:
--objcheck     #强制mongorestore在收到客户端时验证所有请求,以确保客户端从不将无效文档插入数据库。 对于具有高度子文档嵌套的对象,-objcheck对性能影响很小。版本2.4更改:MongoDB默认启用--objcheck,以防止任何客户端将错误或无效的BSON插入到MongoDB数据库中。
--oplogReplay  #重播oplog进行时间点恢复
--oplogLimit=<seconds>[:ordinal]  #只提供所提供的时间戳之前的oplog条目
--oplogFile=<filename>    #指定包含用于还原的oplog数据的oplog文件的路径。
--archive=<filename>      #从归档文件或从标准输入(stdin)恢复。要从存档文件还原,请使用--archive选项和归档文件名运行mongorestore。
--restoreDbUsersAndRoles  #恢复给定数据库的用户和角色定义。
--dir=<directory-name>    #指定转储目录。不能将--archive选项与--dir选项一起使用。
--gzip                    #解压缩gzip输入
恢复选项:
--drop        #在从转储的备份还原集合之前,从目标数据库中删除集合。 --drop不会删除不在备份中的集合。
--dryRun      #运行mongorestore,而不实际导入任何数据,返回mongorestore摘要信息。 与--verbose一起使用以产生更详细的摘要信息。
--writeConcern=<write-concern>  #指定moreorestore写入目标数据库的每个写入操作的写入注意事项。将写入注意事项指定为具有w选项的文档。
--noIndexRestore       #不恢复索引
--noOptionsRestore     #不要恢复集合选项
--keepIndexVersion     #不更新索引版本
--maintainInsertionOrder  #如果指定,mongorestore按照出现的顺序将文档插入输入源,否则mongorestore可以按任意顺序执行插入。
-j, --numParallelCollections=  #并行恢复的集合数(默认为4个)
    --numInsertionWorkersPerCollection=  #每个集合同时运行的插入操作数(默认为1)
--stopOnError         #迫使mongorestore在遇到错误时停止恢复。 默认是关闭此选项。
--bypassDocumentValidation   #使操作期间能绕过文档验证。 这样可以插入不符合验证要求的文档。

全库恢复:

# mongorestore -u root -p 51niux.com  /backup/full_bak_2017-08-15-23\:53\:12.bak/  #全部库恢复

> use fbjtest
switched to db fbjtest
> db.dropDatabase()  #删除fbjtest数据库
{ "dropped" : "fbjtest", "ok" : 1 }

单库恢复:

# mongorestore -u root -p 51niux.com --authenticationDatabase "admin" -d fbjtest /backup/full_bak_2017-08-15-23\:53\:12.bak/fbjtest/   #指定fbjtest数据库单独恢复,输出结果比较多就不打印了。

> db.user.find()  #再次查看数据又恢复了
{ "_id" : ObjectId("599313725e53cd548987209b"), "name" : "chai", "age" : 10 }
{ "_id" : ObjectId("599313725e53cd548987209c"), "name" : "chaishao", "age" : 15 }
{ "_id" : ObjectId("599313725e53cd548987209d"), "name" : "chaishaopen", "age" : 15 }

单个集合恢复:

> db.user.drop()
true
> db.col.drop()
true

# mongorestore -u root -p 51niux.com --authenticationDatabase "admin" -d fbjtest -c user --nsInclude /backup/full_bak_2017-08-15-23\:53\:12.bak/fbjtest/user.metadata.json  /backup/full_bak_2017-08-15-23\:53\:12.bak/fbjtest/user.bson   #-c指定了集合,但是还需要--nsInclude的配合指定两个文件

> show collections  #再次查看就剩下user集合了,col集合不在了
user
> db.user.find()   #集合里面的文档都在
{ "_id" : ObjectId("599313725e53cd548987209b"), "name" : "chai", "age" : 10 }
{ "_id" : ObjectId("599313725e53cd548987209c"), "name" : "chaishao", "age" : 15 }
{ "_id" : ObjectId("599313725e53cd548987209d"), "name" : "chaishaopen", "age" : 15 }

五、mongodb实时监控

5.1  mongostat

mongostat实用程序可以快速查看当前运行的mongod或mongos实例的状态。 mongostat在功能上类似于UNIX / Linux文件系统实用程序vmstat,但提供有关mongod和mongos实例的数据。从系统命令行运行mongostat,而不是mongo shell。

有关其他MongoDB状态输出的更多背景信息,请参见:serverStatus、replSetGetStatus、dbStats、collStats

官网链接:https://docs.mongodb.com/manual/reference/program/mongostat/

# mongostat   #后面的参数就不接受了,直接看下面的截图,解释下各列是什么意思

blob.png

#mongostat返回反映1秒钟以内操作的值。 当mongostat <sleeptime>的值大于1时,mongostat将统计信息平均以反映每秒平均操作。

inserts   #每秒插入数据库的对象数。 如果后跟一个星号(例如*),则基准指的是复制的操作。
query     #每秒查询操作的次数。
update    #每秒更新操作的次数
delete    #每秒删除操作的次数。
getmore   #每秒获取更多(即游标批处理)操作的次数。
command   #每秒命令的数量。在从属和辅助系统中,mongostat呈现以管理字符(例如|)分隔的两个值,以本地|复制命令的形式。比如批量插入,只认为是一条命令。如果是slave,会显示两个值。
flushes     #对于WiredTiger存储引擎,刷新是指在每个轮询间隔之间触发的WiredTiger检查点的数量。对于MMAPv1存储引擎,刷新表示每秒fsync操作的数量。
dirty       #仅适用于WiredTiger存储引擎。 WiredTiger缓存与脏字节的百分比,由wiredTiger.cache.tracked缓存/ wiredTiger.cache.maximum配置的dirty字节计算。
used        #仅适用于WiredTiger存储引擎。 正在使用的WiredTiger缓存的百分比,由wiredTiger.cache.bytes计算,当前在缓存/ wiredTiger.cache.maximum字节中配置。
vsize       #进程在最后一个mongostat调用时使用的虚拟内存量(以兆字节为单位)。
res         #在最后一个mongostat呼叫时进程使用的驻留内存量(以兆字节为单位)。
qr         #等待从MongoDB实例读取数据的客户队列的长度。
qw       #等待从MongoDB实例写入数据的客户队列的长度。
ar     #执行读操作的活动客户端数。
aw     #执行写入操作的活动客户机的数量。
#如果qrw或者arw, 如果这两个数值很大,那么就是DB被堵住了,DB的处理速度不及请求速度。看看是否有开销很大的慢查询。如果查询一切正常,确实是负载很大,就需要加机器了。
netIn   #MongoDB实例收到的网络流量(以字节为单位)。这包括来自mongostat本身的流量。 
netOut  #MongoDB实例发送的网络流量(以字节为单位)。这包括来自mongostat本身的流量。
conn    #当前连接的总数。
time     #当前时间

5.2 mongotop

官网链接:https://docs.mongodb.com/manual/reference/program/mongotop/

mongotop提供了一种跟踪MongoDB实例读取和写入数据的时间量的方法。 mongotop提供每个收集级别的统计信息。 默认情况下,mongotop每秒返回一次值。

# mongotop  15  #15秒刷新一次

blob.png

ns  #包含数据库名称空间,它结合数据库名称和集合。如果使用mongotop --locks,则ns字段不会显示在mongotop输出中。
total #提供这个mongod在这个命名空间上运行的总时间。
read  #提供这个mongod花费在这个命名空间上执行读取操作的时间。
write  #提供这个mongod花费在这个命名空间上执行写操作的时间。
最后边那个时间就是返回部分信息的时间
作者:忙碌的柴少 分类:MongoDB 浏览:9276 评论:1
留言列表
松鼠先生
松鼠先生 先帮你顶一下  回复
发表评论
来宾的头像