MongoDB

MongoDB


里面已经收录上百套项目资料,自行获取。
无套路分享:

http://106.75.108.26:8001/index?empid=15
建议收藏:会一直持续更新。。。

MongoDB下载与安装

环境

软件版本
centos7

下载与安装

1、这里提供 4.4.7的版本

https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.7.tgz

其他版本可以去官网自行选择
官网:

https://www.mongodb.com/try/download

在这里插入图片描述
2、使用上传工具将安装包上传到Linux虚拟机上(我这里使用的是rz)
在这里插入图片描述
3、将压缩包解压即可

tar -zxvf mongodb-linux-x86_64-rhel70-4.4.7.tgz

在这里插入图片描述
4、指定配置文件方式的启动

./bin/mongod -f mongo.conf

配置文件样例: 
dbpath=/data/mongo/  # 需要保证该路径是存在的,不然启动会报错
port=27017 
bind_ip=0.0.0.0 
fork=true 
logpath = /data/mongo/MongoDB.log 
logappend = true 
auth=false

在这里插入图片描述在这里插入图片描述
MongoDB启动和参数说明

参数 			说明 
dbpath 			数据库目录,默认/data/db 
port 			监听的端口,默认27017 
bind_ip 		监听IP地址,默认全部可以访问 
fork 			是否已后台启动的方式登陆 
logpath 		日志路径 
logappend 		是否追加日志 
auth 			是开启用户密码登陆 config 指定配置文件

mongo shell 的启动

启动mongo shell 
	./bin/mongo 
指定主机和端口的方式启动 
	./bin/mongo --host=主机IP --port=端口

在这里插入图片描述

MongoDB的基本操作

查看数据库 
	show dbs; 
切换数据库 如果没有对应的数据库则创建 
	use 数据库名; 
创建集合 
	db.createCollection("集合名") 
查看集合 
	show tables; show collections; 
删除集合 
	db.集合名.drop(); 
删除当前数据库 
	db.dropDatabase();

MongoDB集合数据操作(CURD)

数据添加

1. 插入单条数据 db.集合名.insert(文档) 
  		文档的数据结构和JSON基本一样。
  		所有存储在集合中的数据都是BSON格式。
  		BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON。
2. 例如: 
  		db.lg_resume_preview.insert({name:"张晓峰",birthday:new ISODate("2000-07-01"),expectSalary:15000,gender:0,city:"bj"})
  		没有指定 _id 这个字段 系统会自动生成 当然我们也可以指定 _id
  		( _id 类型是ObjectId 类型是一个12字节 BSON 类型数据,有以下格式:
  			前4个字节表示时间戳 ObjectId("对象Id字符串").getTimestamp() 来获取
  			接下来的3个字节是机器标识码
  			紧接的两个字节由进程id组成(PID)
  			最后三个字节是随机数。) 
3. 插入多条数据
  			db.集合名.insert([文档,文档])

数据查询

比较条件查询
db.集合名.find(条件)

操作条件格式例子RDBMS中的条件
等于{key:value}db.col.find({字段名:值}).pretty()where 字段名=值
大于{key:{$gt:value}}db.col.find({字段名:{$gt:值}}).pretty()where 字段名>值
小于{key:$lt:value}}db.col.find({字段名:{$lt:值}}).pretty()where 字段名<值
大于等于{key:{$gte:value}}db.col.find({字段名:{$gte:值}}).pretty()where 字段名>=值
小于等于{key:$lte:value}}db.col.find({字段名:{$lte:值}}).pretty()where 字段名<=值
不等于{key:$ne:value}}db.col.find({字段名:{$ne:值}}).pretty()where 字段名!=值

逻辑条件查询

and 条件 
	MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件 
	db.集合名.find({key1:value1, key2:value2}).pretty()
or 条件
	db.集合名.find({$or:[{key1:value1}, {key2:value2}]}).pretty() 
not 条件 
	db.集合名.find({key:{$not:{$操作符:value}}).pretty()

分页查询
db.集合名.find({条件}).sort({排序字段:排序方式})).skip(跳过的行数).limit(一页显示多少数据)

数据更新

调用update

$set :设置字段值 
$unset :删除指定字段 
$inc:对修改的值进行自增 
db.集合名.update( 
	<query>, 
	<update>,
	 { 
	 	upsert: <boolean>, 
	 	multi: <boolean>,
	 	writeConcern: <document> 
	 }
)
参数说明: 

query : update的查询条件,类似sql update查询内where后面的。 
update : update的对象和一些更新的操作符(如$set,$inc...)等,也可以理解为sql update中 set后面的 
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认 是false,不插入。 
multi : 可选,MongoDB 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查 出来多条记录全部更新。 
writeConcern :可选,用来指定mongod对写操作的回执行为比如写的行为是否需要确认。

举例: db.集合名.update({条件},{$set:{字段名:值}},{multi:true})
writeConcern 包括以下字段: 
{ w: <value>, j: <boolean>, wtimeout: <number> } 
	w:指定写操作传播到的成员数量 
比如:
	 w=1(默认):则要求得到写操作已经传播到独立的Mongod实例或副本集的primary成员的确认 
	 w=0:则不要求确认写操作,可能会返回socket exceptions和 networking errors 
	 w="majority":要求得到写操作已经传播到大多数具有存储数据具有投票的(data-bearing voting )成员(也就是 members[n].votes 值大于0的成员)的确认 
	
	 j:要求得到Mongodb的写操作已经写到硬盘日志的确认 
比如:
 j=true:要求得到Mongodb(w指定的实例个数)的写操作已经写到硬盘日志的确认。j=true本身并不保证 因为副本集故障而不会回滚。 wtimeout:指定write concern的时间限制,只适用于w>1的情况 
 wtimeout在超过指定时间后写操作会返回error,即使写操作最后执行成功,当这些写操作返回时, 
 MongoDB不会撤消在wtimeout时间限制之前执行成功的数据修改。 如果未指定wtimeout选项且未指定write concern级别,则写入操作将无限期阻止。 指定wtimeout值 为0等同于没有wtimeout选项。

