数据库 MongoDB
2024-03-24 21:23:52 0 举报
AI智能生成
数据库 MongoDB
作者其他创作
大纲/内容
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的,属于文档类型数据库。
存储结构
文档(Document):MongoDB 中最基本的单元,由 BSON 键值对(key-value)组成,类似于关系型数据库中的行(Row)。
集合(Collection):一个集合可以包含多个文档,类似于关系型数据库中的表(Table)。
数据库(Database):一个数据库中可以包含多个集合,可以在 MongoDB 中创建多个数据库,类似于关系型数据库中的数据库(Database)。
文档
MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。
BSON [bee·sahn] 是 Binary JSON 的简称,是 JSON 文档的二进制表示,
支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
BJSON 的遍历速度优于 JSON,但 BJSON 需要更多的存储空间。
键命名规则
键不能含有 \0(空字符)。这个字符用来表示键的结尾。
. 和 $ 有特别的意义,只有在特定环境下才能使用。
以下划线_开头的键是保留的(不是严格要求的)。
集合
MongoDB 集合存在于数据库中,没有固定的结构,也就是 无模式 的,这意味着可以往集合插入不同格式和类型的数据。
集合命名条件
集合名不能是空字符串""。
集合名不能含有 \0 (空字符),这个字符表示集合名的结尾。
集合名不能以"system."开头,这是为系统集合保留的前缀。
集合名必须以下划线或者字母符号开始,并且不能包含 $。
数据库
数据库用于存储所有集合,而集合又用于存储所有文档。一个 MongoDB 中可以创建多个数据库,每一个数据库都有自己的集合和权限。
预留库
admin : admin 数据库主要是保存 root 用户和角色。
local : local 数据库是不会被复制到其他分片的,因此可以用来存储本地单台服务器的任意 collection。
config : 当 MongoDB 使用分片设置时,config 数据库可用来保存分片的相关信息。
test : 默认创建的测试库,连接 mongod 服务时,如果不指定连接的具体数据库,默认就会连接到 test 数据库。
数据库命名条件
不能是空字符串""。
不得含有' '(空格)、.、$、/、\和 \0 (空字符)。
应全部小写。
最多 64 字节。
特点
数据记录被存储为文档:MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。
模式自由:集合的概念类似 MySQL 里的表,但它不需要定义任何模式,能够用更少的数据对象表现复杂的领域模型对象。
支持多种查询方式:MongoDB 查询 API 支持读写操作 (CRUD)以及数据聚合、文本搜索和地理空间查询。
支持 ACID 事务:NoSQL 数据库通常不支持事务,为了可扩展和高性能进行了权衡。但MongoDB 支持事务,同样具有 ACID 特性。
高效的二进制存储:存储在集合中的文档,是以键值对的形式存在的。
自带数据压缩功能:存储同样的数据所需的资源更少。
支持 mapreduce:通过分治的方式完成复杂的聚合任务。从 MongoDB 5.0 开始,推荐其替代方案 聚合管道。
支持多种类型的索引:MongoDB 支持多种类型的索引,包括单字段索引、复合索引、多键索引、哈希索引、文本索引、 地理位置索引等。
支持 failover:提供自动故障恢复的功能,主节点故障时,自动选举新的主节点,客户无感知。
支持分片集群:MongoDB 支持集群自动切分数据,让集群存储更多的数据,具备更强的性能。
支持存储大文件:MongoDB 的单文档存储空间要求不超过 16MB。提供了 GridFS 来进行分块存储。
存储引擎
数据库的核心组件,负责管理数据在内存和磁盘中的存储方式。与 MySQL 一样,MongoDB 采用的也是 插件式的存储引擎架构。
最初默认是使用 MMAPV1 存储引擎,MongoDB4.x 版本不再支持 MMAPv1 存储引擎。
分类
WiredTiger 存储引擎:自 MongoDB 3.2 以后,默认的存储引擎为 WiredTiger 存储引擎 。
非常适合大多数工作负载,建议用于新部署。WiredTiger 提供文档级并发模型、检查点和数据压缩等功能。
非常适合大多数工作负载,建议用于新部署。WiredTiger 提供文档级并发模型、检查点和数据压缩等功能。
In-Memory 存储引擎:In-Memory 存储引擎 在 MongoDB Enterprise 中可用。
它不是将文档存储在磁盘上,而是将它们保留在内存中以获得更可预测的数据延迟。
它不是将文档存储在磁盘上,而是将它们保留在内存中以获得更可预测的数据延迟。
MongoDB 3.0 提供了 可插拔的存储引擎 API ,允许第三方为 MongoDB 开发存储引擎,这点和 MySQL 也比较类似。
WiredTiger
默认使用 B+ 树作为其存储结构,还支持 LSM(Log Structured Merge) 树作为存储结构。
使用 B+ 树时,WiredTiger 以 page 为基本单位往磁盘读写数据。B+ 树的每个节点为一个 page。
page分类
root page(根节点):B+ 树的根节点。
internal page(内部节点):不实际存储数据的中间索引节点。
leaf page(叶子节点):真正存储数据的叶子节点,包含一个页头(page header)、块头(block header)和真正的数据(key/value)。
聚合
将多个文档甚至是多个集合汇总到一起计算分析(比如求和、取最大值)并返回计算后的结果,这个过程被称为 聚合操作 。
分类
聚合管道(Aggregation Pipeline):执行聚合操作的首选方法。
单一目的聚合方法(Single purpose aggregation methods):也就是单一作用的聚合函数比如 count()、distinct()、estimatedDocumentCount()。
mapreduce:通过分治的方式完成复杂的聚合任务。从 MongoDB 5.0 开始,推荐其替代方案 聚合管道。
聚合管道
由多个阶段组成,每个阶段在文档通过管道时转换文档。
工作流程
接受一系列原始数据文档。
对这些文档进行一系列运算。
结果文档输出给下一个阶段。
操作符
$match
匹配操作符,用于对文档集合进行筛选。
$project
投射操作符,用于重构每一个文档的字段,可以提取字段,重命名字段,甚至可以对原有字段进行操作后新增字段。
$sort
排序操作符,用于根据一个或多个字段对文档进行排序。
$limit
限制操作符,用于限制返回文档的数量。
$skip
跳过操作符,用于跳过指定数量的文档。
$count
统计操作符,用于统计文档的数量。
$group
分组操作符,用于对文档集合进行分组。
$unwind
拆分操作符,用于将数组中的每一个值拆分为单独的文档。
$lookup
连接操作符,用于连接同一个数据库中另一个集合,并获取指定的文档,类似于 populate。
事务
NoSQL 数据库通常不支持事务,但 MongoDB 支持事务。
MongoDB 单文档原生支持原子性,也具备事务的特性。通常指的是 多文档 。
MongoDB 4.0 加入了对多文档 ACID 事务的支持,但只支持复制集部署模式下的 ACID 事务,也就是说事务的作用域限制为一个副本集内。
MongoDB 4.2 引入了 分布式事务 ,增加了对分片集群上多文档事务的支持,并合并了对副本集上多文档事务的现有支持。
在大多数情况下,多文档事务比单文档写入会产生更大的性能成本。对于大部分场景来说,适当地对数据进行建模可以最大限度地减少对多文档事务的需求。
从 MongoDB 4.2 开始,多文档事务支持副本集和分片集群,其中:主节点使用 WiredTiger 存储引擎,
同时从节点使用 WiredTiger 存储引擎或 In-Memory 存储引擎。在 MongoDB 4.0 中,只有使用 WiredTiger 存储引擎的副本集支持事务。
同时从节点使用 WiredTiger 存储引擎或 In-Memory 存储引擎。在 MongoDB 4.0 中,只有使用 WiredTiger 存储引擎的副本集支持事务。
在 MongoDB 4.2 及更早版本中,你无法在事务中创建集合。从 MongoDB 4.4 开始,您可以在事务中创建集合和索引。
数据压缩
借助 WiredTiger 存储引擎,MongoDB 支持对所有集合和索引进行压缩。压缩以额外的 CPU 为代价最大限度地减少存储使用。
算法
Snappy:谷歌开源的压缩算法(压缩比 3 ~ 5 倍),WiredTiger 默认使用其对所有集合使用块压缩,对所有索引使用前缀压缩。
zlib:高度压缩算法,压缩比 5 ~ 7 倍。
Zstandard(简称 zstd):Facebook 开源的一种快速无损压缩算法,
针对 zlib 级别的实时压缩场景和更好的压缩比,提供更高的压缩率和更低的 CPU 使用率,MongoDB 4.2 开始可用。
针对 zlib 级别的实时压缩场景和更好的压缩比,提供更高的压缩率和更低的 CPU 使用率,MongoDB 4.2 开始可用。
WiredTiger 日志也会被压缩,默认使用的也是 Snappy 压缩算法。如果日志记录小于或等于 128 字节,WiredTiger 不会压缩该记录。
索引
MongoDB 可以使用该索引来限制它必须检查的文档数量,以便提高查询效率。
分类
单字段索引: 建立在单个字段上的索引,索引创建的排序顺序无所谓,MongoDB 可以头/尾开始遍历。
复合索引: 建立在多个字段上的索引,也可以称之为组合索引、联合索引。字段的顺序非常重要,且遵循左前缀原则。
多键索引:MongoDB 的一个字段可能是数组,在对这种字段创建索引(为数组的每个值创建索引)时,就是多键索引。
哈希索引:按数据的哈希值索引,用在哈希分片集群上。
文本索引: 支持对字符串内容的文本搜索查询。支持全文索引,但性能低下,暂不推荐。
地理位置索引: 基于经纬度的索引,适合 2D 和 3D 的位置查询。
唯一索引:确保索引字段不会存储重复值。
TTL 索引:TTL 索引提供了一个过期机制,允许为每一个文档设置一个过期时间,当一个文档达到预设的过期时间之后就会被删除。
TTL 索引限制
TTL 索引是单字段索引。复合索引不支持 TTL。
_id字段不支持 TTL 索引。
无法在上限集合(Capped Collection)上创建 TTL 索引,因为 MongoDB 无法从上限集合中删除文档。
如果某个字段已经存在非 TTL 索引,那么在该字段上无法再创建 TTL 索引。
覆盖索引查询
所有的查询字段是索引的一部分。
结果中返回的所有字段都在同一索引中。
查询中没有字段等于null。
高可用
复制集群
又称为副本集群,是一组维护相同数据集合的 mongod 进程。
一个复制集群包含 1 个主节点(Primary),多个从节点(Secondary)以及零个或 1 个仲裁节点(Arbiter)。
组成
主节点:整个集群的写操作入口,接收所有的写操作,并将集合所有的变化记录到操作日志中,即 oplog。主节点挂掉之后会自动选出新的主节点。
从节点:从主节点同步数据,在主节点挂掉之后选举新节点。不过,从节点可以配置成 0 优先级,阻止它在选举中成为主节点。
仲裁节点:这个是为了节约资源或者多机房容灾用,只负责主节点选举时投票不存数据,保证能有节点获得多数赞成票。
主节点与备节点之间是通过 oplog(操作日志) 来同步数据的。
oplog 是 local 库下的一个特殊的 上限集合(Capped Collection) ,用来保存写操作所产生的增量日志,类似于 MySQL 中 的 Binlog。
oplog 是 local 库下的一个特殊的 上限集合(Capped Collection) ,用来保存写操作所产生的增量日志,类似于 MySQL 中 的 Binlog。
优势
实现 failover:提供自动故障恢复的功能。
实现读写分离:减轻了主节点读写压力过大的问题。
分片集群
MongoDB 的分布式版本,相较副本集,分片集群数据被均衡的分布在不同分片中。
作用
不仅大幅提升了整个集群的数据容量上限,也将读写的压力分散到不同分片,以解决副本集性能瓶颈的难题。
组成
Config Servers:配置服务器,本质上是一个 MongoDB 的副本集,负责存储集群的各种元数据和配置,如分片地址、Chunks 等。
Mongos:路由服务,不存具体数据,从 Config 获取集群配置讲请求转发到特定的分片,并且整合分片结果返回给客户端。
Shard:每个分片是整体数据的一部分子集,从 MongoDB3.6 版本开始,每个 Shard 必须部署为副本集(replica set)架构。
拓展方式
垂直扩展:通过增加单个服务器的能力来实现,比如磁盘空间、内存容量、CPU 数量等。
水平扩展:通过将数据存储到多个服务器上来实现,根据需要添加额外的服务器以增加容量。
场景
存储容量受单机限制,即磁盘资源遭遇瓶颈。
读写能力受单机限制,可能是 CPU、内存或者网卡等资源遭遇瓶颈,导致读写能力无法扩展。
分片键
分片键(Shard Key) 是数据分区的前提, 从而实现数据分发到不同服务器上,减轻服务器的负担。
分片键就是文档里面的一个字段,但是这个字段不是普通的字段,有一定的要求。
要求
它必须在所有文档中都出现。
它必须是集合的一个索引,可以是单索引或复合索引的前缀索引,不能是多索引、文本索引或地理空间位置索引。
MongoDB 4.2 之前的版本,文档的分片键字段值不可变。
MongoDB 4.2 版本开始,除非分片键字段是不可变的 _id 字段,否则您可以更新文档的分片键值。
MongoDB 5.0 版本开始,实现了实时重新分片(live resharding),可以实现分片键的完全重新选择。
MongoDB 4.2 版本开始,除非分片键字段是不可变的 _id 字段,否则您可以更新文档的分片键值。
MongoDB 5.0 版本开始,实现了实时重新分片(live resharding),可以实现分片键的完全重新选择。
它的大小不能超过 512 字节。
选择条件
选择合适的片键对 sharding 效率影响很大,主要基于四个因素。
取值基数:取值基数建议尽可能大,如果用小基数的片键,因为备选值有限,
那么块的总数量就有限,随着数据增多,块的大小会越来越大,导致水平扩展时移动块会非常困难。
那么块的总数量就有限,随着数据增多,块的大小会越来越大,导致水平扩展时移动块会非常困难。
取值分布:取值分布建议尽量均匀,分布不均匀的片键会造成某些块的数据量非常大,同样有上面数据分布不均匀,性能瓶颈的问题。
查询带分片:查询时建议带上分片,使用分片键进行条件查询时,可以直接定位到具体分片,否则需要将查询分发到所有分片,再等待响应返回。
避免单调递增或递减:单调递增的 sharding key,数据文件挪动小,但写入会集中,导致最后一篇的数据量持续增大,不断发生迁移,递减同理。
分片策略
基于范围的分片
MongoDB 按照分片键(Shard Key)的值的范围将数据拆分为不同的块(Chunk),每个块包含了一段范围内的数据。
当分片键的基数大、频率低且值非单调变更时,范围分片更高效。
当分片键的基数大、频率低且值非单调变更时,范围分片更高效。
优点
Mongos 可以快速定位请求需要的数据,并将请求转发到相应的 Shard 节点中。
缺点
可能导致数据在 Shard 节点上分布不均衡,容易造成读写热点,且不具备写分散性。
场景
分片键的值不是单调递增或单调递减、分片键的值基数大且重复的频率低、需要范围查询等业务场景。
基于 Hash 值的分片
MongoDB 计算单个字段的哈希值作为索引值,并以哈希值的范围将数据拆分为不同的块(Chunk)。
优点
可以将数据更加均衡地分布在各 Shard 节点中,具备写分散性。
缺点
不适合进行范围查询,进行范围查询时,需要将读请求分发到所有的 Shard 节点。
场景
分片键的值存在单调递增或递减、片键的值基数大且重复的频率低、需要写入的数据随机分发、数据读取随机性较大等业务场景。
除了上述两种分片策略,还可以配置 复合片键 ,例如由一个低基数的键和一个单调递增的键组成。
分片数据存储
Chunk(块)
MongoDB 分片集群的一个核心概念,其本质上就是由一组 Document 组成的逻辑数据单元。
每个 Chunk 包含一定范围片键的数据,互不相交且并集为全部数据,即离散数学中划分的概念。
每个 Chunk 包含一定范围片键的数据,互不相交且并集为全部数据,即离散数学中划分的概念。
分片集群不会记录每条数据在哪个分片上,而是记录 Chunk 在哪个分片上一级这个 Chunk 包含哪些数据。
默认情况下,一个 Chunk 的最大值默认为 64MB(可调整,取值范围为 1~1024 MB。如无特殊需求,建议保持默认值)。
Chunk 分裂
进行数据插入、更新、删除时,如果此时 Mongos 感知到了目标 Chunk 的大小或者其中的数据量超过上限,则会触发 Chunk 分裂。
再平衡(Rebalance)
数据的增长会让 Chunk 分裂得越来越多。此时各个分片上的 Chunk 数量可能会不平衡。
Mongos 中的 均衡器(Balancer) 组件就会执行自动平衡,尝试使各个 Shard 上 Chunk 的数量保持均衡,这个过程就是 再平衡(Rebalance)。
默认情况下,数据库和集合的 Rebalance 是开启的。
Mongos 中的 均衡器(Balancer) 组件就会执行自动平衡,尝试使各个 Shard 上 Chunk 的数量保持均衡,这个过程就是 再平衡(Rebalance)。
默认情况下,数据库和集合的 Rebalance 是开启的。
Rebalance 操作是比较耗费系统资源的,我们可以通过在业务低峰期执行、预分片或者设置 Rebalance 时间窗等方式来减少其影响。
Chunk 迁移
MongoDB默认情况下会开启一个balancer模块用于定期检测各个shard上的chunk数量分布,
当检测到各个shard上的chunk数量存在分布不均匀的情况时,就会触发chunk迁移。
当检测到各个shard上的chunk数量存在分布不均匀的情况时,就会触发chunk迁移。
chunk迁移操作通过moveChunk命令发起,可以被balancer自动调用(balancer每隔10s扫描哪些chunk需要被迁移),也支持用户主动发起。
迁移chunk的整个过程实际上就是一次两个shard进行数据交换的过程,分别有 chunk 的发送方和接收方。
应用
MongoDB 的优势在于其数据模型和存储引擎的灵活性、架构的可扩展性以及对强大的索引支持。
0 条评论
下一页
为你推荐
查看更多