MongoDB 入门实战(1)--简介

1、什么是 MongoDB

MongoDB 是一个基于分布式文件存储的数据库,由 C++ 语言编写,旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

MongoDB 入门实战(1)--简介

2、MongoDB 概念

2.1、数据库

MongoDB 的单个实例可以容纳多个独立的数据库,每个数据库都有自己的集合和权限。

数据库通过名字来标识;数据库名为 UTF-8 字符串,需满足以下条件:

  • 不能是空字符串("")。
  • 不得含有 ' '(空格)、.、$、/、\ 和 \0 (空字符)。
  • 应全部小写。
  • 最多 64 字节。

内置数据库:

  • admin:管理数据库。将一个用户添加到这个数据库,则这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如关闭服务器。
  • local:这个数据永远不会被复制,可以用来存储限于本地单台服务器的集合。
  • config:当 MongoDB 使用分片时,config 数据库用于保存分片的相关信息。

2.2、文档(Document)

文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。一个简单的文档例子如下:

{"name":"李白", "age":30}

文档有如下特性:

  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB 区分类型和大小写。
  4. MongoDB 的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意 UTF-8 字符。

文档键命名规范:

  • 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
  • .和$有特别的意义,只有在特定环境下才能使用。
  • 以下划线"_"开头的键是保留的(不是严格要求的)。

2.3、集合

集合就是文档组,类似于关系数据库中的表。集合没有固定的结构,可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

比如,我们可以将以下不同数据结构的文档插入到同一集合中:

{"name":"杜甫", "age":29}
{"name":"李白", "age":30}
{"name":"白居易", "age":31, "height":175}

集合名的命名规范:

  • 集合名不能是空字符串""。
  • 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
  • 集合名字不能含有保留字符;集合名中不要有$。

Capped collections 是固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。和标准的集合不同,你必须要显式的创建一个 capped collection,指定一个集合的大小,单位是字节。固定集合的数据存储空间值提前分配的。固定集合不能删除一个文档,可以使用 drop() 方法删除整个集合。

2.4、MondoDB 和 RDBMS 的对比

RDBMS 术语/概念 MongoDB 术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins $lookup  
primary key primary key 主键,MongoDB 自动将 _id 字段设置为主键
transaction transaction  
group by aggregation  

2.5、MondoDB 数据类型

数据类型 对应数字标识 别名 描述  
Double 1 double 双精度浮点值。  
String 2 string 字符串。在 MongoDB 中,UTF-8 编码的字符串才是合法的。  
Object 3 object 用于内嵌文档  
Array 4 array 数组  
Binary data 5 binData 二进制数据  
Undefined 6 undefined 已过时  
ObjectId 7 objectId 对象 ID  
Boolean 8 bool 布尔值  
Date 9 date 日期  
Null 10 null 空值  
Regular Expression 11 regex 正则表达式  
DBPointer 12 dbPointer 已过时  
JavaScript 13 javascript JavaScript 代码  
Symbol 14 symbol 符号,已过时  
JavaScript code with scope 15 javascriptWithScope 已过时  
32-bit integer 16 int 整形  
Timestamp 17 timestamp 时间戳  
64-bit integer 18 long 长整型  
Decimal128 19 decimal 浮点型,3.4 中新增  
Min key -1 minKey 最小 key,主要是内部使用  
Max key 127 maxKey 最大 key,主要是内部使用  

下面介绍几个重要的数据类型。

2.5.1、ObjectId

ObjectId 类似唯一主键,可以很快的生成和排序,包含 12 bytes:

  • 前 4 个字节表示 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚 8 小时
  • 接下来的 3 个字节是机器标识码
  • 紧接的两个字节由进程 id 组成 PID
  • 最后三个字节是随机数

MongoDB 入门实战(1)--简介

 MongoDB 中的文档必须有一个 _id 键,这个键的值可以是任何类型,默认是 ObjectId 对象。由于 ObjectId 中保存了创建的时间戳,所以不需要为文档保存时间戳字段,可以通过 getTimestamp 函数来获取文档的创建时间:

> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate("2022-01-07T01:45:50Z")

2.5.2、字符串

字符串都是 UTF-8 编码。

2.5.3、时间戳

