MongoDB的安装和使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

1.下载地址
链接: https://www.mongodb.com/try/download/community.


提示:以下是本篇文章正文内容,下面案例可供参考

一、 MongoDB在Linux的安装和使用

1.安装

1.下载社区版 MongoDB 4.1.3 去官网下载对应的MongoDB 然后上传到Linux虚拟机
2.将压缩包解压即可

tar -zxvf MongoDB-linux-x86_64-4.1.3.tgz

3.启动

[root@node1 mongodb-linux-x86_64-4.1.3]# mkdir -p /data/db
[root@node1 mongodb-linux-x86_64-4.1.3]# ./bin/mongod

4.指定配置文件方式的启动

./bin/mongod -f mongo.conf 
配置文件样例: 
dbpath=/data/mongo/ 
port=27017 
bind_ip=0.0.0.0 #监听IP地址,默认全部可以访问
fork=true #后台运行
logpath = /data/mongo/MongoDB.log
logappend = true #是否追加日志
auth=false #是开启用户密码登陆

5.mongo shell
启动mongo shell

./bin/mongo 

指定主机和端口的方式启动

 ./bin/mongo --host=远程服务器主机IP(本机可不用指定) --port=端口

Ctrl+C就可以退出

6.Mongou GUI
在这里插入图片描述
在这里插入图片描述

二、 MongoDB命令

1.基本操作

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

2、MongoDB集合数据操作(CURD)

1.插入数据

db.lg_resume_prview.insert({name:"张3",birthday:new ISODate("2000-07-01"),expectSalary:15000,city:"beijing"})
  • 没有指定 _id 这个字段 系统会自动生成 当然我们也可以指定 _id
    ( _id 类型是ObjectId 类型是一个12字节 BSON 类型数据,有以下格式:前4个字节表示时间戳 ObjectId(“对象Id字符串”).getTimestamp() 来获取,接下来的3个字节是机器标识码,紧接的两个字节由进程id组成(PID)最后三个字节是随机数。)

2.数据查询

在这里插入图片描述
2.逻辑条件查询

  • 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()

pretty()用作格式化

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

db.lg_resume_prview.find({expectSalary:{$gt:15000}}).sort({expectSalary:1}).skip(1).limit(2)

3. 数据更新 调用update

在这里插入图片描述

db.lg_resume_prview.update({expectSalary:30000},
{$set: {expectSalary:28888}},
{multi:false,upsert:false})

4. 数据删除

在这里插入图片描述

3、MongoDB聚合操作

1.单目聚合操作

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

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

2.聚合管道

/**按照city进行分组**/
db.lg_resume_preview.aggregate([{$group: { _id: "$city",city_count:{$sum: 1}}}])
/**按照city进行分组,根据薪资计算平均值**/
db.lg_resume_preview.aggregate([{$group: { _id: "$city",avg_sal:{$avg: "$expectSalary"}}}])
/**按照city进行分组,将城市名放在一个集合**/
db.lg_resume_preview.aggregate([{$group: { _id: "$city",cityName:{$addToSet: "$city"}}}])
   

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}}} ])

3.MapReduce 编程模型

Pipeline查询速度快于MapReduce,但是MapReduce的强大之处在于能够在多台Server上并行执行复杂的聚合逻辑。MongoDB不允许Pipeline的单个聚合操作占用过多的系统内存,如果一个聚合操作消耗20%以上的内存,那么MongoDB直接停止操作,并向客户端输出错误消息。

MapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。

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

  • map:是JavaScript 函数,负责将每一个输入文档转换为零或多个文档,生成键值对序列,作为reduce 函数参数
  • reduce:是JavaScript 函数,对map操作的输出做合并的化简的操作(将key-value变成key-values,也就是把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",
        finalize:function(key,value){
            return value-999;
        }
    })

db.cityAvgSal.find();

三、 MongoDB索引

1、 索引类型

