MongoDB

基础

MongoDB包中的核心组件是:

1、mongod - 核心数据库进程;
2、mongos - 分片群集的控制器和查询路由器,mongos就是 “MongoDB Shard” 的简写;
3、MongoDB Shell - 与mongo交互式的工具。

停止服务的方式

use admin; // 切换到admin库,只能是这个数据库才有权限关闭
db.shutdownServer(); // 关闭服务

保留的数据库
admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合。
config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。

插入文档
要向comment的集合(表)中插入一条测试数据:

db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明
媚","userid":"1001","nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null});

1)comment集合如果不存在,则会隐式创建
2)mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了。
3)插入当前日期使用 new Date()
4)插入的数据没有指定 _id ,会自动生成主键值
5)如果某字段没值,可以赋值为null,或不写该字段。

集合的删除
db.集合.drop();

 db.mycollection.drop(); // 删除mycollection集合.如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。

查询文档
查询spit集合的所有文档的所有field

db.comment.find({});

查询comment集合,结果只显示 _id(默认 _id 会显示)、userid、nickname :

db.comment.find({userid:"1003"},{userid:1,nickname:1});

查询结果只显示 、userid、nickname ,不显示 _id。1-显示、0-不显示。

db.comment.find({userid:"1003"},{userid:1,nickname:1,_id:0});

修改文档
修改_id为2的记录,浏览量为889

db.comment.update({_id:"2"},{$set:{likenum:NumberInt(889)}});

更新所有用户为 1003 的用户的昵称为 凯撒大帝
//默认只修改第一条数据

db.comment.update({userid:"1003"},{$set:{nickname:"凯撒2"}});

//修改所有符合条件的数据

db.comment.update({userid:"1003"},{$set:{nickname:"凯撒大帝"}},{multi:true});

对3号数据的点赞数,每次递增1

db.comment.update({_id:"3"},{$inc:{likenum:NumberInt(1)}});

删除文档
删除_id=1的记录

db.comment.remove({_id:"1"});

数据全部删除

db.comment.remove({});

其他函数
统计comment集合的所有的记录数:count();

db.comment.count();

统计userid为1003的记录条数

db.comment.count({userid:"1003"});

分页查询:skip();limit();
需求:每页2个,第二页开始:跳过前两条数据,接着值显示3和4条数据

db.comment.find().skip(0).limit(2); // 第一页
db.comment.find().skip(2).limit(2); // 第二页
db.comment.find().skip(4).limit(2); // 第三页

排序查询:sort();1 为升序排列,而-1是用于降序排列。
对userid降序排列,并对访问量进行升序排列

db.comment.find().sort({userid:-1,likenum:1});

skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit(),和命令编写顺序无关。

查询评论点赞数量大于700的记录。

db.comment.find({likenum:{$gt:NumberInt(700)}});

$gt、 $lt、 $gte、 $lte、 $ne

查询评论的集合中userid字段包含1003或1004的文档

db.comment.find({userid:{$in:["1003","1004"]}});

查询评论集合中userid字段不包含1003和1004的文档

db.comment.find({userid:{$nin:["1003","1004"]}});

查询评论集合中likenum大于等于700 并且小于2000的文档

db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]});

查询评论集合中userid为1003,或者点赞数小于1000的文档记录

db.comment.find({$or:[ {userid:"1003"} ,{likenum:{$lt:1000} }]});

索引
MongoDB索引使用B树数据结构(确切的说是B-Tree,MySQL是B+Tree)。
单字段索引:
MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。
复合索引:
MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。
复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后在每个userid的值内,再在按score倒序排序。
地理空间索引(Geospatial Index)
为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。
文本索引(Text Indexes)
MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),而将集合中的词作为词干,只存储根词。
哈希索引(Hashed Indexes)
为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。

查看comment集合中所有的索引情况,返回comment集合中的所有索引的数组。

 db.comment.getIndexes();

MongoDB在创建集合的过程中,在 _id 字段上创建一个唯一的索引。在分片集群中,通常使用 _id 作为片键。
对 userid 字段建立单字段索引

 db.comment.createIndex({userid:1});

对 userid 和 nickname 同时建立复合(Compound)索引

db.comment.createIndex({userid:1,nickname:-1});

删除 comment 集合中 userid 字段上的升序索引

db.comment.dropIndex({userid:1});

删除 comment 集合中所有索引。

db.comment.dropIndexes();

分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。建立的索引是否有效,效果如何,都需要通过执行计划查看。