数据删除

db.collection.remove( 
	<query>, 
	{
		 justOne: <boolean>, 
		 writeConcern: <document> 
	} 
)
参数说明: 
query :(可选)删除的文档的条件。 
justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
 writeConcern :(可选)用来指定mongod对写操作的回执行为。

MongoDB 聚合操作

聚合操作简介

聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档
里不存在的文档信息。一般都是将记录按条件分组之后进行一系列求最大值,最小值,平均值的简单操
作,也可以对记录进行复杂数据统计,数据挖掘的操作。聚合操作的输入是集中的文档,输出可以是一
个文档也可以是多个文档。

MongoDB 聚合操作分类

  • 单目的聚合操作(Single Purpose Aggregation Operation)
  • 聚合管道(Aggregation Pipeline)
  • MapReduce 编程模型

单目的聚合操作

单目的聚合命令常用的有:count() 和 distinct()

db.lg_resume_preview.find({}).count()

聚合管道(Aggregation Pipeline)

db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION) 
如: 
db.lg_resume_preview.aggregate([{$group:{_id:"$city",city_count:{$sum:1}}}])

MongoDB中聚合(aggregate)主要用于统计数据(诸如统计平均值,求和等),并返回计算后的数据结果。
表达式:处理输入文档并输出。表达式只能用于计算当前聚合管道的文档,不能处理其它的文档。

表达式描述
$sum计算总和
$avg计算平均值
$min获取集合中所有文档对应值的最小值
$max获取集合中所有文档对应值的最大值
$push在结果文档中插入值到一个数组中
$addToSet在结果文档中插入值到一个数组中,但数据不重复
$first根据资源文档的排序获取第一个文档数据
$last根据文档资源文档的排序获取最后一个文档数据

MongoDB 中使用 db.COLLECTION_NAME.aggregate([{},...])方法来构建和使用聚合管道,每个
文档通过一个由一个或者多个阶段(stage)组成的管道,经过一系列的处理,输出相应的结果。
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作
是可以重复的。
这里我们介绍一下聚合框架中常用的几个操作:

$group:将集合中的文档分组,可用于统计结果。
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及 嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。 
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$sort:将输入文档排序后输出。 
$geoNear:输出接近某一地理位置的有序文档。
db.lg_resume_preview.aggregate( 
	[	{$group : {_id: "$city", avgSal:{$avg:"$expectSalary"}}}, 
		{$project : {city: "$city", salary : "$avgSal"}}
	])
db.lg_resume_preview.aggregate(
	 [	{$group:{_id: "$city",count:{$sum : 1}}}, 
		{$match:{count:{$gt:1}}} 
	 ])

MapReduce 编程模型

Pipeline查询速度快于MapReduce,但是MapReduce的强大之处在于能够在多台Server上并行执行复
杂的聚合逻辑。MongoDB不允许Pipeline的单个聚合操作占用过多的系统内存,如果一个聚合操作消
耗20%以上的内存,那么MongoDB直接停止操作,并向客户端输出错误消息。
MapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结
果合并成最终结果(REDUCE)。

>db.collection.mapReduce( 
	function() {emit(key,value);}, //map 函数 
	function(key,values) {return reduceFunction}, //reduce 函数 
	{ 
		out: collection, 
		query: document, 
		sort: document, 
		limit: number, 
		finalize: <function>, 
		verbose: <boolean> 
	}
)

使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历
collection 中所有的记录, 将 key 与 value 传递给 Reduce 函数进行处理。
参数说明:

  • map:是JavaScript 函数,负责将每一个输入文档转换为零或多个文档,生成键值对序列,作为reduce 函数参数
  • reduce:是JavaScript函数,对map操作的输出做合并的化简的操作(将key-value变成keyvalues,也就是把values数组变成一个单一的值value)
  • out:统计结果存放集合
  • query: 一个筛选条件,只有满足条件的文档才会调用map函数。
  • sort:和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
  • limit:发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
  • finalize:可以对reduce输出结果再一次修改
  • verbose:是否包括结果信息中的时间信息,默认为fasle
db.lg_resume_preview.mapReduce( 
	function() { emit(this.city,this.expectSalary); },
	function(key, value) {return Array.avg(value)},
	{
		query:{expectSalary:{$gt: 15000}}, 
		out:"cityAvgSal" 
	} 
)

MongoDB索引Index

什么是索引

索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表
中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作
用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。索引目标是提高数据库的查
询效率,没有索引的话,查询会进行全表扫描(scan every document in a collection),数据量
大时严重降低了查询效率。默认情况下Mongo在一个集合(collection)创建时,自动地对集合
的_id创建了唯一索引。

索引类型

单键索引 (Single Field)

MongoDB支持所有数据类型中的单个字段索引,并且可以在文档的任何字段上定义。
对于单个字段索引,索引键的排序顺序无关紧要,因为MongoDB可以在任一方向读取索引。
单个例上创建索引:
db.集合名.createIndex({“字段名”:排序方式})
特殊的单键索引 过期索引 TTL ( Time To Live)
TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前TTL索引
只能在单字段上建立,并且字段类型必须是日期类型。

db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})

复合索引(Compound Index)

通常我们需要在多个字段的基础上搜索表/集合,这是非常频繁的。 如果是这种情况,我们可能会考虑
在MongoDB中制作复合索引。 复合索引支持基于多个字段的索引,这扩展了索引的概念并将它们扩展
到索引中的更大域。
制作复合索引时要注意的重要事项包括:字段顺序与索引方向。

db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )

多键索引(Multikey indexes)

针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikey
indexes支持strings,numbers和nested documents

地理空间索引(Geospatial Index)

针对地理空间坐标数据创建索引。
2dsphere索引,用于存储和查找球面上的点
2d索引,用于存储和查找平面上的点