1)单键索引 (Single Field)
db.lg_resume_preview.createIndex(
                  {"name": 1}
     )
db.lg_resume_preview.getIndexes()

特殊的单键索引 过期索引 TTL ( Time To Live)
TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前TTL索引只能在单字段上建立,并且字段类型必须是日期类型。

db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})
2)复合索引(Compound Index)
db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )

注意:方向(升序降序【1,-1】)和顺序(左原则)都会影响索引

3)多键索引(Multikey indexes)

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

4)地理空间索引(Geospatial Index)

针对地理空间坐标数据创建索引。

  • 2dsphere索引,用于存储和查找球面上的点
  • 2d索引,用于存储和查找平面上的点
    在这里插入图片描述
    上述例子不能使用2d,2d是平面的点,而loc是球面的点
5)全文索引

MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的索引查询。注意:一个集合仅支持最多一个Text Index,中文分词不理想 推荐ES。
也就是:one word one dream 根据这几个单词都能找到该文

db.集合.createIndex({"字段(description)": "text"}) 
db.集合.find({"$text": {"$search": "coffee"}})
6) 哈希索引 Hashed Index

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

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

2、 索引和explain 分析

1)索引管理

在这里插入图片描述

1) explain 分析

使用js循环 插入100万条数据 不使用索引字段 查询查看执行计划 ,然后给某个字段建立索引,使用索引字段作为查询条件 再查看执行计划进行分析

/**向lg_resume中插入100万条数据**/

for(var i=0;i<1000000;i++){
    db.lg_resume.insert({id:1,name:"test"+i,salary:(Math.random()*20000).toFixed(2)});
}

db.lg_resume.count()

1、queryPlanner 默认参数
需要记住

参数含义
namespace要查询的集合(该值返回的是该query所查询的表)数据库.集合
winningPlan.stage被选中执行计划的stage(查询方式),常见的有:COLLSCAN/全表扫描:(应该知道就是CollectionScan,就是所谓的“集合扫描”, 和mysql中table scan/heap scan类似,这个就是所谓的性能最烂最无奈的由来)、IXSCAN/索引扫描:(是IndexScan,这就说明我们已经命中索引了)、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询等
winningPlan.isMultiKey是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。
winningPlan.direction此query的查询顺序,此处是forward,如果用了.sort({字段:-1})将显示backward。
winningPlan.indexBoundswinningplan所扫描的索引范围,如果没有制定范围就是[MaxKey,MinKey],这主要是直接定位到mongodb的chunck中去查找数据,加快数据读取。

.2、executionStats参数

参数参数
executionSuccess是否执行成功
nReturned返回的文档数
executionTimeMillis执行耗时
totalKeysExamined索引扫描次数
totalDocsExamined文档扫描次数
executionStages这个分类下描述执行的状态
stage扫描方式,具体可选值与上文的相同
nReturned查询结果数量
executionTimeMillisEstimate检索document获得数据的时间
works工作单元数,一个查询会分解成小的工作单元
advanced优先返回的结果数
docsExamined文档检查数目,与totalDocsExamined一致。检查了总共的document 个数,而从返回上面的nReturned数量