查看根据userid查询数据的情况

db.comment.find({userid:"1003"}).explain();

关键点看: “stage” : “COLLSCAN”, 表示全集合扫描。

db.comment.createIndex({userid:1});

关键点看: “stage” : “IXSCAN” ,基于索引的扫描。

当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以非常有效。

db.comment.find({userid:"1003"},{userid:1,_id:0});

索引可以大大提升查询效率,一般在查询字段上添加索引,索引的添加可以通过Mongo的命令来添加,也可以在Java的实体类中通过注解添加。

高级

副本集-Replica Sets
MongoDB中的副本集(Replica Set)是一组维护相同数据集的mongod服务。 副本集可提供冗余和高可用性,是所有生产部署的基础。
主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂掉后,又在剩下的从节点中选中其他节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多个备份节点(从、secondary)。

副本集的两种类型、三个角色
两种类型:
主节点(Primary)类型:数据操作的主要连接点,可读写。
次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。
三种角色:
主要成员(Primary):主要接收所有写操作。就是主节点。
副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

副本集的创建
第一步:创建主节点(IP和port是:180.76.159.126:27017),启动
第二步:创建副本节点(IP和port是:180.76.159.126:27018),启动
第三步:创建仲裁节点(IP和port是:180.76.159.126:27019),启动
第四步:初始化配置副本集和主节点,使用客户端命令连接任意一个节点,但这里尽量要连接【主节点】,连接上之后,很多命令无法使用,比如 show dbs 等,必须初始化副本集才行。

rs.initiate();

命令行提示符发生的变化
【SECONDARY> 】稍等片刻再回车会自动变为【PRIMARY>】
第五步:查看副本集的配置内容

rs.conf();

副本集配置的查看命令,本质是查询的是 system.replset 的表中的数据

 db.system.replset.find();

第六步:查看副本集状态

rs.status();

第七步:添加副本从节点
在主节点添加从节点,将其他成员加入到副本集,语法:rs.add(host, arbiterOnly);其中的arbiterOnly是可选的,仅在 值为字符串时适用。 设置为true,则添加的主机是仲裁者。

rs.add("180.76.159.126:27018");

此时查看副本集状态:rs.status();有两个角色了
“stateStr” : “PRIMARY”
“stateStr” : “SECONDARY”
第八步:添加仲裁从节点

rs.addArb("180.76.159.126:27019");

此时查看副本集状态:rs.status();有三个角色了
“stateStr” : “PRIMARY”
“stateStr” : “SECONDARY”
“stateStr” : “ARBITER”,

副本集的数据读写操作
登录主节点27017,写入和读取数据,正常。
登录从节点27018,不能写,也不能读(为默认情况下,从节点是没有读写权限的)。
在27018上设置作为奴隶节点权限,具备读权限

rs.slaveOk();

现在可实现了读写分离,让主插入数据,让从来读取数据。如果要取消作为奴隶节点的读权限

 rs.slaveOk(false);

仲裁者节点,不存放任何业务数据的,只存放副本集配置等数据。
主节点的选举原则
MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
1) 主节点故障
2) 主节点网络不可达(默认心跳信息为10秒)
3) 人工干预(rs.stepDown(600))
选举规则是根据票数来决定谁获胜:
票数最高,且获得了“大多数”成员的投票支持的节点获胜。“大多数”的定义为:假设副本集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,则大多数的值是2。当副本集内存活成员数量不足大多数时,整个副本集将无法选举出Primary,副本集将无法提供写服务,处于只读状态。
若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。数据的新旧是通过操作日志oplog来对比的。

一、副本节点故障测试
关闭27018副本节点:
发现,主节点和仲裁节点对27018的心跳失败。因为主节点还在,因此,没有触发投票选举。如果此时,在主节点写入数据。
再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。

二、主节点故障测试
关闭27017主节点:
发现,从节点和仲裁节点对27017的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起投票。而副本节点只有27018,因此,候选人只有一个就是27018,开始投票。27019向27018投了一票,27018本身自带一票,因此共两票,超过了“大多数”27019是仲裁节点,没有被选举权,27018不向其投票,其票数是0。最终结果,27018成为主节点。具备读写功能。
再启动27017节点,发现27017变成了从节点,27018仍保持主节点。登录27017节点,发现是从节点了,数据自动从27018同步。从而实现了高可用。

