1.应用篇
1.1 体系结构
1.1.1 MongoDB的逻辑结构
MongoDB的逻辑结构,主要由:文档(document)、集合(collection)、数据库(database)这三部分构成的。逻辑结构是面向用户的,结构图如下所示:
与关系型数据库的术语名词比较表如下:
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
1.1.2 MongoDB的数据库
·
数据库名 | 数据库作用 |
---|---|
local | 存储限于本地单台服务器的任意集合,副本集的配置信息、oplog就存储在local库中 |
admin | 主要存放有数据库账号相关信息 |
config | 用于分片集群环境,存放了分片相关的元数据信息 |
test | MongoDB默认创建的一个测试库,连接mongod服务时,如果不指定连接的具体数据库,默认就会连接到test库 |
1.1.3 MongoDB的数据结构
名字 | 作用 |
---|---|
journal | 日志文件,用于持久化数据和宕机后数据故障恢复 |
namespace | 用于存储整个数据库的集合以及索引的名字和它们在数据文件的位置 |
data | dbname.0,dbname.1,…dbname.n,存储数据和索引 |
1.2 MongoDB的启动和停止
1.2.1 启动
1.2.2 停止
1.3 事务
1.3.1 事务区别
关系型数据库与非关系型数据库事务的区别:
- 关系型数据库的事务:遵守ACID原则,即原子性、一致性、隔离性、持久性
- 非关系型数据库的事务:遵守BASE原则:即基本可用、柔性事务、最终一致性
1.3.2 事务应用
MongoDB中,事务在3.x版本和4.x版本有不同体现,如下所示:
- 3.x版本
- 对单个文档的操作提供了原子操作
- 多个文档需在应用层进行“两阶段提交”来模拟事务
- 4.x版本
- 基于session做操作
- startTransaction()/CRUD/commitWithRetry
关于两阶段提交的更多内容,在下一小节进行说明。
1.3.3 两阶段提交
步骤如下:
- 在事务执行的文档中添加操作标识字段
- 记录事务要操作的文档及更新的内容,并设置事务初始化状态(initial)
- 更新事务状态为等待(pending)
- 将事务操作对应到具体的文档中
- 设置事务状态为提交(commited)
- 将事务执行文档中添加的操作标识移除
- 设置事务状态为结束(done)
1.3.4 GridFS
1.3.4.1 MongoDB写入策略(writeConcern)
示例如下:
db.collection.insert({x: 1},{writeConcern:{w:number}})
其中,较为重要的是w
参数,它代表着数据写入到number个节点才向客户端进行确认
该参数的一些值如下:
{w:0}
:对客户端的写入不需要发送任何确认,适用于性能要求高,但不关注正确性的场景,这是使用的最多的选项{w:1}
:默认的writeConcern,数据写入到Primary就向客户端发送确认{w:"majority"}
:数据写入到副本集大多数成员后向客户端发送确认,适用于对数据安全性要求比较高的场景,该选项会降低写入性能
1.3.4.2 GridFS简介
- GridFS用两个集合来存储一个文件:fs.files与fs.chunks
- GridFS会将大文件对象分割成多个小的chunk(文件片段,大小显示256k),每个chunk将作为一个文档被存储在chunks集合中
- 文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中
- fs.files的文件结构如下:
- fs.chunk的文件结构如下:
1.3.5 MapReduce
Map-Reduce将大批量的工作(数据)分组(Map)执行,然后再将结果合并成最终结果(Reduce)。相当于关系型数据库中的GROUP BY要实现的功能
- 基本语法:
- 参数说明:
2.管理篇
2.1 数据备份和恢复
2.1.1 数据导出
数据导出分为两种:
- mongoexport
- 导出为JSON
- 导出为CSV
- mongodump
2.1.1.1 mongoexport
下面简单介绍一下mongoexport的参数:
示例:
2.1.1.2 mongodump
2.2.2 数据导入
跟数据导出类似的,数据导入也分为两种:
- mongoimport
- 导入为JSON
- 导入为CSV
- mongostore
2.1.2.1 mongoimport
下面简单介绍一下mongoimportt的参数:
示例如下:
2.1.2.2 mongostore
2.2 访问控制
MongoDB数据库安全有几个方面:绑定IP内网地址访问MongoDB服务、设置监听端口、使用用户名和口令登录
- 绑定IP地址
- 数据库启动时加
bind_ip
参数,示例:./mongod --bind_ip 192.168.1.102
- 客户端访问时指定ip,示例:
./mongo 192.168.1.102
- 数据库启动时加
- 设置监听端口
- 默认是27017,数据库启动时加一个参数
bind_ip
,示例:./mongod -- bind_ip 192.168.1.102 --port 28018
- 客户端访问时指定IP和端口,示例:
./mongo 192.168.1.102:29018
- 默认是27017,数据库启动时加一个参数
- 用户权限
- 建立用户,并设定权限,如:只读用户权限
- 数据库启动时添加
auth
参数
2.3 进程控制
进程控制主要分为以下内容:
- 查看当前正在执行的线程
- 查看MongoDB当前正在做哪些操作:
db.currentOp()
等同于db.$cmd.sys.inprog.findOne()
- 查看当前有多少个连接:
db.serverStatus().connections
- 查看MongoDB当前正在做哪些操作:
- 结束当前正在执行的进程
- 如果某个进程产生了异常,
db.$cmd.sys.killop.findOne({op:10417})
- 不要在
dbcurrentOp()
查出进程号后,通过kill -9
结束进程,会造成节点数据丢失
- 如果某个进程产生了异常,
进程控制参数详解如下:
3.性能篇
3.1 索引
在mongoDB中,根据类型来划分,索引分为以下类型:
- 基础索引
- 单字段上创建索引,1(升序);-1(降序)
- 中_id 是创建表的时候自动创建的索引,此索引是不能够删除的
- 文档索引
- 建立于子文档上,会对子文档下各个字段建立单独索引
- 索引方式与基础索引一致
- 联合索引
- 针对多个字段联合创建索引,先按第一个字段排序,第一个字段相同的文档按第二个字段排序
- 当建立联合索引后,可以使用匹配索引前缀的查询
若是根据属性来划分,索引分为以下类型:
- 唯一索引:保证索引对应的字段不会出现相同的值,比如_id索引就是唯一索引
- TTL索引:可以针对某个时间字段,指定文档的过期时间(经过指定时间后过期 或 在某个时间点过期)
- 稀疏索引:只针对符合某个特定条件的文档建立索引
3.2 执行计划
MongoDB查询分析可以确保我们所建立的索引是否有效,是查询语句性能分析的重要工具。
常用的函数为:explain()
和hint()
,这里主要介绍较为常用的explain()
,介绍如下:
3.3 性能优化
如果在执行计划中发现nscanned(扫描的记录数)远大于nreturned(返回结果的记录数),则需要考虑性能优化,优化的措施一般如下所示:
- 创建索引:在查询条件的字段上,或者排序条件的字段上创建索引
- 限定结果数:使用
limit()
限定返回结果集的大小,可以减少database server的资源消耗,可以减少网络传输数据量 - 查询需要的字段:只查询使用到的字段,而不查询所有字段
- capped colleciton:比普通的collections的读写效率高,且默认基于insert的次序排序,如果查询时没有排序,则总是按照insert的顺序返回
- Server-Side Processing:类似于SQL数据库的存储过程,可以减少网络通讯的开销
- Hint:Hint可以强制要求查询操作使用某个索引,例如:如果要查询多个字段的值,如果在其中一个字段上有索引
4.架构篇
4.1 副本集
4.1.1 副本集简介
副本集(Replica Set)中的成员角色有三种:Primary(主节点)、Secondary(从节点)和Arbiter(仲裁节点)。
部署一个副本集至少需要三个节点:一个主节点、一个从节点和一个仲裁节点;或者一个主节点,两个从节点
下面来介绍一下主节点和从节点。
- 主节点
- mongoDB各个节点常见的搭配方式为:一主一从、一主多从,主节点可以读写,从节点只能读
- 主节点将数据修改操作保存至oplog中
- 心跳信息每两秒传递一次,通过选举,实现自动故障转移。主节点宕机后会进行自动选举
- 从节点
- 0优先级节点:冷备节点,参与选举,但是不会被选举成为主节点
- 隐藏的从节点:首先是一个0优先级节点,并且对客户端不可见
- 延迟复制从节点:首先是一个0优先级节点,并且复制时间落后于主节点一个固定时长,持有的数据始终为过期数据。主要作用为保存原来的数据,以备在主节点读写错误数据时拥有可以恢复原数据的节点
- arbiter:仲裁节点,不持有数据
除此之外,每个节点都会有oplog,但只有主节点会写oplog,然后同步给从节点。oplog是一个大小固定的文件,存储在local库中。
副本集的结构如图所示:
4.1.2 副本集的安装
4.1.3 副本集的维护
4.2 分片
4.2.1 分片简介
MongoDB是一种将海量的数据水平扩展的数据库集群系统,数据分表存储在sharding的各个节点上。由于MongoDB设计重要特性为水平扩展,于是其更有利于使用sharding,实现动态扩容、自动平衡数据、单个shard可以平衡审计为副本集
下面简单介绍一下分片的类型:
- Shard Server
即存储实际数据的分片,每个Shard可以是一个mongod实例,也可以是一组mongod实例构成的副本集,为了实现每个Shard内部的autofailover,MongoDB3.2后每个Shard可为一组副本集 - Config Server
为了将一个特定的集合存储在多个Shard中,需要为该集合指定一个Shard key,例如{age:1},Shard key可以决定该条记录属于哪个chunk。Config Servers就是用来存储:所有Shard节点的配置信息、每个chunk的shard key范围、chunk在各个Shard的分布情况、该集群中所有DB和集合的Sharding的配置信息 - Route Process
这是一个前端路由,客户端由此接入,然后询问Config Servers需要到哪个Shard上查询或保存记录,再连接相应的Shard进行操作,最后将结果返回给客户端
大致的结构图如下所示:
4.2.2 分片的相关操作
4.2.3 分片中对于Shard key(片键)的选择
- 方案
- 范围分片:通常能很好的支持基于Shard key的范围查询
- Hash分片:通常能将写入均衡分布到各个Shard
- 要素
- key分布足够离散
- 写请求均匀分布
- 尽量避免scatter-gather查询
- 限定
- MongoDB不允许插入没有片键的文档
- 分片之后数据的存放位置依赖于片键,对于分片Key的选定直接决定了集群中数据分布是否均衡、集群性能是否合理