db.company.insert( 
	{ 
		loc : { type: "Point", coordinates: [ 116.482451, 39.914176 ] }, 
		name: "大望路地铁", 
		category : "Parks" 
	}
)
db.company.ensureIndex( { loc : "2dsphere" } ) 
参数不是1或-1,为2dsphere 或者 2d。还可以建立组合索引。 
db.company.find({
	 "loc" : {
	 	"$geoWithin" : { 
	 		"$center":[[116.482451,39.914176],0.05] 
	 	} 
	 } 
})

全文索引

MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的
索引查询。注意:一个集合仅支持最多一个Text Index,中文分词不理想 推荐ES。

db.集合.createIndex({"字段": "text"}) 
db.集合.find({"$text": {"$search": "coffee"}})

哈希索引 Hashed Index

针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无
需程序计算hash值。注:hash index仅支持等于查询,不支持范围查询。

db.集合.createIndex({"字段": "hashed"})

MongoDB实战

MongoDB的适用场景

  • 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  • 缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载。
  • 大尺寸、低价值的数据:使用传统的关系型数据库存储一些大尺寸低价值数据时会比较浪费,在此之前,很多时候程序员往往会选择传统的文件进行存储。
  • 高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce引擎的内置支持以及集群高可用的解决方案。
  • 用于对象及JSON 数据的存储:Mongo 的BSON数据格式非常适合文档化格式的存储及查询。

MongoDB的行业具体应用场景

  • 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存 储,方便查询、更新。
  • 物流场景,使用MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
  • 社交场景,使用 MongoDB存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引 实现附近的人、地点等功能。
  • 物联网场景,使用 MongoDB存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这 些信息进行多维度的分析。
  • 直播,使用 MongoDB存储用户信息、礼物信息等。

如何抉择是否使用MongoDB

应用特征Yes / No
应用不需要事务及复杂 join 支持必须 Yes
新应用,需求会变,数据模型无法确定,想快速迭代开发
应用需要2000-3000以上的读写QPS(更高也可以)
应用需要TB甚至 PB 级别数据存储?
应用发展迅速,需要能快速水平扩展?
应用要求存储的数据不丢失?
应用需要99.999%高可用?
应用需要大量的地理位置查询、文本查询

Java 访问MongoDB

maven 依赖

<dependency> 
	<groupId>org.mongodb</groupId> 
	<artifactId>mongo-java-driver</artifactId> 
	<version>3.10.1</version> 
</dependency>

文档添加

MongoClient mongoClient = new MongoClient("192.168.211.133", 37017); 
MongoDatabase database = mongoClient.getDatabase("lg_resume"); 
MongoCollection<Document> collection = database.getCollection("lg_resume_preview"); 
Document document = Document.parse(
	 "{name:'lisi',city:'bj',birth_day:new ISODate('2001-08- 01'),
	 expectSalary:18000}"); 
collection.insertOne(document );
mongoClient.close();

文档查询

MongoClient mongoClient = new MongoClient("192.168.211.133", 37017); 
MongoDatabase database = mongoClient.getDatabase("lg_resume"); 
MongoCollection<Document> collection = database.getCollection("lg_resume_preview"); 
Document sdoc=new Document(); 
//按expectSalary倒序 
sdoc.append("expectSalary", -1); 
FindIterable<Document> findIterable = collection.find().sort(sdoc);
for (Document document : findIterable) {
	System.out.println(document); 
}
mongoClient.close();

文档查询过滤

MongoClient mongoClient = new MongoClient("192.168.211.133", 37017); 
MongoDatabase database = mongoClient.getDatabase("lg_resume");
MongoCollection<Document> collection = database.getCollection("lg_resume_preview"); 
Document sdoc=new Document(); 
//按expectSalary倒序 
sdoc.append("expectSalary", -1); 
FindIterable<Document> findIterable = collection.find(Filters.gt("expectSalary",21000)).sort(sdoc); 
for (Document document : findIterable) { 
	System.out.println(document); 
}
mongoClient.close();

Spring 访问MongoDB

第1步:基于maven新建工程 导入依赖的包

<dependency> 
	<groupId>org.springframework.data</groupId> 
	<artifactId>spring-data-mongodb</artifactId> 
	<version>2.0.9.RELEASE</version> 
</dependency>

第2步:在配置文件中配置 MongoTemplate

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:mongo="http://www.springframework.org/schema/data/mongo" 
	xsi:schemaLocation=" http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd 
		http://www.springframework.org/schema/data/mongo 
		http://www.springframework.org/schema/data/mongo/spring-mongo.xsd"> 

	<!-- 构建MongoDb工厂对象 --> 
	<mongo:db-factory id="mongoDbFactory" client-uri="mongodb://192.168.211.133:37017/lg_resume"></mongo:db-factory> 
	<!-- 构建 MongoTemplate 类型的对象 --> 
	<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
		<constructor-arg index="0" ref="mongoDbFactory"></constructor-arg> 
	</bean> 
	<!-- 开启组件扫描 --> 
	<context:component-scan base-package="com.lagou"></context:component-scan> 
</beans>

第3步:DAO 实现类注入 MongoTemplate 完成增删改查

@Autowired 
protected MongoTemplate mongoTemplate;

第4步: 从Spring容器中获取DAO对象 进行测试 (注意:要开启组件扫描)

Spring Boot 访问 MongoDB

MongoTemplate 的方式

第1步:基于maven新建springboot工程

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-data-mongodb</artifactId> 
	<version>2.2.2.RELEASE</version> 
</dependency>

第2步: 配置文件application.properties

spring.data.mongodb.host=192.168.211.133 
spring.data.mongodb.port=37017 
spring.data.mongodb.database=lg_resume

第3步: DAO 实现类 注入 MongoTemplate 完成增删改查

@Autowired 
protected MongoTemplate mongoTemplate;

第4步: 从Spring容器中获取DAO对象 进行测试

MongoRepository 的方式

第1步:基于maven新建springboot工程

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-data-mongodb</artifactId> 
	<version>2.2.2.RELEASE</version> 
</dependency>

第2步: 配置文件application.properties

spring.data.mongodb.host=192.168.211.133 
spring.data.mongodb.port=37017 
spring.data.mongodb.database=lg_resume

