一、简介
MongoDB 是一个开源、高性能无模式的文档数据库,不是关系型数据库,是 NoSQL 数据库产品中的一种,放弃关系模型的主要原因是为了获得更方便的扩展性。
与 MySQL 对比,数据库都是 database,数据库中的表对应到 MongoDB中的 Collection,表中的行对应到 MongoDB中 的 Document。MongoDB 不支持表连接查询。
MongoDB 的版本偶数版本是稳定版本,奇数版本为开发版本。
二、MongoDB 特点
高可扩展性:应用数据集的大小在飞速发展,传感器技术的发展、带宽的增加,以及可连接到因特网的手持设备的普及使得当下即便很小的应用也要储存大量数据,量大到很多数据库应付不过来。MongoDB 从设计之初就考虑扩展的问题。采用了面向文档的数据模型使其可以自动在多台服务器之间分割数据。还可以平衡集群数据和负载,自动重排文档,这样只需要在集群中添加新机器,然后让数据库处理接下来的事。
高性能:MongoDB 使用 MongoDB 传输协议作为与服务器交互的主要方式。它对文档进行动态填充,预分配数据文件,用空间获取性能稳定。默认的存储引擎中使用了内存映射文件,将内存管理工作交给操作系统处理。动态查询优化器会记住执行查询最高效的方式。
高可用性:MongoDB 的复制工具称为副本集(replica set),它可提供自动故障转移和数据冗余。
三、核心概念
如下为 MongoDB 的核心概念图
3.1 文档
文档是 MongoDB 的核心概念,是最小的操作单元,多个键及其关联的值有序的放置在一起便是文档。如果插入数据时没有指定 _id属性,则数据库集合会自动为文档加 _id,作为唯一的ID。下图为具体的数据示例
文档的键是字符串,除了少数例外情况,键可以使用任意UTF-8字符。
- 键不能是空字符
- . 和 $ 有特殊含义,只有在特定环境才能使用,通常是保留字段
- 以下划线 "_" 开头的键是保留的
MongoDB 不但区分类型还区分大小写
3.2 集合
集合就是一组文档,如果说 MongoDB 中的文档类似于关系数据库中的行,那么集合就类似于表。
集合是无模式的,这意味着一个集合里的文档可以各式各样,但是这种方式并不规范,通过集合来把一类文档放到一起,这样更利于管理。
3.3 数据库
MongoDB 中多个文档组成集合,同样多个集合可以组成数据库。一个MongoDB实例可以承载多个数据库,他们之间是完全独立的。如下图所示:
3.4 数据类型
MongoDB 文档类似与 JSON,在概念上和 JavaScript 中的对象神似。JSON 是一种简单的标识数据的方式,JSON 的表现力也有限制,因为只有 NULL、布尔、数字、字符串、数组和对象几种类型。虽然这些类型表现力已经足够强大,但是还有欠缺,没有日期类型。
MongoDB 在保留 JSON 基本键/值对特性的基础上,添加了其他一些数据类型。
MongoDB 的文档是一个抽象概念。其具体的呈现形式取决于使用的驱动和编程语言。因为MongoDB 中的通信大量依赖于文档,所以需要一种所有驱动、工具和进程都能共享的文档表达方式。这种表达方式叫做 Binary JSON(BSON)。
BSON 是轻量的二进制格式,能将 MongoDB 的所有文档表示为字节字符串。数据库能理解BSON,存在磁盘上的文档也是这种格式。
当驱动要插入文档,或者将文档作为查询条件,驱动会将文档转换为 BSON,然后再发往服务器。同样,返回到客户端的文档也是 BSON 格式的字符串。
BSON 格式的主要目标:
- 效率:BSON 设计用来更有效的表示数据,占用更少的空间。最差的情况,BSON 比 JSON效率略低;最好的情况下,BSON 要高效的多。
- 可遍历性:有时 BSON 牺牲了空间效率,换取更容易的遍历格式。例如在字符串前面加入长度,而不是在结尾处使用一个终结符。
- 性能:BSON 的编码和解码速度都很快。它用 C 风格的表现方式来表示类型,在大多数编程语言中都很快。
3.5 传输协议
驱动在 TCP/IP 协议的基础上简单封装了 MongoDB 传输协议,用来与 MongoDB 交互。简单说基本上就是一个简单封装的 BSON 数据。
四、分片
分片是 MongoDB 的扩展方式,分片是指将数据拆分,将其分散在不同机器上的过程,有时也用分区来表示这一概念。将数据分散在不同机器上,不需要功能强大的计算机就可以存储大量数据,处理更大的负载。
使用几乎所有的数据库软件都能进行手动分片。应用需要维护与若干不同数据库的连接,每个链接还完全是独立的,应用程序管理不同服务器上不同数据,存储查询都需要在正常的服务器上进行。这种方法可以很好的进行,但是非常难维护,比如向集群中添加或删除节点都很困难,调整数据分布和负载也不轻松。
MongoDB 支持自动分片,可以摆脱手动分片的困扰。集群自动切分数据,做负载均衡。
分片集群的概念:
- Shard Rules:分片规则,也叫分片算法,指分发读写请求的逻辑
- Shard Key:分片键,也叫路由键,指基于文档中的哪个字段进行分片计算
- Document:文档,一条数据
- Chunk:块,指包含一定范围内多个文档的数据段,数据集群中分割、存储数据的基本单元
- Shard:分片,每个分片都由一个副本集组成,一个分片中可以存储多个Chunk
- Cluster:集群,由多个Shard分片组成,统一对外提供读写服务
4.1 MongoDB 自动分片
MongoDB 分片的基本思想就是将集合切分成小块。这些块分散到若干片里面,每个片只负责一部分数据。应用程序不必知道哪片对应哪些数据,甚至不知道数据已经拆分,所以在分片之前需要运行一个路由进程,该进程的名字为 mongos。这个路由知道所有数据存放位置,所以应用可以链接他来正常发送请求。
分片集群的组成
- shard:每个分片包含分片数据的一个子集。每个分片都可以部署为副本集
- mongos:mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口
- config servers:配置服务器存储集群的元数据和配置设置
shard、config servers 组件部署副本集保障高可用,mongos是单点架构,可以部署多个节点保障高可用。
4.2 何时分片
出现下面信号时就可以考虑分片了
- 机器的磁盘不够用了
- 单个 mongod 已经不能满足写数据性能要求
- 想将大量数据放在内存中提高性能
一般来说,先要从不分片开始,然后再需要时将其转换成分片。
4.3 片键
设置分片时,需要从集合里选一个键,用该键的值作为数据拆分的依据。这个键称为片键(shard key)。
举个例子:假设有个集合存储的事人员信息,如果选择人员姓名(name)作为片键,第一片可能会存放名字以 A - F 开头的文档,第二片存放 G - P 的名字,第三片存放余下的名字。随着数据的不断变化,添加或者删除,MongoDB 会重新平衡数据,使每片的数据都比较均衡,数据分布在合理的范围内。
将已有的集合分片,假设有个存储日志的集合,现在要分片。我们开启分片功能,然后告诉MongoDB 用时间戳作为片键,就把所有数据放到一个片上,可以随意插入数据,但是总归在一个片上。而后增加一个片,这个片建好并运行后,MongoDB 就会把集合拆分成两半,称为块。每个块中包括片键值在一定范围内的所有文档,所以就假设一个块包含时间戳在 2023年6月26日以前的文档,另一块含有2023年6月27日以后得文档。
片键分为递增片键和随机片键,该如何选择呢?
如果写入负载很高的话,不适合使用递增片键,比如时间戳,因为写入会集中在一个片内,但递增片键查询效率非常高。如果写入负载很高的话,选择随机片键,均匀分散负载到各个片上。
不论片键随机跳跃还是稳定增加,片键的变化至关重要,例如,如果有个 "logLevel" 键只有3个值,DEBUG、WARN 或 ERROR,MongoDB 就无论如何也不会把他作为片键将数据分为 3块。如果键的变化太少,但又想将其作为片键,可以将这个键与一个变化较大的键组合起来。
关于 MongoDB 的相关介绍就到这里,后续继续介绍相关核心原理。