时间戳类型用于 MongoDB 内部使用,与普通的日期类型不相关;时间戳值是一个 64 位的值:

  • 前32位是一个 time_t 值(与 Unix 新纪元相差的秒数)
  • 后32位是在某秒中操作的一个递增的序数

在单个 mongod 实例中,时间戳值通常是唯一的。

2.5.4、日期

表示当前距离 Unix 新纪元(1970年1月1日)的毫秒数。日期类型是有符号的,负数表示 1970 年之前的日期。

> var mydate1 = new Date()
> mydate1
ISODate("2022-01-07T02:26:33.011Z")
> 
> var mydate2 = ISODate()
> mydate2
ISODate("2022-01-07T02:26:47.088Z")

3、MongoDB 架构模式

3.1、单机模式

该模式只安装一个节点,一般用于测试学习。

3.2、Master-Slave 模式

 MongoDB 入门实战(1)--简介

主从架构一般用于备份或者做读写分离。一般有一主一从设计和一主多从设计。由两种角色构成:

主(Master):可读可写,当数据有修改的时候,会将 oplog 同步到所有的 Salve 上去。
从(Slave):只读,从 Master 同步数据。

注:新版的 MongoDB 已经不支持这种模式了。

3.3、Replica Set 模式

MongoDB 入门实战(1)--简介

Replica Set 提供了数据的冗余备份,在多个服务器上存储数据副本,提高了数据的可用性, 保证了数据的安全性。Replica Set 包含三类角色:

(1)主节点(Primary)
接收所有的写请求,然后把修改同步到所有 Secondary。一个 Replica Set 只能有一个 Primary 节点,当 Primary 挂掉后,其他 Secondary 或者 Arbiter 节点会重新选举一个主节点。默认读请求也发到Primary 节点处理,如果需要发到 Secondary 可修改下客户端的连接配置。
(2)副本节点(Secondary)
与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。
(3)仲裁者(Arbiter)
不保存数据,不参与选主,只进行选主投票。使用 Arbiter 可以减轻数据存储的硬件需求。

Replica Set 中 Secondary 宕机,不受影响,若 Primary 宕机,会重新选主:

MongoDB 入门实战(1)--简介

3.3、Sharding 模式

3.3.1、分片架构

MongoDB 入门实战(1)--简介

在 MongoDB 中存在另一种集群,就是分片技术,通过在多台机器上分片存储数据,可以满足 MongoDB 数据量大量增长的需求。分片技术中包含的组件:

A.数据分片(Shards):用来存数据,可以是一个单独的mongod实例,也可以是一个副本集。生产环境下 Shard 一般是一个Replica Set,防止该数据片的单点故障。
B.路由(Routers):前端路由,客户端由此接入,让整个集群看上去像单一数据库,应用可以透明使用。路由为 mongos实例,一个 Sharding 集群,可以有一个 mongos,也可以有多 mongos 以减轻客户端请求的压力。
C.配置服务器(Config Servers):保存集群的元数据信息(路由、分片),它也是一个副本集。

Sharding 分片技术高可用的架构图如下:

MongoDB 入门实战(1)--简介

3.3.2、分片算法

基于分片切分后的数据块称为 chunk,一个分片后的集合会包含多个 chunk,每个 chunk 位于哪个分片(Shard) 记录在 Config Server(配置服务器)上。Mongos 在操作分片集合时,会自动根据分片键找到对应的 chunk,并向该 chunk 所在的分片发起操作请求。

数据是根据分片策略来进行切分的,分片策略由分片键(ShardKey)+分片算法(ShardStrategy)组成。MongoDB 支持两种分片策略:

  • 范围分片

MongoDB 入门实战(1)--简介

如上图所示,假设集合根据 x 字段来分片,x 的取值范围为[minKey, maxKey],将整个取值范围划分为多个 chunk,每个 chunk(默认配置为64MB)包含其中一小段的数据:如 Chunk1 包含 x 的取值在[minKey, -75)的所有文档,而 Chunk2 包含x取值在 [-75, 25) 之间的所有文档,Chunk3、Chunk4 依次类推。