第3步:编写实体类 并在实体类上打@Document(“集合名”)
第4步:编写 Repository 接口 继承 MongoRepository

方法具体参考:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-m
ethods.query-creation
如果内置方法不够用 就自己定义 如:定义find|read|get 等开头的方法进行查询

第5步: 从Spring容器中获取Repository对象 进行测试

MongoDB架构

MongoDB逻辑结构

在这里插入图片描述
MongoDB 与 MySQL 中的架构相差不多,底层都使用了可插拔的存储引擎以满足用户的不同需要。用
户可以根据程序的数据特征选择不同的存储引擎,在最新版本的 MongoDB 中使用了 WiredTiger 作为默
认的存储引擎,WiredTiger 提供了不同粒度的并发控制和压缩机制,能够为不同种类的应用提供了最
好的性能和存储率。
在存储引擎上层的就是 MongoDB 的数据模型和查询语言了,由于 MongoDB 对数据的存储与 RDBMS
有较大的差异,所以它创建了一套不同的数据模型和查询语言。

MongoDB的数据模型

描述数据模型

内嵌
内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。MongoDB的文档结构允许一个字
段或者一个数组内的值作为一个嵌套的文档。
引用
引用方式通过存储数据引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引
用来访问相关数据。

如何选择数据模型

选择内嵌:

  1. 数据对象之间有包含关系 ,一般是数据对象之间有一对多或者一对一的关系 。
  2. 需要经常一起读取的数据。
  3. 有 map-reduce/aggregation 需求的数据放在一起,这些操作都只能操作单个 collection。

选择引用:

  1. 当内嵌数据会导致很多数据的重复,并且读性能的优势又不足于覆盖数据重复的弊端 。
  2. 需要表达比较复杂的多对多关系的时候 。
  3. 大型层次结果数据集 嵌套不要太深。

MongoDB 存储引擎

存储引擎概述

存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上。MongoDB支持的存储引擎有 MMAPv1 ,WiredTiger和InMemory。InMemory存储引擎用于将数据只存储在内存中,只将少量的元数据 (meta-data)和诊断日志(Diagnostic)存储到硬盘文件中,由于不需要Disk的IO操作,就能获取所需 的数据,InMemory存储引擎大幅度降低了数据查询的延迟(Latency)。从mongodb3.2开始默认的存储 引擎是WiredTiger,3.2版本之前的默认存储引擎是MMAPv1,mongodb4.x版本不再支持MMAPv1存储引 擎。

storage: 
	journal: 
		enabled: true 
	dbPath: /data/mongo/
	##是否一个库一个文件夹 
	directoryPerDB: true 
	##数据引擎 
	engine: wiredTiger 
	##WT引擎配置 
	WiredTiger: 
		engineConfig: 
			##WT最大使用cache(根据服务器实际情况调节) 
			cacheSizeGB: 2
			##是否将索引也按数据库名单独存储 
			directoryForIndexes: true 
			journalCompressor:none (默认snappy) 
		##表压缩配置 
		collectionConfig: blockCompressor: zlib (默认snappy,还可选none、zlib) 
		##索引配置 
		indexConfig: 
			prefixCompression: true

WiredTiger存储引擎优势

1.文档空间分配方式 
	WiredTiger使用的是BTree存储 MMAPV1 线性存储 需要Padding 
2.并发级别 WiredTiger 
	文档级别锁 MMAPV1引擎使用表级锁 
3.数据压缩 
	snappy (默认) 和 zlib ,相比MMAPV1(无压缩) 空间节省数倍。 
4.内存使用 
	WiredTiger 可以指定内存的使用大小。 
5.Cache使用 
	WT引擎使用了二阶缓存WiredTiger Cache, File System Cache来保证Disk上的数据的最终一 致性。
	而MMAPv1 只有journal 日志

WiredTiger引擎包含的文件和作用

在这里插入图片描述

  • WiredTiger.basecfg: 存储基本配置信息,与 ConfigServer有关系
  • WiredTiger.lock: 定义锁操作
  • table*.wt: 存储各张表的数据
  • WiredTiger.wt: 存储table* 的元数据
  • WiredTiger.turtle:存储WiredTiger.wt的元数据
  • journal: 存储WAL(Write Ahead Log)

WiredTiger存储引擎实现原理

写请求
WiredTiger的写操作会默认写入 Cache ,并持久化到 WAL (Write Ahead Log),每60s或Log文件达到2G
做一次 checkpoint (当然我们也可以通过在写入时传入 j: true 的参数强制 journal 文件的同步 ,
writeConcern
{ w: , j: , wtimeout: }) 产生快照文件。WiredTiger初始化时,恢复至最新的快照状态,然后再根据WAL
恢复数据,保证数据的完整性。
在这里插入图片描述
Cache是基于BTree的,节点是一个page,root page是根节点,internal page是中间索引节点,leaf
page真正存储数据,数据以page为单位读写。WiredTiger采用Copy on write的方式管理写操作
(insert、update、delete),写操作会先缓存在cache里,持久化时,写操作不会在原来的leaf page
上进行,而是写入新分配的page,每次checkpoint都会产生一个新的root page。

checkpoint流程

1.对所有的table进行一次checkpoint,每个table的checkpoint的元数据更新至WiredTiger.wt
2.对WiredTiger.wt进行checkpoint,将该table checkpoint的元数据更新至临时文件 WiredTiger.turtle.set
3.将WiredTiger.turtle.set重命名为WiredTiger.turtle。
4.上述过程如果中间失败,WiredTiger在下次连接初始化时,首先将数据恢复至最新的快照状态,然后根 据WAL恢复数据,以保证存储可靠性。

Journaling
在数据库宕机时 , 为保证 MongoDB 中数据的持久性,MongoDB 使用了 Write Ahead Logging 向磁盘
上的 journal 文件预先进行写入。除了 journal 日志,MongoDB 还使用检查点(checkpoint)来保证
数据的一致性,当数据库发生宕机时,我们就需要 checkpoint 和 journal 文件协作完成数据的恢复工
作。

  1. 在数据文件中查找上一个检查点的标识符
  2. 在 journal 文件中查找标识符对应的记录
  3. 重做对应记录之后的全部操作
    在这里插入图片描述