3、executionStats返回逐层分析

  1. 第一层,executionTimeMillis最为直观explain返回值是executionTimeMillis值,指的是这条语句的执行时间,这个值当然是希望越少越好。
    其中有3个executionTimeMillis,分别是:
    executionStats.executionTimeMillis 该query的整体查询时间。
    executionStats.executionStages.executionTimeMillisEstimate 该查询检索document获得数据的时间。
    executionStats.executionStages.inputStage.executionTimeMillisEstimate 该查询扫描文档 index所用时间。
  2. 第二层,index与document扫描数与查询返回条目数 这个主要讨论3个返回项 nReturned、totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描条目。 这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。 对于一个查询,我们最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined
  3. 第三层,stage状态分析 那么又是什么影响到了totalKeysExamined和totalDocsExamined?是stage的类型。
    类型列举如下:
    COLLSCAN:全表扫描
    IXSCAN:索引扫描
    FETCH:根据索引去检索指定document
    SHARD_MERGE:将各个分片返回数据进行merge
    SORT:表明在内存中进行了排序
    LIMIT:使用limit限制返回数
    SKIP:使用skip进行跳过
    IDHACK:针对_id进行查询
    SHARDING_FILTER:通过mongos对分片数据进行查询
    COUNT:利用db.coll.explain().count()之类进行count运算
    TEXT:使用全文索引进行查询时候的stage返回
    PROJECTION:限定返回字段时候stage的返回
    对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引):
    Fetch+IDHACK
    Fetch+IXSCAN
    Limit+(Fetch+IXSCAN)
    PROJECTION+IXSCAN
    SHARDING_FITER+IXSCAN
    不希望看到包含如下的stage
    COLLSCAN(全表扫描)
    SORT(使用sort但是无index)
    COUNT 不使用index进行count)

4、慢查询分析

  1. 开启内置的查询分析器,记录读写操作效率
    db.setProfilingLevel(n,m),n的取值可选0,1,2
    0表示不记录
    1表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询时间的阈值
    2表示记录所有的读写操作
  2. 查询监控结果
    db.system.profile.find().sort({millis:-1}).limit(3)
  3. 分析慢速查询
    应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等
  4. 解读explain结果 确定是否缺少索引

3、MongoDB 索引底层实现原理分析

MongoDB使用B-树,所有节点都有Data域,只要找到指定索引就可以进行访问,
单次查询从结构上来看要快于MySql。
在这里插入图片描述
B-树的特点:
(1) 多路 非二叉树
(2) 每个节点 既保存数据 又保存索引
(3) 搜索时 相当于二分查找

Mysql B+树是B-树的变种
在这里插入图片描述
B+ 树的特点:
(1) 多路非二叉
(2) 只有叶子节点保存数据
(3) 搜索时 也相当于二分查找
(4) 增加了 相邻节点指针

MongoDB和MySql的差别
(1)B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和data 在一起 适合随机读写 ,而区间查找效率很差。
(2)B+树更适合外部存储,也就是磁盘存储,使用B-结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围更大更精确。
(3)注意这个区别相当重要,是基于(1)(2)的,B-树每个节点即保存数据又保存索引 树的深度小,所以磁盘IO的次数很少,B+树只有叶子节点保存,较B树而言深度大磁盘IO多,但是区间访问比较好。

四、 MongoDB 应用实战

1. MongoDB的行业具体应用场景

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

2. Java 访问MongoDB

1.dependency

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

2.java

MongoClient mongoClient = new MongoClient("192.168.142.128:27017");
        MongoDatabase mongoDatabase = mongoClient.getDatabase("lg_resume");
        MongoCollection<Document> collection = mongoDatabase.getCollection("lg_resume_preview");
        Document document = new Document();
        document.append("expectSalary", -1);
        //查找迭代的对象,根据expectSalary降序排序
        // FindIterable<Document> documents = collection.find(Document.parse("{expectSalary:{$gt:21000}}")).sort(document);
        FindIterable<Document> documents = collection.find(Filters.gt("expectSalary", 20000)).sort(document);
        for (Document document1 : documents) {
            System.out.println(document1);
        }
        mongoClient.close();

3. Spring 访问MongoDB

1.applicationContext.xml

<?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.142.128:27017/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.qch"></context:component-scan>
</beans>

2.Dao

public interface ResumeDao {
    void insertResume(Resume resume);
     List<Resume> findByNameAndSa(String name,double expectSalary);
}