范围分片能很好的满足范围查询的需求,比如想查询 x 的值在[-30, 10]之间的所有文档,这时 Mongos 直接能将请求路由到 Chunk2,就能查询出所有符合条件的文档。 范围分片的缺点在于,如果 ShardKey 有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个 chunk,无法扩展写的能力,比如使用 _id 作为 ShardKey,而 MongoDB 自动生成的 id 高位是时间戳,是持续递增的。

  • 哈希分片

MongoDB 入门实战(1)--简介

 Hash 分片是根据用户的 ShardKey 先计算出 hash 值(64bit整型),再根据 hash 值按照范围分片的策略将文档分布到不同的 chunk。由于 hash 值的计算是随机的,因此 Hash 分片具有很好的离散性,可以将数据随机分发到不同的 chunk 上。 Hash 分片可以充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要查询多个 chunk 才能找出满足条件的文档。

3.3.3、分片均衡

数据是分布在不同的 chunk上的,而 chunk 则会分配到不同的分片上,那么如何保证分片上的数据(chunk) 是均衡的?有如下两种情况:

A. 全预分配,chunk 的数量和 shard 都是预先定义好的,比如 10 个shard,存储 1000 个 chunk,那么每个 shard 分别拥有100个 chunk。此时集群已经是均衡的状态(这里假定)。
B. 非预分配,这种情况则比较复杂,一般当一个 chunk 太大时会产生分裂(split),不断分裂的结果会导致不均衡;或者动态扩容增加分片时,也会出现不均衡的状态。 这种不均衡的状态由集群均衡器进行检测,一旦发现了不均衡则执行 chunk 数据的搬迁达到均衡。

MongoDB 的数据均衡器运行于 Primary Config Server(配置服务器的主节点)上,而该节点也同时会控制 Chunk 数据的搬迁。

MongoDB 入门实战(1)--简介

对于数据的不均衡是根据两个分片上的 Chunk 个数差异来判定的,阈值对应表如下:

Number of Chunks Migration Threshold
Fewer than 20 2
20-79 4
80 and greater 8

MongoDB 的数据迁移对集群性能存在一定影响,这点无法避免,目前的规避手段只能是将均衡时间放到业务闲时段。

4、MongoDB 用户管理

在 MongoDB 里面用户是属于数据库的,不同的数据库可以拥有不同的用户。用户通过角色来控制权限,角色也是与数据库关联的;设置角色时需要同时设置对应的数据库。MongoDB 中内置了一些角色:

1.Database User Roles(数据库用户角色)
  Read:允许从指定数据库读数据
  readWrite:允许从指定数据库读写数据
2.Database Administration Roles(数据库管理角色)
  dbAdmin:数据库管理功能
  dbOwner: 该角色是 readWrite, dbAdmin 和 userAdmin 三个角色的集合
  userAdmin:在当前数据库上创建、修改角色和用户
3.Cluster Administration Roles(集群管理角色)
  clusterAdmin:该角色是 clusterManager, clusterMonitor 和 hostManager 三个角色的集合
  clusterManager:提供管理和监视的权限
  clusterMonitor:提供只读的监视的权限
  hostManager:提供监视和管理服务器的权限
4.Backup and Restoration Roles(备份恢复角色)
  backup:备份
  restore:还原数据
5.All-Database Roles(针对所有数据库的角色,除了 local 和 config 数据库)
  readAnyDatabase:从所有数据(除了 local 和 config)读取数据
  readWriteAnyDatabase:从所有数据(除了 local 和 config)读写取数据
  userAdminAnyDatabase:对所有数据(除了 local 和 config)提供与 userAdmin 一样的权限
  dbAdminAnyDatabase:对所有数据(除了 local 和 config)提供与 dbAdmin 一样的权限
6.Superuser Roles(超级角色)
  root:拥有任何数据库的任何权限
7.Internal Role
  __system:对数据库中的任何对象具有任何操作的权限

创建用户方法如下:

db.createUser({
  user: 'test', 
  pwd: '123456',
  roles:[{
    role: 'readWrite', 
    db: 'test'
  }]
})

如需启用权限认证,可在 MongoDB 启动时增加 --auth 参数。

 

 

 

参考:
https://www.runoob.com/mongodb/mongodb-tutorial.html
https://www.cnblogs.com/littleatp/p/11675233.html


 

上一篇:第 38 题:apply、call 和 bind 是什么?哪些区别?


下一篇:为什么我越来越喜欢画低保真原型?