MongoDB集群高可用

MongoDB主从复制架构原理和缺陷

master-slave架构中master节点负责数据的读写,slave没有写入权限只负责读取数据。
在这里插入图片描述
在主从结构中,主节点的操作记录成为oplog(operation log)。oplog存储在系统数据库local的 oplog.$main集合中,这个集合的每个文档都代表主节点上执行的一个操作。从服务器会定期从主服务器 中获取oplog记录,然后在本机上执行!对于存储oplog的集合,MongoDB采用的是固定集合,也就是说随 着操作过多,新的操作会覆盖旧的操作!

主从结构没有自动故障转移功能,需要指定master和slave端,不推荐在生产中使用。
mongodb4.0后不再支持主从复制!
[main] Master/slave replication is no longer supported

复制集replica sets

什么是复制集

在这里插入图片描述
复制集是由一组拥有相同数据集的mongod实例做组成的集群。
复制集是一个集群,它是2台及2台以上的服务器组成,以及复制集成员包括Primary主节点,secondary从节点和投票节点。 复制集提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,保证数据的安全 性。

为什么要使用复制集

1.高可用防止设备(服务器、网络)故障。 提供自动failover 功能。 技术来保证高可用
2.灾难恢复 当发生故障时,可以从其他节点恢复 用于备份。
3.功能隔离 我们可以在备节点上执行读操作,减少主节点的压力
比如:用于分析、报表,数据挖掘,系统任务等。

复制集集群架构原理

一个复制集中Primary节点上能够完成读写操作,Secondary节点仅能用于读操作。Primary节点需要记
录所有改变数据库状态的操作,这些记录保存在 oplog 中,这个文件存储在 local 数据库,各个Secondary
节点通过此 oplog 来复制数据并应用于本地,保持本地的数据与主节点的一致。oplog 具有幂等性,即无
论执行几次其结果一致,这个比 mysql 的二进制日志更好用。

oplog的组成结构

{
"ts" : Timestamp(1446011584, 2), 
"h" : NumberLong("1687359108795812092"),
 "v" : 2,
 "op" : "i", 
 "ns" : "test.nosql", 
 "o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), 
 "name" : "mongodb", "score" : "10"}
 }

ts:操作时间,当前timestamp + 计数器,计数器每秒都被重置 
h:	操作的全局唯一标识
v:	oplog版本信息 
op:操作类型 
	i:	插入操作 
	u:	更新操作 
	d:	删除操作 
	c:	执行命令(如createDatabase,dropDatabase) 
n:	空操作,特殊用途 
ns:操作针对的集合 
o:	操作内容 
o2:更新查询条件,仅update操作包含该字段

复制集数据同步分为初始化同步和keep复制同步。初始化同步指全量从主节点同步数据,如果Primary
节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后,节点之间的实时同步一般是增量
同步。
初始化同步有以下两种情况会触发:
(1) Secondary第一次加入。
(2) Secondary落后的数据量超过了oplog的大小,这样也会被全量复制。

MongoDB的Primary节点选举基于心跳触发。一个复制集N个节点中的任意两个节点维持心跳,每个节
点维护其他N-1个节点的状态。
在这里插入图片描述

心跳检测:
整个集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其他节点每2秒就会发送一次pings包,
如果其他节点在10秒钟之内没有返回就标示为不能访问。每个节点内部都会 维护一个状态映射表,表明当前每个节点是什么角色、日志时间戳等关键信息。如果主节点发现自己无法与 大部分节点通讯则把自己降级为secondary只读节点。

主节点选举触发的时机:

第一次初始化一个复制集
Secondary节点权重比Primary节点高时,发起替换选举
Secondary节点发现集群中没有Primary时,发起选举
Primary节点不能访问到大部分(Majority)成员时主动降级

当触发选举时,Secondary节点尝试将自身选举为Primary。主节点选举是一个二阶段过程+多数派协议。

第一阶段: 检测自身是否有被选举的资格 如果符合资格会向其它节点发起本节点是否有选举资格的 FreshnessCheck,进行同僚仲裁
第二阶段: 发起者向集群中存活节点发送Elect(选举)请求,仲裁者收到请求的节点会执行一系列合法性检查,如果检 查通过,则仲裁者(一个复制集中最多50个节点 其中只有7个具有投票权)给发起者投一票。 pv0通过30秒选举锁防止一次选举中两次投票。 pv1使用了terms(一个单调递增的选举计数器)来防止在一次选举中投两次票的情况。
多数派协议: 发起者如果获得超过半数的投票,则选举通过,自身成为Primary节点。获得低于半数选票的原因,除了常 见的网络问题外,相同优先级的节点同时通过第一阶段的同僚仲裁并进入第二阶段也是一个原因。因此,当 选票不足时,会sleep[0,1]秒内的随机时间,之后再次尝试选举。

复制集搭建

在这里插入图片描述
1.主节点配置 mongo_37017.conf

# 主节点配置 
dbpath=/data/mongo/data/server1 
bind_ip=0.0.0.0 
port=37017 
fork=true 
logpath=/data/mongo/logs/server1.log 
replSet=lagouCluster

2.从节点1配置 mongo_37018.conf

dbpath=/data/mongo/data/server2 
bind_ip=0.0.0.0 
port=37018 
fork=true 
logpath=/data/mongo/logs/server2.log 
replSet=lagouCluster

3.从节点2配置 mongo_37019.conf

dbpath=/data/mongo/data/server3 
bind_ip=0.0.0.0 
port=37019 
fork=true 
logpath=/data/mongo/logs/server3.log 
replSet=lagouCluster

4.初始化节点配置
启动三个节点 然后进入任意一个节点 运行如下命令:

var cfg ={"_id":"lagouCluster", 
		"protocolVersion" : 1, 
		"members":[ 
			{"_id":1,"host":"192.168.211.133:37017","priority":10}, 
			{"_id":2,"host":"192.168.211.133:37018"} 
		] 
	}