@Repository("resumeDao")
public class ResumeDaoImpl implements ResumeDao {
    @Autowired
    private MongoTemplate mongoTemplate;
    public void insertResume(Resume resume) {
        mongoTemplate.insert(resume,"lg_resume_preview");
    }

public List<Resume> findByNameAndSa(String name, double expectSalary) {
        Query query=new Query();
        query.addCriteria(Criteria.where("name").is(name).andOperator(Criteria.where("expectSalary").gt(expectSalary)));
        List<Resume> list = mongoTemplate.find(query,Resume.class,dbtable);
        return list;
    }
}

3.测试类

public static void main(String[] args) throws ParseException {
        //构建spring 容器
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        ResumeDao resumeDao=applicationContext.getBean("resumeDao",ResumeDao.class);
        Resume resume=new Resume();
        resume.setName("qq");
        String daf="yyyy-MM-dd hh:mm:ss";
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat(daf);
        Date parse = simpleDateFormat.parse("2021-09-30 12:34:11");
        resume.setBirthday(parse);
        resume.setCity("南京");
        resume.setExpectSalary(18000);
        resumeDao.insertResume(resume);
    }

4. SpringBoot 访问MongoDB

1.application.properties

spring.data.mongodb.host=192.168.142.128
spring.data.mongodb.port=27017
spring.data.mongodb.database=lg_resume

2.repository

@Document("lg_resume_preview")
public class Resume
public interface ResumeRepository extends MongoRepository<Resume,String>{
    List<Resume> findByNameEquals(String name);
}

五、 MongoDB 架构

5.1 MongoDB的数据模型

  • 内嵌( 应用场景:数据对象之间有包含关系,数据对象之间有一对多或者一对一的关系)
    内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。MongoDB的文档结构允许一个字段或者一个数组内的值作为一个嵌套的文档。

  • 引用(应用场景:当内嵌数据会导致很多数据的重复,表达比较复杂的多对多关系)
    引用方式通过存储数据引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引用来访问相关数据。

5.2 MongoDB存储引擎

存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上。MongoDB支持的存储引擎有 MMAPv1 ,WiredTiger和InMemory(适合数据不持久化,用于缓存)

1. WiredTiger存储引擎优势

在这里插入图片描述

2. WiredTiger引擎包含的文件和作用

在这里插入图片描述

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

WiredTiger的写操作会默认写入 Cache ,并持久化到 WAL (Write Ahead Log),每60s或Log文件达到2G做一次 checkpoint (当然我们也可以通过在写入时传入 j: true 的参数强制 journal 文件的同步 ,writeConcern { w: , j: , wtimeout: }) 产生快照文件。WiredTiger初始化时,恢复至最新的快照状态,然后再根据WAL恢复数据,保证数据的完整性。

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 集群高可用

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

主从结构没有自动故障转移功能,需要指定master和slave端,不推荐在生产中使用。

6.2 复制集replica sets

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

  • 高可用:能自动切换主从
  • 灾难恢复:可从从节点恢复,用于备份
  • 功能隔离:我们可以在备节点上执行读操作,减少主节点的压力 比如:用于分析、报表,数据挖掘,系统任务等。

6.3 复制集集群架构原理

oplog 具有幂等性,即无论执行几次其结果一致,这个比 mysql 的二进制日志更好用。
oplog的组成结构
在这里插入图片描述
复制集数据同步分为初始化同步和keep复制同步。初始化同步指全量从主节点同步数据,如果Primary节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后,节点之间的实时同步一般是增量同步。

初始化同步有以下两种情况会触发:
(1) Secondary第一次加入。
(2) Secondary落后的数据量超过了oplog的大小,这样也会被全量复制。

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

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

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

6.4 复制集集群搭建

在这里插入图片描述
1.文件准备