三、仲裁节点和主节点故障
先关掉仲裁节点27019,
关掉现在的主节点27018
登录27017后,发现,27017仍然是从节点,副本集中没有主节点了,导致此时,【副本集是只读状态】,无法写入。
为啥不选举了?因为27017的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)如果要触发选举,随便加入一个成员即可。两种情况:
1、如果只加入27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举(没有被选举权),但参与投票。
2、如果只加入27018节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节点。

四、仲裁节点和从节点故障
先关掉仲裁节点27019,
关掉现在的副本节点27018
10秒后,27017主节点自动降级为副本节点。(服务降级)副本集不可写数据了,已经故障了。

Compass和SpringDataMongoDB也可以连接副本集,刚才是用shell演示的连接副本集。

分片集群-Sharded Cluster
分片(sharding)是一种跨多台机器分布数据的方法, MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署。换句话说:分片(sharding)是指将数据拆分,将其分散存在不同的机器上的过程。有时也用分区(partitioning)来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以储存
更多的数据,处理更多的负载。MongoDB支持通过分片进行水平扩展。
MongoDB分片群集包含以下组件:
分片(存储):每个分片包含分片数据的子集。 每个分片都可以部署为副本集。
mongos(路由):mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口。
config servers(“调度”的配置):配置服务器存储群集的元数据和配置设置。 从MongoDB 3.4开始,必须将配置服务器部署为副本集(CSRS)。
分片集群中组件的交互
MongoDB在集合级别对数据进行分片,将集合数据分布在集群中的分片上。

分片(存储)节点副本集的创建
分片(存储)节点副本集的创建:两个分片节点副本集(3+3)+一个配置节点副本集(3)+两个路由节点(2),共11个服务节点。
分片(存储)节点副本集的创建
第一部分:分片节点副本集
第一套副本集(一主一副本一仲裁)
180.76.159.126:27018、180.76.159.126:27118、180.76.159.126:27218。
按照单个副本集的步骤,启动第一套分片节点副本集,初始化副本集和创建主节点(尽量要连接主节点),执行初始化副本集命令,主节点配置查看,添加副本节点,添加仲裁节点,查看副本集的配置情况。

 replication:
	#副本集的名称
	replSetName: myshardrs01
sharding:
	#分片角色
	clusterRole: shardsvr

第二套副本集(一主一副本一仲裁)
180.76.159.126:27318、180.76.159.126:27418、180.76.159.126:27518。
按照单个副本集的步骤,启动第二套分片节点副本集,初始化副本集和创建主节点(尽量要连接主节点),执行初始化副本集命令,主节点配置查看,添加副本节点,添加仲裁节点,查看副本集的配置情况。

replication:
	replSetName: myshardrs02
sharding:
	clusterRole: shardsvr

第二部分:配置节点副本集(一主两副本)
180.76.159.126:27019、180.76.159.126:27119、180.76.159.126:27219。
按照单个副本集的步骤,启动配置节点副本集,初始化副本集和创建主节点(尽量要连接主节点),执行初始化副本集命令,主节点配置查看,添加副本节点,添加副本节点,查看副本集的配置情况。注意这里,没有仲裁节点。

replication:
	replSetName: myconfigrs
sharding:
	clusterRole: configsvr

第三部分:路由节点(两个)
180.76.159.126:27017。
路由节点的配置文件追加了配置节点的IP和Port

sharding:
	#指定配置节点副本集
	configDB:
	myconfigrs/180.76.159.126:27019,180.76.159.126:27119,180.76.159.126:27219

启动mongos,客户端登录mongos。注意这里,是mongos,而不是前面两个的mongod。
此时,写不进去数据,如果写数据会报错。通过路由节点操作,现在只是连接了配置节点,还没有连接分片数据节点,因此无法写入业务数据。

在路由节点上进行分片配置操作,sh.addShard(“IP:Port”);
首先、将第一套分片副本集添加进来:

sh.addShard("myshardrs01/192.168.0.2:27018,180.76.159.126:27118,180.76.159.126:27218")

将第二套分片副本集添加进来:

sh.addShard("myshardrs02/192.168.0.2:27318,180.76.159.126:27418,180.76.159.126:27518")

其次、开启分片功能:sh.enableSharding(“库名”)、sh.shardCollection(“库名.集合名”,{“key”:1});

最后、对集合分片,你必须使用如下方法指定集合和分片键。

sh.shardCollection(namespace, key, unique);

