MongoDB
MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need
MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是可以应用于各种规模的企业、各个行业以及各类应用程序的开源数据库。作为一个适用于敏捷开发的数据库,MongoDB的数据模式可以随着应用程序的发展而灵活地更新。与此同时,它也为开发人员 提供了传统数据库的功能:二级索引,完整的查询系统以及严格一致性等等。 MongoDB能够使企业更加具有敏捷性和可扩展性,各种规模的企业都可以通过使用MongoDB来创建新的应用,提高与客户之间的工作效率,加快产品上市时间,以及降低企业成本。
MongoDB 是专为可扩展性,高性能和高可用性而设计的数据库。它可以从单服务器部署扩展到大型、复杂的多数据中心架构。利用内存计算的优势,MongoDB能够提供高性能的数据读写操作。 MongoDB的本地复制和自动故障转移功能使您的应用程序具有企业级的可靠性和操作灵活性。
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
Databases、Collections and Documents
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
MongoDB 将数据记录作为文档 (特别是BSON 文档)存储在集合中。数据库存储一个或多个文档集合。
|
|
MongoDB 将数据记录存储为 BSON 文档。BSON 是JSON文档的二进制表示,尽管它包含比 JSON 更多的数据类型。对于 BSON 规范,请参阅 bsonspec.org
BSON 文档的最大大小为 16 兆字节。
namespace 数据库名与集合名称以点连接起来就叫名字空间
BSON Types
下表为MongoDB中常用的几种数据类型。
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
32-bit integer | int 整型数值。用于存储数值。 |
64-bit integer | long 整型数值。用于存储数值。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Decimal128 | 16 bytes decimal new in version 3.4 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
ObjectId | 对象 ID。用于创建文档的 ID。 |
Binary data | 二进制数据。用于存储二进制数据。 |
JavaScript | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
ObjectId
ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:
- 一个 4 字节的时间戳,表示 ObjectId 的创建,以 Unix 纪元以来的秒数为单位。
- 每个进程生成一次的 5 字节随机值。这个随机值对于机器和进程是唯一的。
- 一个 3 字节递增计数器,初始化为随机值。
在 MongoDB 中,存储在集合中的每个文档都需要一个唯一的 _id字段作为主键。如果插入的文档省略了该_id字段,MongoDB 驱动程序会自动为该字段生成一个ObjectId_id。
- 在 mongosh 中,您可以使用
ObjectId.getTimestamp()
方法访问创建时间。 - _id对存储值的字段 ObjectId 进行排序大致相当于按创建时间排序。
|
|
Timestamps
BSON 有一个特殊的时间戳类型供内部MongoDB 使用,并且 与常规的Date 类型无关。此内部时间戳类型是 64 位值,其中:
Date
BSON Date 是一个 64 位整数,表示自 Unix 纪元(1970 年 1 月 1 日)以来的毫秒数。这导致过去和未来大约 2.9 亿年的可表示日期范围。
数据安全
恢复日志 (Journal) 用来解决因为系统掉电或者崩溃导致内存数据丢失问题的一种日志。数据在写入内存之后即刻返回给应用程序。而数据刷盘动作则在后台由操作系统来进行。MongoDB会每隔60秒强制把数据刷到磁盘上。
自从2.0开始,MongoDB已经把Journal日志设为默认开启。MongoDB会先把数据更新写入到Journal Buffer里面然后再更新内存数据,然后再返回给应用端。 Journal会以100ms的间隔批量刷到盘上。这样的情况下,即使出现断电数据尚未保存到文件, 由于有Journal文件的存在,MongoDB会自动根据Journal里面的操作历史记录来对数据文件重新进行追加。
写关注(写安全机制 write concern) 写关注是MongoDB特有的一个功能。 它可以让你灵活地指定你写操作的持久化设定。 这是一个在性能和可靠性之间的一个权衡。
{w: 0} Unacknowledged
对每一个写入操作,MongoDB并不会返回一个是否成功的状态值。这个级别是写入性能最好但也是最不安全的级别。{w: 1} Acknowledged
Acknowledged 的意思就是对每一个写入MongoDB都会确认操作的完成状态,不管是成功还是失败。当然这个确认只是基于主节点的内存写入。但就是这个级别,可以侦测到重复主键, 网络错误,系统故障或者是无效数据等错误。{j:1} Journaled
每一次的写操作会在MongoDB实实在在的把journal落盘以后才会返回。MongoDB并不会对每一个操作都立即刷盘,而是会等最多30ms,把30ms内的写操作集中到一起,采用顺序追加的方式写入到盘里,在这30ms内客户端线程会处于等待状态- {w: “majority”} 写到多数节点,使用这个写安全级别,MongoDB只有在数据已经被复制到多数个节点的情况下才会向客户端返回确认。
java Driver 中 WriteConcern
定义了几种抛出异常的级别, insert,update,remove 方法均有设置此参数的重载。
复制 Replication
MongoDB 中的副本集是一组维护相同数据集的mongod进程。副本集提供冗余和高可用性,是所有生产部署的基础。
MongoDB 复制集由一组MongoDB实例(进程)组成,包含一个Primary节点和多个Secondary节点,MongoDB Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。
MongoDB 中的复制
副本集(replica set)是一组护相同数据集的mongod维实例。一个副本集包含几个数据承载节点和一个可选的仲裁(arbiter)节点。在数据承载节点中,只有一个成员被视为主(primary)节点,而其他节点被视为辅助(secondary)节点。
主节点接收所有写操作。一个副本集只能有一个主节点能够确认写入通过 { w: "majority" }
写关注;尽管在某些情况下,另一个 mongod 实例可能会暂时认为自己也是主要的。 主节点在其操作日志中记录其数据集的所有更改,即 oplog。
辅助节点复制主节点的oplog 并将操作应用于其数据集,以便辅助节点的数据集反映主节点的数据集。如果主节点不可用,符合条件的辅助节点将举行选举,将自己选为新的主节点。
在某些情况下(例如您有一个主节点和一个辅助节点,但成本限制禁止添加另一个辅助节点),您可以选择将一个mongod实例添加到副本集作为 仲裁器。仲裁者参与 选举但不持有数据(即不提供数据冗余)。
仲裁者将永远是仲裁者,而主节点可能会下台并成为辅助节点,而 辅助节点可能会在选举期间成为主节点。
副本集选举
在MongoDB中副本集由一组MongoDB实例组成,包括一个主节点多个次节点,MongoDB客户端的所有数据都写入主节点(Primary),副节点从主节点同步写入数据,以保持所有复制集内存储相同的数据,提高数据可用性。
副本集类似于主从式架构,但他们结合的能力为副机,如果当前一直迟缓时,选出新的主机。
复制集通过replSetInitiate命令(或mongoshell的rs.initiate())进行初始化,初始化后各个成员间开始发送心跳消息,并发起Primary选举操作,获得大多数成员投票支持的节点,会成为Primary,其余节点成为Secondary。
“大多数”的定义
假设复制集内投票成员(后续介绍)数量为N,则大多数为N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。
通常建议将复制集成员数量设置为奇数,从上表可以看出3个节点和4个节点的复制集都只能容忍1个节点失效,从服务可用性的角度看,其效果是一样的,但无疑4个节点能提供更可靠的数据存储。
特殊的Secondary节点
正常情况下,复制集的Secondary会参与Primary选举(自身也可能会被选为Primary),并从Primary同步最新写入的数据,以保证与Primary存储相同的数据。
Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,MongoDB支持对复制集的Secondary节点进行灵活的配置,以适应多种场景的需求。
Arbiter:
Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据。
比如你部署了一个2个节点的复制集,1个Primary,1个Secondary,任意节点宕机,复制集将不能提供服务了(无法选出Primary),这时可以给复制集添加一个Arbiter节点,即使有节点宕机,仍能选出Primary。
Arbiter本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入一个Arbiter节点,以提升复制集可用性。
Priority0:
Priority0节点的选举优先级为0,不会被选举为Primary。
比如你跨机房A、B部署了一个复制集,并且想指定Primary必须在A机房,这时可以将B机房的复制集成员Priority设置为0,这样Primary就一定会是A机房的成员。
说明 如果这样部署,最好将大多数节点部署在A机房,否则网络分区时可能无法选出Primary。
Vote0:
MongoDB 3.0里,复制集成员最多50个,参与Primary选举投票的成员最多7个,其他成员(Vote0)的vote属性必须设置为0,即不参与投票。
Hidden:
Hidden节点不能被选为主(Priority为0),并且对Driver不可见。
因Hidden节点不会接受Driver的请求,可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务。
Delayed:
Delayed节点必须是Hidden节点,并且其数据落后于Primary一段时间(可配置,比如1个小时)。
因Delayed节点的数据比Primary落后一段时间,当错误或者无效的数据写入Primary时,可通过Delayed节点的数据来恢复到之前的时间点。
无投票权的成员同时具有votes并 priority等于0:
|
|
副本集 Oplog
oplog(操作日志)是一个特殊的上限集合,它保留所有修改存储在数据库中的数据的操作的滚动记录。
MongoDB 在主节点上应用数据库操作,然后在主节点的 oplog 上记录这些操作。次要成员然后在异步过程中复制和应用这些操作。所有副本集成员都在 local.oplog.rs集合中包含 oplog 的副本,这允许它们维护数据库的当前状态。
为了便于复制,所有副本集成员都会向所有其他成员发送心跳(ping)。任何次要成员都可以从任何其他成员导入 oplog 条目。
oplog 中的每个操作都是幂等的。也就是说,oplog 操作无论对目标数据集应用一次还是多次都会产生相同的结果。
副本集的读写设置
-
Read Preference 默认情况下,复制集的所有读请求都发到Primary,Driver可通过设置Read Preference来将读请求路由到其他的节点。
- primary:默认规则,所有读请求发到Primary。
- primaryPreferred:Primary优先,如果Primary不可达,请求Secondary。
- secondary:所有的读请求都发到Secondary。
- secondaryPreferred:Secondary优先,当所有Secondary不可达时,请求Primary。
- nearest:读请求发送到最近的可达节点上(通过ping探测得出最近的节点)。
-
Write Concern(写关注) 默认情况下,Primary完成写操作即返回,Driver可通过配置Write Concern来设置写成功的规则,详情请参见Write Concern。
如下的write concern规则设置写必须在大多数节点上成功,超时时间为5秒。
|
|
上面的设置方式是针对单个请求的,也可以修改副本集默认的write concern,这样就不用单独设置每个请求。
|
|
分片 Sharding
分片是一种在多台机器上分布数据的方法。MongoDB 使用分片来支持具有非常大的数据集和高吞吐量操作的部署。
具有大型数据集或高吞吐量应用程序的数据库系统可能会挑战单个服务器的容量。例如,高查询率会耗尽服务器的 CPU 容量。大于系统 RAM 的工作集大小会加重磁盘驱动器的 I/O 容量。
解决系统增长的方法有两种:垂直扩展和水平扩展。
垂直扩展涉及增加单个服务器的容量,例如使用更强大的 CPU、添加更多 RAM 或增加存储空间量。可用技术的限制可能会限制单个机器对于给定的工作负载足够强大。此外,基于云的提供商具有基于可用硬件配置的硬上限。因此,垂直缩放有一个实际最大值。
水平扩展涉及划分系统数据集并在多个服务器上加载,添加额外的服务器以根据需要增加容量。虽然单台机器的整体速度或容量可能不高,但每台机器都处理整体工作负载的一个子集,可能比单台高速大容量服务器提供更好的效率。扩展部署的容量只需要根据需要添加额外的服务器,这可以比单机的高端硬件更低的总体成本。代价是基础设施和部署维护的复杂性增加。
MongoDB通过sharding支持水平扩展。
分片集群
一个 MongoDB分片集群由以下组件组成:
- shard:每个分片包含分片数据的一个子集。每个分片都可以部署为副本集。
- mongos:mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口。从 MongoDB 4.4 开始,mongos可以支持 对冲读取以最小化延迟。
- config servers:配置服务器存储集群的元数据和配置设置。
MongoDB 在集合级别对数据进行分片,将集合数据分布在集群中的各个分片上。
每一个分片(shard)是一个分区数据的逻辑集合。分片可能由单一服务器或者集群组成,我们推荐为每一个分片(shard)使用集群。
分片键
MongoDB 使用分片键将集合的文档分布在分片之间。分片键由文档中的一个或多个字段组成。
- 从 MongoDB 5.0 开始,您可以通过更改集合的分片键来重新分片集合。
- 从 MongoDB 4.4 开始,您可以通过向现有分片键添加一个或多个后缀字段来优化分片键。
- 在 MongoDB 4.2 及更早版本中,分片后无法更改分片键的选择。
文档的分片键值决定了它在分片中的分布。
Sharded Cluster Balancer
MongoDB 平衡器是一个后台进程,用于监控 每个分片上的块数。当给定分片上的块数达到特定迁移阈值时,平衡器会尝试在分片之间自动迁移块并达到每个分片相同数量的块。
分片集群的平衡过程对用户和应用层是完全透明的,尽管在过程发生时可能会有一些性能影响。
平衡器在配置服务器副本集 (CSRS) 的主服务器上运行。
Sharding 策略选择
Hashed Sharding
散列分片涉及计算分片键字段值的散列。然后根据散列的分片键值为每个块分配一个范围。
MongoDB 在使用散列索引解析查询时会自动计算散列值。应用程序不需要计算哈希。
虽然一系列分片键可能“接近”,但它们的散列值不太可能在同一个块上。基于散列值的数据分布有助于更均匀的数据分布,尤其是在分片键单调变化的数据集中。
但是,散列分布意味着对分片键的基于范围的查询不太可能针对单个分片,从而导致更多集群范围的 广播操作
Ranged Sharding
范围分片涉及根据分片键值将数据划分为范围。然后根据分片键值为每个块分配一个范围。
值“接近”的一系列分片键更有可能驻留在同一个块上。这允许有针对性的操作,因为mongos可以将操作路由到仅包含所需数据的分片。
远程分片的效率取决于选择的分片键。考虑不周的分片键会导致数据分布不均匀,这可能会抵消分片的一些好处或导致性能瓶颈。有关基于范围的分片,请参阅 分片键选择。
deploy shard cluster
config server replica set (CSRS)
|
|
|
|
|
|
Create the Shard Replica Sets
|
|
|
|
|
|
Start a mongos for the Sharded Cluster
|
|
Add Shards to the Cluster
|
|
Enable Sharding for a Database
|
|
MongoDB 组件
- mongod - The database server.
- mongos - Sharding router.
- mongosh - The database shell 替代就版本的 mongo 命令
MongoDB Tools Go 语言开发的命令行工具
- bsondump - display BSON files in a human-readable format
- mongoimport - Convert data from JSON, TSV or CSV and insert them into a collection
- mongoexport - Write an existing collection to CSV or JSON format
- mongodump/mongorestore - Dump MongoDB backups to disk in .BSON format, or restore them to a live database
- mongostat - Monitor live MongoDB servers, replica sets, or sharded clusters
- mongofiles - Read, write, delete, or update files in GridFS
- mongotop - Monitor read/write activity on a mongo server
使用场景
- 大数据
- 内容管理系统
- 移动端Apps
- 数据管理