[root@node1 mongodb-linux-x86_64-4.1.3]# mkdir /data/mongo/data/server1 -p
[root@node1 mongodb-linux-x86_64-4.1.3]# mkdir /data/mongo/data/server2 -p
[root@node1 mongodb-linux-x86_64-4.1.3]# mkdir /data/mongo/data/server3 -p
[root@node1 mongodb-linux-x86_64-4.1.3]# mkdir /data/mongo/logs -p
[root@node1 mongodb-linux-x86_64-4.1.3]# cp mongo_37017.conf mongo_37018.conf 

2.主节点配置 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

从节点同上

3.进入其中一台客户端进行配置

[root@node1 mongodb-linux-x86_64-4.1.3]# ./bin/mongo --port 37017

var cfg ={"_id":"lagouCluster", "protocolVersion" : 1, "members":[ {"_id":1,"host":"192.168.142.128:37017","priority":10}, {"_id":2,"host":"192.168.142.128:37018"} ] }

rs.initiate(cfg)
rs.status()

4.节点的动态增删

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

5.从节点读数据设置

lagouCluster:SECONDARY> rs.slaveOk()

6.仲裁节点
必须再主节点上设置

// 重新装载配置,并重新生成集群节点。 
rs.reconfig(cfg)

或者以动态增加节点的方式

注入节点 执行 rs.addArb("IP:端口");
rs.addArb("192.168.211.133:37020")

6.5分片集群

1.分片的工作原则
在这里插入图片描述分片集群由以下3个服务组成:

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

2.分片策略

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

  • hash分片(Hash based sharding)

在这里插入图片描述
相邻的值不一定再一个块
缺点:查询费劲
优化:
组合片键 A + B(散列思想,不能是直接hash)
数据库中没有比较合适的片键供选择,或者是打算使用的片键基数太小(即变化少如星期只有7天可变化),可以选另一个字段使用组合片键,甚至可以添加冗余字段来组合。一般是粗粒度+细粒度进行组合。【A控制shard,B控制chunk】

6.6分片集群搭建

在这里插入图片描述

1.配置 并启动config 节点集群(3个)

# 数据库文件位置
dbpath=config/config1
#日志文件位置
logpath=config/logs/config1.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork = true 
bind_ip=0.0.0.0
port = 17017
# 表示是一个配置服务器
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.142.128:17017"}, {"_id":2,"host":"192.168.142.128:17018"}, {"_id":3,"host":"192.168.142.128:17019"}] };
rs.initiate(cfg)