namespace:string类型,要(分片)共享的目标集合的命名空间,格式: .
key:document类型,用作分片键的索引规范文档。shard键决定了MongoDB如何在shard之间分发文档。索引必须在shardCollection(namespace, key, unique);命令之前存在,除非集合为空。如果集合为空,则MongoDB在对集合进行分片之前创建索引,前提是支持分片键的索引不存在。简单的说:由包含字段和该字段的索引遍历方向的文档组成。
unique:boolean类型,当值为true情况下,片键字段上会限制为确保是唯一索引。哈希策略片键不支持唯一索引。默认是false。

对集合进行分片时,你需要选择一个片键(Shard Key),Shard key 是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的 数据块中,并将 数据块 均衡地分布到所有分片中。为了按照片键划分数块,MongoDB使用 基于哈希的分片方式(随机平均分配)或者基于范围的分片方式(数值大小分配) 。

分片规则一:哈希策略
对于基于哈希的分片,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,拥有”相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。
使用nickname作为片键,根据其值的哈希值进行数据分片

sh.shardCollection("articledb.comment",{"nickname":"hashed"});

分片规则二:范围策略
对于基于范围的分片,MongoDB按照片键的范围把数据分成不同部分。假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点。MongoDB把这条直线划分为更短的不重叠的片段,并称之为数据块,每个数据块包含了片键在一定范围内的数据。
在使用片键做范围划分的系统中,拥有”相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中。
使用作者年龄字段作为片键(age后面的1,就相当于添加索引时的作用):

sh.shardCollection("articledb.author",{"age":1});

1)一个集合只能指定一个片键,否则报错。
2)一旦对一个集合分片,分片键和分片值就不可改变。 如:不能给集合选择不同的分片键、不能更新分片键的值。
3)根据age索引进行分配数据。

注意:范围策略,如果查看状态发现没有分片,则可能是由于以下原因造成了:
1)系统繁忙,正在分片中。
2)数据块(chunk)没有填满,默认的数据块尺寸(chunksize)是64M,填满后才会考虑向其他片的数据块填充数据,因此,为了测试,可以将其改小,这里改为1M,

use config;
db.settings.save( { _id:"chunksize", value: 1 } );

测试完改回来:

db.settings.save( { _id:"chunksize", value: 64 } );

再增加一个路由节点
180.76.159.126:27117。
如第一个路由节点操作后,
启动mongos,客户端登录mongos。
使用mongo客户端登录27117,发现,第二个路由无需配置,因为分片配置都保存到了【配置服务器】中了。

Compass和SpringDataMongDB连接分片集群

如果在搭建分片的时候有操作失败或配置有问题,需要重新来过的,可以进行如下操作:
第一步:查询出所有的测试服务节点的进程

 ps -ef |grep mongo

根据上述的进程编号,依次中断进程

kill -2 进程编号

第二步:清除所有的节点的数据