rs.initiate(cfg) 
rs.status()

5.节点的动态增删

增加节点 
rs.add("192.168.211.133:37019") 
删除slave 节点 
rs.remove("192.168.211.133:37019")

6.复制集操作演示
进入主节点 ----- 插入数据 ------ 进入从节点验证
注意:默认节点下从节点不能读取数据。调用 rs.slaveOk() 解决
为了保证高可用,在集群当中如果主节点挂掉后,会自动 在从节点中选举一个 重新做为主节点。
rs.status()
节点说明:
PRIMARY 节点: 可以查询和新增数据
SECONDARY 节点:只能查询 不能新增 基于priority 权重可以被选为主节点
ARBITER 节点: 不能查询数据 和新增数据 ,不能变成主节点

复制集成员的配置参数

参数字段类型说明取值说明
_id整数_id:0复制集中的标识
host字符串host:“主机:端口”节点主机名
arbiterOnly布尔值arbiterOnly:true是否为仲裁(裁判)节点
priority(权重)整数priority=0|1默认1,是否有资格变成主节点,取值范围0-1000,0永远不会变成主节点
hidden布尔值hidden=true|false ,0|1隐藏,权重必须为0,才可以设置
votes整数votes = 0|1投票,是否为投票节点,0不投票,1投票
slaveDelay整数slaveDelay=3600从库的延迟多少秒
buildIndexes布尔值buildIndexes=true|false,0|1主库的索引,从库也创建,_id索引无效

举例:

var cfg ={"_id":"lagouCluster",
			"protocolVersion" : 1, 
			"members":[ 
				{"_id":1,"host":"192.168.211.133:37017","priority":10}, 
				{"_id":2,"host":"192.168.211.133:37018","priority":0}, 
				{"_id":3,"host":"192.168.211.133:37019","priority":5}, 
				{"_id":4,"host":"192.168.211.133:37020","arbiterOnly":true}
			] 
		}; 
// 重新装载配置,并重新生成集群节点。 
rs.reconfig(cfg) 
//重新查看集群状态 
rs.status()

有仲裁节点复制集搭建

和上面的配置步骤相同 只是增加了 一个特殊的仲裁节点
注入节点 执行 rs.addArb(“IP:端口”);
rs.addArb(“192.168.211.133:37020”)

分片集群 Shard Cluster

什么是分片

分片(sharding)是MongoDB用来将大型集合水平分割到不同服务器(或者复制集)上所采用的方法。 不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载。

为什么要分片

1.存储容量需求超出单机磁盘容量。
2.活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能。
3.IOPS超出单个MongoDB节点的服务能力,随着数据的增长,单机实例的瓶颈会越来越明显。
4.副本集具有节点数量限制。

垂直扩展:增加更多的CPU和存储资源来扩展容量。
水平扩展:将数据集分布在多个服务器上。水平扩展即分片。

分片的工作原理

在这里插入图片描述
分片集群由以下3个服务组成:
Shards Server: 每个shard由一个或多个mongod进程组成,用于存储数据。
Router Server: 数据库集群的请求入口,所有请求都通过Router(mongos)进行协调,不需要在应用程 序添加一个路由选择器,Router(mongos)就是一个请求分发中心它负责把应用程序的请求转发到对应的 Shard服务器上。
Config Server: 配置服务器。存储所有数据库元信息(路由、分片)的配置。

片键(shard key)
为了在数据集合中分配文档,MongoDB使用分片主键分割集合。
区块(chunk)
在一个shard server内部,MongoDB还是会把数据分为chunks,每个chunk代表这个shard
server内部一部分数据。MongoDB分割分片数据到区块,每一个区块包含基于分片主键的左闭右开的
区间范围。
分片策略

  • 范围分片(Range based sharding)
    在这里插入图片描述

范围分片是基于分片主键的值切分数据,每一个区块将会分配到一个范围。
范围分片适合满足在一定范围内的查找,例如查找X的值在[20,30)之间的数据,mongo 路由根据
Config server中存储的元数据,可以直接定位到指定的shard的Chunk中。
缺点: 如果shard key有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个chunk,无
法扩展写的能力。

  • hash分片(Hash based sharding)
    在这里插入图片描述

Hash分片是计算一个分片主键的hash值,每一个区块将分配一个范围的hash值。
Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围
分片的不足,缺点是不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找
出满足条件的文档。

  • 组合片键 A + B(散列思想 不能是直接hash)
    数据库中没有比较合适的片键供选择,或者是打算使用的片键基数太小(即变化少如星期只有7天
    可变化),可以选另一个字段使用组合片键,甚至可以添加冗余字段来组合。一般是粗粒度+细粒
    度进行组合。

合理的选择shard key
无非从两个方面考虑,数据的查询和写入,最好的效果就是数据查询时能命中更少的分片,数据写入时
能够随机的写入每个分片,关键在于如何权衡性能和负载。

分片集群的搭建过程

在这里插入图片描述

1.配置 并启动config 节点集群

节点1 config-17017.conf

# 数据库文件位置 
dbpath=config/config1 
#日志文件位置 
logpath=config/logs/config1.log 
# 以追加方式写入日志 
logappend=true 
# 是否以守护进程方式运行 
fork = true 
bind_ip=0.0.0.0 port = 17017 
# 表示是一个配置服务器 
configsvr=true 
#配置服务器副本集名称 
replSet=configsvr

节点2 config-17018.conf

# 数据库文件位置
dbpath=config/config2 
#日志文件位置 
logpath=config/logs/config.log 
# 以追加方式写入日志 
logappend=true 
# 是否以守护进程方式运行 
fork = true bind_ip=0.0.0.0 
port = 17018 
# 表示是一个配置服务器 
configsvr=true 
#配置服务器副本集名称 
replSet=configsvr

节点3 config-17019.conf

