四、角色安全控制
4.1.角色分类
4.1.1.数据库一般角色( Databaser User Roles )
每个数据库都包含的一般角色;
read
提供读取所有非系统集合和部分系统集合的数据的能力,系统集合包括:
system.indexes,system.js 和 system.namespaces 集合。
readWrite
提供 read 角色的所有权限以及修改所有非系统集合和 system.js 集合上的数据的能力。
4.1.2.数据库管理角色(Database Administration Roles)
每个数据库都包含的数据库管理角色;
dbAdmin
提供执行管理任务的能力,如与模式相关的任务,索引,收集统计信息。 此角色不授予用户和角色管理的权限。
userAdmin
提供在当前数据库上创建和修改角色和用户的能力。
dbOwner
提供对数据库执行任何管理操作的能力。 此角色结合了 readWrite,dbAdmin和 userAdmin 角色授予的权限。
4.1.3.集群管理角色(Cluster Administration Roles )
在 admin 数据库创建,用于管理整个数据库集群系统而不是特定数据库的角色。
这些角色包括但不限于副本集和分片群集管理功能。
clusterManager
在集群上提供管理和监视操作。 具有此角色的用户可以分别访问在分片和复制中使用的 config 和 local 数据库。
clusterMonitor
为监控工具(如 MongoDB Cloud Manager 和 Ops Manager 监控代理)提供只读访问权限。
hostManager
提供监视和管理服务器的能力。
clusterAdmin
提供权限最高的群集管理访问。 此角色结合了由 clusterManager,clusterMonitor 和 hostManager 角色授予的权限。 此外,该角色还提供了
dropDatabase 操作。
4.1.4.备份和恢复角色(Backup and Restoration Roles )
在 admin 数据库创建,用于专门的备份和恢复的角色
backup
提供备份数据所需的权限。 此角色提供足够的权限来使用 MongoDB Cloud Manager 备份代理,Ops Manager 备份代理或使用 mongodump。
restore
提供使用 mongorestore 恢复数据所需的权限
4.1.5.全数据库角色(All-Database Roles )
在 admin 数据库创建,适用于除 mongod 实例中的 local 和 config 之外的所有数据库:
readAnyDatabase
提供与读取相同的只读权限,除了适用于群集中除本地和配置数据库以外的所有权限。 该角色还提供了整个集群上的 listDatabases 操作。
readWriteAnyDatabase
提供与 readWrite 相同的读取和写入权限,除了它适用于群集中除本地和配置数据库以外的所有数据。 该角色还提供了整个集群上的 listDatabases 操作。
userAdminAnyDatabase
提供与 userAdmin 相同的用户管理操作访问权限,除了适用于群集中除本地数据库和配置数据库外的所有数据。
dbAdminAnyDatabase
提供与 dbAdmin 相同的数据库管理操作访问权限,除了它适用于除集群中的本地数据库和配置数据库以外的所有数据库管理操作。 该角色还提供了整个集群上的 listDatabases 操作。
4.1.6.超级角色(r Superuser Roles )
所有资源的完整权限
root
提供对 readWriteAnyDatabase,dbAdminAnyDatabase,userAdminAnyDatabase,clusterAdmin,还原和备份相结合的操作和所有资源的访问。
4.2.mogno 服务开启安全认证方式
1.服务器启动加上 auth 参数,开启安全验证 ./mongod -f mongodb.conf --auth
2.数据库增加安全模式后,初始化一个“userAdminAnyDatabase“,通过客户端连接,使用admin 数据库, 执行脚本db.createUser({'user':'boss', 'pwd':'boss','roles':[{'role':'userAdminAnyDatabase', 'db':'admin'}]})
3.使用刚创建成功的用户登录:db.auth("boss","boss");
4.切换到 lison 数据库,创建读写权限用户
use lison
db.createUser({‘user’:‘lison’,‘pwd’:‘lison’,‘roles’:[{‘role’:‘readWrite’,‘db’:‘lison’}]})
5.使用读写权限用户 lison 登录,db.auth(“lison”,“lison”),登录后测试;
4.3.代码安全模式连接方式
Spring
<mongo:mongo-client host="192.168.1.142" port="27022" credentials="lison:lison@lison"> </mongo:mongo-client>
Java
public void init() { MongoCredential createCredential = MongoCredential.createCredential("lison", "lison","lison".toCharArray()); MongoClientOptions mco = MongoClientOptions.builder() .writeConcern(WriteConcern.JOURNALED) .connectionsPerHost(100) .readPreference(ReadPreference.secondary()) .threadsAllowedToBlockForConnectionMultiplier(5) .maxWaitTime(120000).connectTimeout(10000).build(); List<ServerAddress> asList = Arrays.asList(new ServerAddress("116.62.222.124",27022)); this.client = new MongoClient(asList, createCredential,mco); db = client.getDatabase("lison"); collection = db.getCollection("users"); }
五、MongoDB高级知识
5.1.存储引擎
5.1.1.MMAPV1
在 3.2 版本之前 MMAPV1 是默认的存储引擎
5.1.2.wiredTiger
3.4 以上版本默认的存储引擎是 wiredTiger,相对于 MMAPV1 其有如下优势:
读写操作性能更好,WiredTiger 能更好的发挥多核系统的处理能力;
MMAPV1 引 擎 使 用 表 级 锁 ,当 某 个 单 表 上 有 并 发 的 操 作 ,吞 吐 将 受 到 限 制 。
WiredTiger 使用文档级锁,由此带来并发及吞吐的提高,相比 MMAPV1 存储索引时 WiredTiger 使用前缀压缩,更节省对内存空间的损耗;
提供压缩算法,可以大大降低对硬盘资源的消耗,节省约 60%以上的硬盘资源;
5.1.2.1.写入数据原理
5.1.2.2.Journaling
3.4 以上版本默认的存储引擎是 wiredTiger,相对于 MMAPV1 其有如下优势:
读写操作性能更好,WiredTiger 能更好的发挥多核系统的处理能力;
MMAPV1 引 擎 使 用 表 级 锁 ,当 某 个 单 表 上 有 并 发 的 操 作 ,吞 吐 将 受 到 限 制 。
WiredTiger 使用文档级锁,由此带来并发及吞吐的提高,相比 MMAPV1 存储索引时 WiredTiger 使用前缀压缩,更节省对内存空间的损耗;
提供压缩算法,可以大大降低对硬盘资源的消耗,节省约 60%以上的硬盘资源;
5.1.2.3.写策略配置
写配置说明
Java 代码实现写策略
Q1:写策略配置相关的类是?
答:com.mongodb.WriteConcern,其中有如下几个常用写策略配置:
UNACKNOWLEDGED:不等待服务器返回或确认,仅可以抛出网络异常;
ACKNOWLEDGED:默认配置,等待服务器返回结果;
JOURNALED:等待服务器完成 journal 持久化之后返回;
W1 :等待集群中一台服务器返回结果;
W2 :等待集群中两台服务器返回结果;
W3 :等待集群中三台服务器返回结果;
MAJORITY:等待集群中多数服务器返回结果;
Q2:Java 代码中如何加入写策略
答:Java 客户端可以按两种方式来设置写策略:
在 MongoClient初始化过程中使用 MongoClientOptions.writeConcern(writeConcern)来进行配置;
在写操作过程中,也可动态的指定写策略,mongodb 可以在三个层次来进行写策略的配置,既 MongoClient、 MongoDatabase 、MongoCollection 这三个类都可以通过 WriteConcern 方法来设置写策略;
Spring 中如何配置写策略?
<mongo:mongo-client id="mongo" host="127.0.0.1" port="27017" > <mongo:client-options write-concern="NONE"/> </mongo:mongo-client>
配置文件配置引擎
storage: journal: enabled: true dbPath: /data/zhou/mongo1/ ##是否一个库一个文件夹 directoryPerDB: true ##数据引擎 engine: wiredTiger ##WT 引擎配置 wiredTiger: engineConfig: ##WT 最大使用 cache(根据服务器实际情况调节) cacheSizeGB: 1 ##是否将索引也按数据库名单独存储 directoryForIndexes: true journalCompressor:none (默认 snappy) ##表压缩配置,性能: none>snappy>zlib,压缩比:zlib>snappy>none collectionConfig: blockCompressor: zlib (默认 snappy,还可选 none、zlib) ##索引配置 indexConfig: prefixCompression: true
5.2.索引
5.2.1.索引管理
新增db.collection.createIndex(keys, options)
语法中 Key 值为要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为-1,也可以指定为 hashed(哈希索引)。
语法中 options 为索引的属性,属性说明见下表
单键唯一索引:db.users.createIndex({username :1},{unique:true});
单键唯一稀疏索引:db.users. createIndex({username :1},{unique:true,sparse:true});
复合唯一稀疏索引:db.users. createIndex({username:1,age:-1},{unique:true,sparse:true});
创建哈希索引并后台运行:db.users. createIndex({username :‘hashed’},{background:true});
删除
根据索引名字删除某一个指定索引:db.users.dropIndex(“username_1”);
删除某集合上所有索引:db.users.dropIndexs();
重建某集合上所有索引:db.users.reIndex();
查询集合上所有索引:db.users.getIndexes();
5.2.2.索引分类
单键索引
在某一个特定的属性上建立索引,例如:db.users. createIndex({age:-1});
mongoDB 在 ID 上建立了唯一的单键索引,所以经常会使用 id 来进行查询;
在索引字段上进行精确匹配、排序以及范围查找都会使用此索引;
复合索引
在多个特定的属性上建立索引,例如:db.users.createIndex({username:1,age:-1,country:1});
复合索引键的排序顺序,可以确定该索引是否可以支持排序操作;
在索引字段上进行精确匹配、排序以及范围查找都会使用此索引,但与索引的顺
序有关;
为了内存性能考虑,应删除存在与第一个键相同的单键索引
多键索引
在数组的属性上建立索引,例如:db.users. createIndex({favorites.city:1});针对这个数组的任意值的查询都会定位到这个文档,既多个索引入口或者键值引用同一个文档
哈希索引
不同于传统的 B-树索引,哈希索引使用 hash 函数来创建索引。
例如:db.users. createIndex({username : 'hashed'});
在索引字段上进行精确匹配,但不支持范围查询,不支持多键 hash;
Hash 索引上的入口是均匀分布的,在分片集合中非常有用;
5.2.3.查询优化
1.开启慢查询
开启内置的查询分析器,记录读写操作效率:
db.setProfilingLevel(n,{m}),n 的取值可选 0,1,2;
0 是默认值表示不记录;
1 表示记录慢速操作,如果值为 1,m 必须赋值单位为 ms,用于定义慢速查询时间的阈值;
2 表示记录所有的读写操作;
例如:db.setProfilingLevel(1,300)
2.查询监控结果
监控结果保存在一个特殊的盖子集合 system.profile 里,这个集合分配了 128kb
的空间,要确保监控分析数据不会消耗太多的系统性资源;盖子集合维护了自然
的插入顺序,可以使用 $natural 操作符进行排序,如:db.system.profile.find().sort({' $natural':-1}).limit(5)
盖子集合 Tips:
大小或者数量固定;
不能做 update 和 delete 操作;
容量满了以后,按照时间顺序,新文档会覆盖旧文档
3.分析慢速查询
找出慢速查询的原因比较棘手,原因可能有多个:应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等;接下来对于缺少索引的情况进行分析:
使用 explain 分析慢速查询
例如:db.orders.find({'price':{'$lt':2000}}).explain('executionStats')
explain 的入参可选值为:
"queryPlanner" 是默认值,表示仅仅展示执行计划信息;
"executionStats" 表示展示执行计划信息同时展示被选中的执行计划的执行情
况信息;
"allPlansExecution" 表示展示执行计划信息,并展示被选中的执行计划的执行情
况信息,还展示备选的执行计划的执行情况信息
explain 结果
queryPlanner(执行计划描述)
winningPlan(被选中的执行计划)
stage(可选项:COLLSCAN 没有走索引;IXSCAN 使用了索引)
rejectedPlans(候选的执行计划)
executionStats(执行情况描述)
nReturned (返回的文档个数)
executionTimeMillis(执行时间 ms)
totalKeysExamined (检查的索引键值个数)
totalDocsExamined (检查的文档个数)
优化目标 Tips:
根据需求建立索引
每个查询都要使用索引以提高查询效率, winningPlan. stage 必须为 IXSCAN;
追求 totalDocsExamined = nReturned
5.2.4.索引的注意事项
1.索引很有用,但是它也是有成本的——它占内存,让写入变慢;
2.mongoDB 通常在一次查询里使用一个索引,所以多个字段的查询或者排序需要复合索引才能更加高效;
3.复合索引的顺序非常重要
4.在生成环境构建索引往往开销很大,时间也不可以接受,在数据量庞大之前尽量进行查询优化和构建索引;
5.避免昂贵的查询,使用查询分析器记录那些开销很大的查询便于问题排查;
6.通过减少扫描文档数量来优化查询,使用 explain 对开销大的查询进行分析并优化;
7.索引是用来查询小范围数据的,不适合使用索引的情况:
1.每次查询都需要返回大部分数据的文档,避免使用索引
2.写比读多
六、高可用
6.1.部署模型
6.2.可复制集
6.2.1.概念
可复制集是跨多个 MongDB 服务器(节点)分布和维护数据的方法。mongoDB可以把数据从一个节点复制到其他节点并在修改时进行同步,集群中的节点配置为自动同步数据;旧方法叫做主从复制,mongoDB 3.0 以后推荐使用可复制集;
6.2.2.优点
1.避免数据丢失,保障数据安全,提高系统安全性;(最少 3 节点,最大 50 节点)
2.自动化灾备机制,主节点宕机后通过选举产生新主机;提高系统健壮性;(7 个选举节点上限)
3.读写分离,负载均衡,提高系统性能;
4.生产环境推荐的部署模式
6.2.3.原理
oplog(操作日志) 保存操作记录、时间戳 。是盖子集合,大小是可以调整的,默认是所在硬盘 5%;
数据同步 从节点与主节点保持长轮询;1.从节点查询本机 oplog 最新时间戳;2.查询主节点 oplog 晚于此时间戳的所有文档;3.加载这些文档,并根据 log 执行写操作
阻塞复制 与 writeconcern 相关,不需要同步到从节点的策略(如:acknowledged Unacknowledged 、w1),数据同步都是异步的,其他情况都是同步
心跳机制 成员之间会每 2s 进行一次心跳检测(ping 操作),发现故障后进行选举和故障转移
选举制度 主节点故障后,其余节点根据优先级和 bully 算法选举出新的主节点,在选出主节点之前,集群服务是只读的
6.2.4.搭建
1.安装好 3 个以上节点的 mongoDB
2.配置 mongodb.conf,增加跟复制相关的配置
replication: replSetName: configRS //集群名称 oplogSizeMB: 50 //oplog 集合大小
3.在 primary 节点切换到 admin 库上运行可复制集的初始化命令,初始化可复制集
//复制集初始化,在主节点上执行,ip 禁止使用 localhost rs.initiate({ _id: "configRS", version: 1, members: [{ _id: 0, host : "192.168.0.128:27017" }]}); rs.add("192.168.0.128:27018");//有几个节点就执行几次方法 rs.add("192.168.0.128:27019");//有几个节点就执行几次方法
4.在每个节点运行 rs.status()或 isMaster()
命令查看复制集状态.只此时能在主节点查询数据,但如果想在副节点查询到数据需运行 rs.slaveOk();
5.测试数据复制集效果
6.测试故障失效转移效果
代码连接复制集
java 原生驱动
List<ServerAddress> asList = Arrays.asList(new ServerAddress("116.62.222.124", 27018), new ServerAddress("116.62.222.124", 27017),new ServerAddress("116.62.222.124", 27019)); client = new MongoClient(asList);
Spring 配置
<mongo:mongo-client replica-set="116.62.222.124:27017,116.62.222.124:27018,116.62.222.124:27019"> </mongo:mongo-client>
6.2.5.tips
配置 Tips:
关注 Write Concern 参数的设置,默认值 1 可以满足大多数场景的需求。W 值大于 1 可以提高数据的可靠持久化,但会降低写性能。
在 options 里添加 readPreference=secondaryPreferred 即可实现读写分离,读请求优先到 Secondary 节点,从而实现读写分离的功能
6.3.分片
6.3.1.概念
分片是把大型数据集进行分区成更小的可管理的片,这些数据片分散到不同的
mongoDB 节点,这些节点组成了分片集群.
mongoDB 分片集群推荐的模式是:分片集合,它是一种基于分片键的逻辑对文档
进行分组,分片键的选择对分片非常重要,分片键一旦确定,mongoDB 对数据的分片对应用是透明的
**分片理解:**使用一个字段做分片,经过 hash 后确定数据存储在哪个服务器的哪块区域上。
分片迁移
随着数据量的的增大,分片会分割和迁移,以满足数据的均匀分布
请求分流:通过路由节点将请求分发到对应的分片和块中;
数据分流:内部提供平衡器保证数据的均匀分布,数据平均分布式请求平均分布的前提
块的拆分:3.4 版本块的最大容量为 64M 或者 10w 的数据,当到达这个阈值,触发块的拆分,一分为二
块的迁移:为保证数据在分片节点服务器分片节点服务器均匀分布,块会在节点之间迁移。一般相差 8 个分块的时候触发;
6.3.2.分片模型
6.3.3.优点
1.数据海量增长,需要更大的读写吞吐量 → 存储分布式
2.单台服务器内存、cpu 等资源是有瓶颈的 → 负载分布式
tips:分片集群是个双刃剑,在提高系统可扩展性和性能的同时,增大了系统的复杂性,所以在实施之前请确定是必须的。
6.3.4.分片搭建
结构图
步骤
1.分片服务器配置:给 27020、27021 以及复制集(27017、27018、27019)的配置文件增加
sharding: clusterRole: shardsvr
2.config 服务器配置:给复制集(27022、27023、27024)的配置文件增加
sharding: clusterRole: configsvr
3.配置存储数据的分片复制集
rs.initiate({ _id: "dataRS", version: 1, members: [{ _id: 0, host : "192.168.0.128:27024" }]}); rs.add("192.168.0.128:27025");//有几个节点就执行几次方法 rs.add("192.168.0.128:27026");//有几个节点就执行几次方法
4.配置 config 的数据集
rs.initiate({ _id: "configRS", version: 1, members: [{ _id: 0, host : "192.168.0.128:27028" }]}); rs.add("192.168.0.128:27029");//有几个节点就执行几次方法 rs.add("192.168.0.128:27030");//有几个节点就执行几次方法
5.修改 mongos 路由节点的配置文件。mongos 的配置文件(mongodb.conf),没有“storage”“http.RESTInterfaceEnabled”这些配置,但增加如下配置
sharding: configDB: configRS/192.168.0.128:27028,192.168.0.128:27029,192.168.0.128:27030 这是配置路由节点需要连接的配置服务器的复制集地址;
6.使用 ./mongos -f mongodb.conf
启动路由节点;
7.配置分片 sharding
连接 mongos: mongo --port 27025
增加分区
use admin; sh.addShard("192.168.0.128:27023"); sh.addShard("192.168.0.128:27027"); //configRS 这个是复制集的名称 sh.addShard("dataRS/192.168.0.128:27024,192.168.0.128:27025,192.168.0.128:27026");
通过 sh.status()或图形化工具查看分片结果
对 lison 数据库启用分片:sh.enableSharding("lison")
对 ordersTest 集合进行分片,分片键为{“useCode”:1,"_id":1}
sh.shardCollection(“lison.orders”,{“useCode”:“hashed”});
6.3.5.tips
分片注意点
1.热点 :某些分片键会导致所有的读或者写请求都操作在单个数据块或者分片上,导致单个分片服务器严重不堪重负。自增长的分片键容易导致写热点问题;
2.不可分割数据块:过于粗粒度的分片键可能导致许多文档使用相同的分片键,这意味着这些文档不能被分割为多个数据块,限制了 mongoDB 均匀分布数据的能力;
3.查询障碍:分片键与查询没有关联,造成糟糕的查询性能。
建议
1.不要使用自增长的字段作为分片键,避免热点问题;
2.不能使用粗粒度的分片键,避免数据块无法分割;
3.不能使用完全随机的分片键值,造成查询性能低下;
4.使用与常用查询相关的字段作为分片键,而且包含唯一字段(如业务主键,id 等);
5.索引对于分区同样重要,每个分片集合上要有同样的索引,分片键默认成为索引;
6.分片集合只允许在 id 和分片键上创建唯一索引;