rm -rf /mongodb/sharded_cluster/myconfigrs_27019/data/db/*.* \ &

第三步:查看或修改有问题的配置
第四步:依次启动所有节点,不包括路由节点
第五步:对两个数据分片副本集和一个配置副本集进行初始化和相关配置
第六步:检查路由mongos的配置,并启动mongos
第七步:mongo登录mongos,在其上进行相关操作

安全认证

mongodb官网上说,为了能保障mongodb的安全可以做以下几个步骤:
1)使用新的端口,默认的27017端口如果一旦知道了ip就能连接上,不太安全。
2)设置mongodb的网络环境,最好将mongodb部署到公司服务器内网,这样外网是访问不到的。公司内部访问使用vpn等。
3)开启安全认证。认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式。

为了强制开启用户访问控制(用户验证),则需要在MongoDB实例启动时使用选项 --auth 或在指定启动配置文件中添加选项auth=true 。

1)启用访问控制:
MongoDB使用的是基于角色的访问控制(Role-Based Access Control,RBAC)来管理用户对实例的访问。通过对用户授予一个或多个角色来控制,用户访问数据库资源的权限和数据库操作的权限,在对用户分配角色之前,用户无法访问实例。
在实例启动时添加选项 --auth 或指定启动配置文件中添加选项 auth=true 。
2)角色:
在MongoDB中通过角色对用户授予相应数据库资源的操作权限,每个角色当中的权限可以显式指定,也可以通过继承其他角色的权限,或者两者都存在的权限。
3)权限:
权限由指定的数据库资源(resource)以及允许在指定资源上进行的操作(action)组成。

  1. 资源(resource)包括:数据库、集合、部分集合和集群;
  2. 操作(action)包括:对资源进行的增、删、改、查(CRUD)操作。
    在角色定义时可以包含一个或多个已存在的角色。新创建的角色会继承包含的角色所有的权限。
    在同一个数据库中,新创建角色可以继承其他角色的权限,在 admin 数据库中创建的角色可以继承在其它任意数据库中角色的权限。
db.runCommand({ rolesInfo: 1 }); // 查询所有角色权限(仅用户自定义角色)
db.runCommand({ rolesInfo: 1, showBuiltinRoles: true }); // 查询所有角色权限(包含内置角色)
db.runCommand({ rolesInfo: "<rolename>" }); // 查询当前数据库中的某角色的权限
db.runCommand({ rolesInfo: { role: "<rolename>", db: "<database>" } }; // 查询其它数据库中指定的角色权限

常用的内置角色:
数据库用户角色:read、readWrite;
所有数据库用户角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
数据库管理角色:dbAdmin、dbOwner、userAdmin;
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
备份恢复角色:backup、restore;
超级用户角色:root
内部角色:system

一、单实例环境开启安全认证(未开启副本集或分片的MongoDB实例)

1、通过mongo客户端中的shutdownServer命令来关闭服务

use admin; // 切换到admin库
db.shutdownServer(); // 关闭服务

2、添加用户和权限
按之前未开启认证的方式(不添加 --auth 参数)来启动MongoDB服务(在操作用户时,启动mongod服务时尽量不要开启授权)

/usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf

这里的/usr/local/mongodb/bin/mongod是因为,从官网上下载的mongod-linux-x86_64-4.0.10.tgz解压后,移到了mv mongodb-linux-x86_64-4.0.10 /usr/local/mongodb这个目录下。
使用Mongo客户端登录

/usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017

创建两个管理员用户,一个是系统的超级管理员 myroot ,一个是admin库的管理用户
myadmin

//切换到admin库
> use admin
//创建系统超级用户 myroot,设置密码123456,设置角色root
//> db.createUser({user:"myroot",pwd:"123456",roles:[ { "role" : "root", "db" : "admin" } ]});
//或
> db.createUser({user:"myroot",pwd:"123456",roles:["root"]});
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }
//创建专门用来管理admin库的账号myadmin,只用来作为用户权限的管理
> db.createUser({user:"myadmin",pwd:"123456",roles: [{role:"userAdminAnyDatabase",db:"admin"}]});
Successfully added user: 此处省略
//查看已经创建了的用户的情况:
> db.system.users.find();
//删除用户
> db.dropUser("myadmin");
true
//修改密码
> db.changeUserPassword("myroot", "myroot");

Mongodb存储所有的用户信息在admin 数据库的集合system.users中,保存用户名、密码
和数据库信息。如果不指定数据库,则创建的指定的权限的用户在所有的数据库上有效,如 {role:“userAdminAnyDatabase”, db:“”}

认证测试

//切换到admin
> use admin
//密码输错
> db.auth("myroot","12345")
Error: Authentication failed.
0
//密码正确
> db.auth("myroot","123456")
1

创建普通用户可以在没有开启认证的时候添加,也可以在开启认证之后添加,但开启认证之后,必须使用有操作admin库的用户登录认证后才能操作。底层都是将用户信息保存在了admin数据库的集合system.users中。

//创建(切换)将来要操作的数据库articledb,
> use articledb;
switched to db articledb
//创建用户,拥有articledb数据库的读写权限readWrite,密码是123456
> db.createUser({user: "bobo", pwd: "123456", roles: [{ role: "readWrite", db:"articledb" }]});
//> db.createUser({user: "bobo", pwd: "123456", roles: ["readWrite"]});
//测试是否可用
> db.auth("bobo","123456")
1

服务端开启认证和客户端连接登录
关闭已经启动的服务

> db.shutdownServer();
shutdown command only works with the admin database; try 'use admin'
> use admin;
switched to db admin
> db.shutdownServer();

必须是在admin库下执行该关闭服务命令。
如果没有开启认证,必须是从localhost登陆的,才能执行关闭服务命令。
非localhost的、通过远程登录的,必须有登录且必须登录用户有对admin操作权限才可以。

有两种方式开启权限认证启动服务:一种是参数方式,一种是配置文件方式。
1)参数方式
在启动时指定参数 --auth

/usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf --auth

2)配置文件方式
在mongod.conf配置文件中加入:
vim /mongodb/single/mongod.conf

security:
	#开启授权认证
	authorization: enabled

配置以后,启动时可不加 --auth 参数

/usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf

开启了认证的情况下的客户端登录
有两种认证方式,一种是先登录,在mongo shell中认证;一种是登录时直接认证。
1)先连接再认证

/usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017
> db.auth("myroot","123456")
1

2)连接时直接认证

 /usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 --authenticationDatabase admin -u myroot -p 123456
/usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 --authenticationDatabase articledb -u bobo -p 123456

-u :用户名
-p :密码
–authenticationDatabase :指定连接到哪个库。当登录是指定用户名密码时,必须指定对应的数据库!

二、副本集环境开启安全认证

对副本集执行访问控制需要配置两个方面:
1)副本集和共享集群的各个节点成员之间使用内部身份验证,可以使用密钥文件或x.509证书。密钥文件比较简单,本文使用密钥文件,官方推荐如果是测试环境可以使用密钥文件,但是正式环境,官方推荐x.509证书。原理就是,集群中每一个实例彼此连接的时候都检验彼此使用的证书的内容是否相同。只有证书相同的实例彼此才可以访问
2)使用客户端连接到mongodb集群时,开启访问授权。对于集群外部的访问。如通过可视化客户端,或者通过代码连接的时候,需要开启授权。
3)在keyfile身份验证中,副本集中的每个mongod实例都使用keyfile的内容作为共享密码,只有具有正确密钥文件的mongod或者mongos实例可以连接到副本集。密钥文件的内容必须在6到1024个字符之间,并且在unix/linux系统中文件所有者必须有对文件至少有读的权限。

增加副本集的安全认证和服务鉴权功能,可以在副本集搭建的时候直接添加,也可以在之前搭建好的副本集服务上添加。这里使用之前搭建好的副本集服务,因此,先停止之前的集群服务。
通过mongo客户端中的shutdownServer命令来依次关闭各个服务,建议依次关闭仲裁节点、副本节点、主节点。
//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。

mongo --port 27017;
//告知副本集说本机要下线
rs.stepDown();
//#切换到admin库
use admin;
//关闭服务
db.shutdownServer();

只需要在主节点上添加用户,副本集会自动同步。开启认证之前,创建超管用户:myroot,密码:123456

myrs:PRIMARY> use admin;
switched to db admin
myrs:PRIMARY> db.createUser({user:"myroot",pwd:"123456",roles:["root"]});
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }

该步骤也可以在开启认证之后,但需要通过localhost登录才允许添加用户,用户数据也会自动同步到副本集。
后续再创建其他用户,都可以使用该超管用户创建。

创建副本集认证的key文件
第一步:生成一个key文件到当前文件夹中。以下操作使用openssl生成密码文件,然后使用chmod来更改文件权限,仅为文件所有者提供读取权限

[root@bobohost ~]# openssl rand -base64 90 -out ./mongo.keyfile
[root@bobohost ~]# chmod 400 ./mongo.keyfile
[root@bobohost ~]# ll mongo.keyfile
-r--------. 1 root root 122 8月 14 14:23 mongo.keyfile

所有副本集节点都必须要用同一份keyfile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读的权限,否则将来会报错: permissions on /mongodb/replica_sets/myrs_27017/mongo.keyfile are too open
一定要保证密钥文件一致,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,都放到和配置文件一起的目录中。

修改配置文件指定keyfile,分别编辑几个服务的mongod.conf文件,添加相关内容:

 security:
	#KeyFile鉴权文件
	keyFile: /mongodb/replica_sets/myrs_27017/mongo.keyfile
	#开启认证方式运行
	authorization: enabled

重新启动副本集
如果副本集是开启状态,则先分别关闭关闭复本集中的每个mongod,从次节点开始。直到副本集的所有成员都离线,包括任何仲裁者。主节点必须是最后一个成员关闭,以避免潜在的回滚。
在主节点上添加普通账号

#先用管理员账号登录
#切换到admin库
use admin
#管理员账号认证
db.auth("myroot","123456")
#切换到要认证的库
use articledb
#添加普通用户
db.createUser({user: "bobo", pwd: "123456", roles: ["readWrite"]})

重新连接,使用普通用户bobo重新登录,查看数据。

分片集群环境开启安全认证

分片集群环境下的安全认证和副本集环境下基本上一样。
但分片集群的服务器环境和架构较为复杂,建议在搭建分片集群的时候,直接加入安全认证和服务器间的鉴权。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值