# 数据库文件位置 
dbpath=config/config3 
#日志文件位置 
logpath=config/logs/config3.log 
# 以追加方式写入日志 
logappend=true 
# 是否以守护进程方式运行 
fork = true 
bind_ip=0.0.0.0 
port = 17019 
# 表示是一个配置服务器 
configsvr=true 
#配置服务器副本集名称 
replSet=configsvr

启动配置节点

./bin/mongod -f config/config-17017.conf 
./bin/mongod -f config/config-17018.conf 
./bin/mongod -f config/config-17019.conf

进入任意节点的mongo shell 并添加 配置节点集群 注意use admin

./bin/mongo --port 17017 

use admin 

var cfg ={"_id":"configsvr", 
		"members":[ 
			{"_id":1,"host":"192.168.211.133:17017"}, 
			{"_id":2,"host":"192.168.211.133:17018"}, 
			{"_id":3,"host":"192.168.211.133:17019"}
		]
	};
rs.initiate(cfg)
2.配置shard集群

shard1集群搭建37017到37019

dbpath=shard/shard1/shard1-37017 
bind_ip=0.0.0.0 
port=37017 
fork=true 
logpath=shard/shard1/shard1-37017.log 
replSet=shard1 
shardsvr=true 

dbpath=shard/shard1/shard1-37018 
bind_ip=0.0.0.0 
port=37018 
fork=true 
logpath=shard/shard1/logs/shard1-37018.log 
replSet=shard1 
shardsvr=true 

dbpath=shard/shard1/shard1-37019 
bind_ip=0.0.0.0 
port=37019 
fork=true 
logpath=shard/shard1/logs/shard1-37019.log 
replSet=shard1 
shardsvr=true
启动每个mongod 然后进入其中一个进行集群配置 
var cfg ={"_id":"shard1", 
	"protocolVersion" : 1, 
	"members":[ 
		{"_id":1,"host":"192.168.211.133:37017"}, 
		{"_id":2,"host":"192.168.211.133:37018"}, 
		{"_id":3,"host":"192.168.211.133:37019"} 
	]
};
rs.initiate(cfg) 
rs.status()

shard2集群搭建47017到47019

dbpath=shard/shard2/shard2-47017 
bind_ip=0.0.0.0 
port=47017 
fork=true 
logpath=shard/shard2/logs/shard2-47017.log 
replSet=shard2 
shardsvr=true 

dbpath=shard/shard2/shard2-47018
bind_ip=0.0.0.0 
port=47018 
fork=true 
logpath=shard/shard2/logs/shard2-47018.log 
replSet=shard2 
shardsvr=true 

dbpath=shard/shard2/shard2-47019 
bind_ip=0.0.0.0 
port=47019 
fork=true 
logpath=shard/shard2/logs/shard2-47019.log 
replSet=shard2 
shardsvr=true
启动每个mongod 然后进入其中一个进行集群配置 
var cfg ={"_id":"shard2", 
	"protocolVersion" : 1, 
	"members":[ 
		{"_id":1,"host":"192.168.211.133:47017"}, 
		{"_id":2,"host":"192.168.211.133:47018"}, 
		{"_id":3,"host":"192.168.211.133:47019"} 
	]
};
rs.initiate(cfg) 
rs.status()
3.配置和启动 路由节点

route-27017.conf

port=27017 
bind_ip=0.0.0.0 
fork=true 
logpath=route/logs/route.log 
configdb=configsvr/192.168.211.133:17017,192.168.211.133:17018,192.168.211.133:17019

启动路由节点使用 mongos (注意不是mongod)

./bin/mongos -f route/route-27017.conf
4. mongos(路由)中添加分片节点

进入路由mongos

mongo --port 27017 
sh.status() 
sh.addShard("shard1/192.168.211.133:37017,192.168.211.133:37018,192.168.211.133:37019"); 
sh.addShard("shard2/192.168.211.133:47017,192.168.211.133:47018,192.168.211.133:47019"); 
sh.status()
5. 开启数据库和集合分片(指定片键)

继续使用mongos完成分片开启和分片大小设置

为数据库开启分片功能 
sh.enableSharding("lagou_resume") 
为指定集合开启分片功能 
sh.shardCollection("lagou_resume.lagou_resume_datas",{"片键字段名如 name":索引说明})
6. 向集合中插入数据测试

通过路由循环向集合中添加数

use lagou_resume; 

for(var i=1;i<= 1000;i++){ 
	db.lagou_resume_datas.insert({"name":"test"+i, 
				salary:(Math.random()*20000).toFixed(2)}); 
}
7.验证分片效果

分别进入 shard1 和 shard2 中的数据库 进行验证

MongoDB安全认证

安全认证概述

MongoDB 默认是没有账号的,可以直接连接,无须身份验证。实际项目中肯定是要权限验证的,否则
后果不堪设想。从2016年开始 发生了多起MongoDB黑客赎金事件,大部分MongoDB安全问题 暴露出
了安全问题的短板其实是用户,首先用户对于数据库的安全不重视,其次用户在使用过程中可能没有养
成定期备份的好习惯,最后是企业可能缺乏有经验和技术的专业人员。所以对MongoDB进行安全认证
是必须要做的。

用户相关操作

切换到admin数据库对用户的添加

use admin;
db.createUser(userDocument):用于创建 MongoDB 登录用户以及分配权限的方法

db.createUser( {
	user: "账号", 
	pwd: "密码", 
	roles: [ 
		{ role: "角色", db: "安全认证的数据库" }, 
		{ role: "角色", db: "安全认证的数据库" } 
	] 
})

user:创建的用户名称,如 admin、root 、lagou
pwd:用户登录的密码
roles:为用户分配的角色,不同的角色拥有不同的权限,参数是数组,可以同时设置多个
role:角色,MonngoDB 已经约定好的角色,不同的角色对应不同的权限 后面会对role做详细解释
db:数据库实例名称,如 MongoDB 4.0.2 默认自带的有 admin、local、config、test 等,即为哪个数
据库实例 设置用户
举例:

db.createUser({
	user:"root", 
	pwd:"123321", 
	roles:[
		{role:"root",db:"admin"}
	] 
})

修改密码

 db.changeUserPassword( 'root' , 'rootNew' );