rs.reconfig(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

启动每个mongod 然后进入其中一个进行集群配置

 var cfg ={"_id":"shard1", "protocolVersion" : 1, "members":[ {"_id":1,"host":"192.168.142.128:37017"}, {"_id":2,"host":"192.168.142.128:37018"}, {"_id":3,"host":"192.168.142.128:37019"} ,
 {"_id":4,"host":"192.168.211.133:37020","arbiterOnly":true}]};
 rs.initiate(cfg) 
 rs.status()
 rs.addArb("192.168.211.133:37020")
 
 var cfg ={"_id":"shard2", "protocolVersion" : 1, "members":[ {"_id":1,"host":"192.168.142.128:47017"}, {"_id":2,"host":"192.168.142.128:47018"}, {"_id":3,"host":"192.168.142.128:47019"} ]};

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

3.配置和启动 路由节点
/route/route-27017.conf

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

[root@node1 mongo_shard_cluster]# ./bin/mongos -f route/route-27017.conf 

mongos(路由)中添加分片节点
进入路由mongos

mongos> sh.status()
sh.addShard("shard1/192.168.142.128:37017,192.168.142.128:37018,192.168.142.128:37019"); sh.addShard("shard2/192.168.142.128:47017,192.168.142.128:47018,192.168.142.128:47019");

开启数据库和集合分片(指定片键)
继续使用mongos完成分片开启和分片大小设置

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

sh.shardCollection(“lagou_resume.lagou_resume_datas”,{“name”:“hashed”})

4.向集合中插入数据测试

use lagou_resume; 
for(var i=1;i<= 1000;i++){ db.lagou_resume_datas.insert({"name":"test"+i, salary:(Math.random()*20000).toFixed(2)}); }

六、 MongoDB 安全认证

7.1

  • 7.1.1
shard2:PRIMARY> db.createUser({user:"myroot",pwd:"123",roles:[{role:"root",db:"laagou_resume"}]});
2021-04-22T12:42:05.726+0800 E QUERY    [js] Error: couldn't add user: No role named root@laagou_resume :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1408:15
@(shell):1:1
shard2:PRIMARY> db.createUser({user:"myroot",pwd:"123",roles:[{role:"root",db:"admin"}]})
Successfully added user: {
	"user" : "myroot",
	"roles" : [
		{
			"role" : "root",
			"db" : "admin"
		}
	]
}

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

  • 7.1.2 修改密码
    db.changeUserPassword( ‘root’ , ‘rootNew’ );

  • 7.1.3 用户添加角色
    db.grantRolesToUser( ‘用户名’ , [{ role: ‘角色名’ , db: ‘数据库名’}])

  • 7.1.4 以auth 方向启动mongod
    ./bin/mongod -f conf/mongo.conf --auth
    (也可以在mongo.conf 中添加auth=true 参数)

  • 7.1.5 验证用户
    db.auth(“账号”,“密码”)

  • 7.1…删除用户
    db.dropUser(“用户名”)

7.2 单机安全认证实现流程

  1. 创建管理员
    MongoDB 服务端开启安全检查之前,至少需要有一个管理员账号,admin 数据库中的用户都被视为管理员如果 admin 库没有任何用户的话,即使在其他数据库中创建了用户,启用身份验证,默认的连接方式依然会有超级权限,即仍然可以不验证账号密码照样能进行 CRUD,安全认证相当于无效。
>use admin 
switched to db admin
> db.createUser(  {user:"root",pwd:"123456", roles:[{role:"root",db:"admin"}] })
  1. 创建普通用户
    如下所示 lg_resume是自己新建的数据库,没安全认证之前可以随意 CRUD,其余的都是 mongoDB4.0.2 自带的数据库
    为 admin 库创建管理员之后,现在来为 普通数据库创建普通用户,以 lg_resume为例,方式与创建管理员一致,切换到指定数据库进行创建即可。

如下所示,为 lg_resume数据库创建了两个用户,zhangsan 拥有读写权限,lisi 拥有只读权限,密码都是 123456.

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

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

  1. MongoDB 安全认证方式启动
    mongod --dbpath=数据库路径 --port=端口 --auth
    也可以在配置文件中 加入 auth=true
    在这里插入图片描述
> use admin
switched to db admin
> db.auth("root","123456")

7.3 分片集群安全认证

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

mongos> use admin
switched to db admin
mongos> db.createUser({user:"root",pwd:"123456", roles:[{role:"root",db:"admin"}]})
Successfully added user: {
	"user" : "root",
	"roles" : [
		{
			"role" : "root",
			"db" : "admin"
		}
	]
}
mongos> use lg_resume
switched to db lg_resume
mongos> db.createUser({user:"lagou_gx",pwd:"abc321",roles:[{role:"readWrite",db:"lg_resume"}]})
Successfully added user: {
	"user" : "lagou_gx",
	"roles" : [
		{
			"role" : "readWrite",
			"db" : "lg_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

加执行权限

[root@node1 mongo_shard_cluster]# vi startup.sh
[root@node1 mongo_shard_cluster]# chmod +x startup.sh

执行命令

[root@node1 mongo_shard_cluster]# ./startup.sh

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

spring.data.mongodb.host=192.168.142.128
spring.data.mongodb.port=27017
spring.data.mongodb.database=lagou_resume
spring.data.mongodb.username=zhangsan
spring.data.mongodb.password=123456
   #spring.data.mongodb.uri=mongodb://账号:密码@IP:端口/数据库名

root超级管理员权限不可用


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值