MongoDB深入学习 - 二

一、MongoDB架构

1.1.MongoDB逻辑结构

MongoDB逻辑结构

最新版本的 MongoDB 中使用了 WiredTiger 作为默认的存储引擎,WiredTiger 提供了不同粒度的并发控制和压缩机制,能够为不同种类的应用提供了最好的性能和存储率。

1.2.MongoDB的数据模型

1.2.1.描述数据模型

内嵌

内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。MongoDB的文档结构允许一个字段或者一个数组内的值作为一个嵌套的文档。

引用

引用方式通过存储数据引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引用来访问相关数据。

1.2.2.如何选择数据模型

选择内嵌

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

选择引用

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

1.3.1.存储引擎概述

存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上。MongoDB支持的存储引擎有MMAPv1 ,WiredTiger和InMemory。

InMemory存储引擎用于将数据只存储在内存中,只将少量的元数据(meta-data)和诊断日志(Diagnostic)存储到硬盘文件中,由于不需要Disk的IO操作,就能获取所需的数据,InMemory存储引擎大幅度降低了数据查询的延迟(Latency)

从3.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

1.3.2.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 日志。

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

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

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

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

master-slave架构中master节点负责数据的读写,slave没有写入权限只负责读取数据。

在主从结构中,主节点的操作记录成为oplog(operation log)。oplog存储在系统数据库local的oplog.$main集合中,这个集合的每个文档都代表主节点上执行的一个操作。从服务器会定期从主服务器中获取oplog记录,然后在本机上执行!对于存储oplog的集合,MongoDB采用的是固定集合,也就是说随着操作过多,新的操作会覆盖旧的操作!

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

4.0后不再支持主从复制

2.2.复制集replica sets

2.2.1.什么是复制集

复制集是由一组拥有相同数据集的mongod实例做组成的集群。

复制集是一个集群,它是2台及2台以上的服务器组成,以及复制集成员包括Primary主节点,secondary从节点和投票节点。

复制集提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,保证数据的安全性。

2.2.2.为什么要使用复制集

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

2.2.3.复制集集群架构原理

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

{
"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]秒内的随机时间,之后再次尝试选举。

2.2.4.复制集搭建

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

从节点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

从节点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

初始化节点配置

启动三个节点 然后进入任意一个节点 运行如下命令:

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

节点的动态增删

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

2.2.5.复制集成员的配置参数

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

2.2.6.有仲裁节点复制集搭建

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

3.3.分片集群 Shard Cluster

3.3.1.什么是分片

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

3.3.2.为什么要分片

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

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

3.3.3.分片的工作原理

分片集群由以下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分割分片数据到区块,每一个区块包含基于分片主键的左闭右开的区间范围。

分片策略

  • 范围分片:范围分片是基于分片主键的值切分数据,每一个区块将会分配到一个范围。

    范围分片适合满足在一定范围内的查找,如果shard key有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个chunk,无法扩展写的能力。

  • hash分片:Hash分片是计算一个分片主键的hash值,每一个区块将分配一个范围的hash值。

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

  • 组合片键 A + B(散列思想 不能是直接hash)

    数据库中没有比较合适的片键供选择,或者是打算使用的片键基数太小,可以选另一个字段使用组合片键,甚至可以添加冗余字段来组合。

合理的选择shard key

数据的查询和写入,最好的效果就是数据查询时能命中更少的分片,数据写入时能够随机的写入每个分片,关键在于如何权衡性能和负载。

3.3.4.分片集群的搭建过程

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/config2.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安全认证

3.1.安全认证概述

MongoDB 默认是没有账号的,可以直接连接,无须身份验证。实际项目中肯定是要权限验证的,,否则后果不堪设想。

3.2.用户相关操作

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

use admin;
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 等,即为哪个数据库实例 设置用户

3.2.2.修改密码

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

3.2.3.用户添加角色

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

3.2.4.以auth方式启动mongod

./bin/mongod -f conf/mongo.conf --auth

(也可以在mongo.conf 中添加auth=true 参数)

3.2.5.验证用户

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

3.2.6.删除用户

db.dropUser("用户名")

3.3.角色

3.3.1.数据库内置的角色

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角色的合体

3.3.2.各个类型用户对应的角色

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

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

3.4.1.创建管理员

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

>use admin
switched to db admin

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

3.4.2.创建普通用户

> 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.createUser({
    ... user:"zhangsan",
    ... pwd:"123456",
    ... roles:[{role:"readWrite",db:"mydb1"}]
    ... })
    > db.createUser({
    ... user:"lisi",
    ... pwd:"123456",
    ... roles:[{role:"read",db:"mydb1"}]
    ... })
    

    接着重启Mongo服务,服务端会以安全认证方式进行启动。

3.4.3.MongoDB 安全认证方式启动

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

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

普通用户现在仍然像以前一样进行登录,只是登录后日志少了很多东西,而且执行 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

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

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

mongo localhost:57017
> use admin
switched to db admin
> db.auth("root","root")
1
> show dbs
...
3.5.分片集群安全认证

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

参考上面单机安全认证

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

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

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

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

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

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

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

keyFile=data/mongodb/testKeyFile.file

3.5.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

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

spring.data.mongodb.username=账号
spring.data.mongodb.password=密码
#spring.data.mongodb.uri=mongodb://账号:密码@IP:端口/数据库名

__EOF__

作  者Jerry
出  处https://www.cnblogs.com/jerry0612/p/14373511.html
关于博主:编程路上的小学生,热爱技术,喜欢专研。评论和私信会在第一时间回复。或者直接私信我。
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

posted @   郭靖宇  阅读(244)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
0
0
关注
跳至底部
点击右上角即可分享
微信分享提示