用户添加角色

 db.grantRolesToUser( '用户名' , [{ role: '角色名' , db: '数据库名'}])

以auth 方向启动mongod

./bin/mongod -f conf/mongo.conf --auth
(也可以在mongo.conf 中添加auth=true 参数)

验证用户

 db.auth("账号","密码")

删除用户

 db.dropUser("用户名")

角色

数据库内置的角色

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

各个类型用户对应的角色

数据库用户角色:read、readWrite 
数据库管理角色:dbAdmin、dbOwner、userAdmin 
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager 
备份恢复角色:backup、restore; 
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、
			userAdminAnyDatabase、 dbAdminAnyDatabase 
超级用户角色:root 这里还有几个角色间接或直接提供了系统超级用户的访问
			(dbOwner 、userAdmin、 userAdminAnyDatabase)

单机安全认证实现流程

创建 mydb1 数据库并创建了两个用户,zhangsan 拥有读写权限,lisi 拥有只读权限测试这两个账户的权限。
以超级管理员登录测试权限。

1. 创建管理员

MongoDB 服务端开启安全检查之前,至少需要有一个管理员账号,admin 数据库中的用户都被视为管理员
如果 admin 库没有任何用户的话,即使在其他数据库中创建了用户,启用身份验证,默认的连接方式
依然会有超级权限,即仍然可以不验证账号密码照样能进行 CRUD,安全认证相当于无效。

>use admin 
switched to db admin 
> db 
admin 
> db.createUser({ 
	user:"root", 
	pwd:"123456", 
	roles:[
		{role:"root",db:"admin"}
	] 
})

2. 创建普通用户

如下所示 mydb1 是自己新建的数据库,没安全认证之前可以随意 CRUD,其余的都是 mongoDB自带的数据库

>show dbs
admin 0.000GB 
config 0.000GB 
local 0.000GB 
mydb1 0.000GB 
> use mydb1 
switched to db mydb1 
> db.c1.insert({name:"testdb1"}) 
> > db.c1.insert({name:"testdb1"}) 
> show tables 
c1
c2
> db.c1.find() 
...
  • 为 admin 库创建管理员之后,现在来为 普通数据库创建普通用户,以 mydb1 为例,方式与创建
    管理员一致,切换到指定数据库进行创建即可。
  • 如下所示,为 mydb1 数据库创建了两个用户,zhangsan 拥有读写权限,lisi 拥有只读权限,密码
    都是 123456.
use mydb1 
switched to db mydb1 
> db 
mydb1 
> db.createUser({ 
	user:"zhangsan",  
	pwd:"123456", 
	roles:[
		{role:"readWrite",db:"mydb1"}
	]  
}) 

> db.createUser({ 
	user:"lisi", 
	pwd:"123456", 
	roles:[
		{role:"read",db:"mydb1"}
	] 
})

接着从客户端关闭 MongoDB 服务端,之后服务端会以安全认证方式进行启动

> use admin 
switched to db admin 
> db.shutdownServer() 
server should be down...

3. MongoDB 安全认证方式启动

mongod --dbpath=数据库路径 --port=端口 --auth
也可以在配置文件中 加入 auth=true

4. 分别以普通用户登录验证权限

普通用户现在仍然像以前一样进行登录,如下所示直接登录进入 mydb1 数据库中,登录是成功的,只
是登录后日志少了很多东西,而且执行 show dbs 命令,以及 show tables 等命令都是失败的,即使没
有被安全认证的数据库,用户同样操作不了,这都是因为权限不足,一句话:用户只能在自己权限范围
内的数据库中进行操作

mongo localhost:57017/mydb1 
> show dbs

如下所示,登录之后必须使用 db.auth(“账号”,“密码”) 方法进行安全认证,认证通过,才能进行权限范
围内的操作

> db.auth("zhangsan","123456")
 1
> show dbs 
mydb1 0.000GB 
> show tables 
c1
c2

5.以管理员登录验证权限

客户端管理员登录如下所示 管理员 root 登录,安全认证通过后,拥有对所有数据库的所有权限。

mongo localhost:57017 
> use admin 
switched to db admin 
> db.auth("root","root") 
1
> show dbs 
...

分片集群安全认证

1.开启安全认证之前 进入路由创建管理员和普通用户

完全参考上一步即可

use lagou_resume
db.createUser({
	 user:"chengdao",
	 pwd:"123456",
	 roles:[{role:"readWrite",db:"lagou_resume"}]
})

2.关闭所有的配置节点 分片节点 和 路由节点

安装psmisc 
yum install psmisc 
安装完之后可以使用killall 命令 快速关闭多个进程 
killall mongod

3.生成密钥文件 并修改权限

openssl rand -base64 756 > data/mongodb/testKeyFile.file 
chmod 600 data/mongodb/keyfile/testKeyFile.file

4.配置节点集群和分片节点集群开启安全认证和指定密钥文件

auth=true 
keyFile=data/mongodb/testKeyFile.file

5.在路由配置文件中 设置密钥文件

keyFile=data/mongodb/testKeyFile.file

6.启动所有的配置节点 分片节点 和 路由节点 使用路由进行权限验证

可以编写一个shell 脚本 批量启动

./bin/mongod -f config/config-17017.conf 
./bin/mongod -f config/config-17018.conf 
./bin/mongod -f config/config-17019.conf 
./bin/mongod -f shard/shard1/shard1-37017.conf 
./bin/mongod -f shard/shard1/shard1-37018.conf 
./bin/mongod -f shard/shard1/shard1-37019.conf 
./bin/mongod -f shard/shard2/shard2-47017.conf 
./bin/mongod -f shard/shard2/shard2-47018.conf 
./bin/mongod -f shard/shard2/shard2-47019.conf 
./bin/mongos -f route/route-27017.conf

7.Spring boot 连接安全认证的分片集群

spring.data.mongodb.username=账号 
spring.data.mongodb.password=密码 
#spring.data.mongodb.uri=mongodb://账号:密码@IP:端口/数据库名
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

添砖#Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值