《MongoDB管理与开发精要》——2.1节体系结构

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介: 本节书摘来自华章社区《MongoDB管理与开发精要》一书中的第2章,第2.1节体系结构,作者:红 丸,更多章节内容可以访问云栖社区“华章社区”公众号查看

2.1 体系结构
一个运行着的MongoDB数据库可以看作一个MongoDB Server,该Server由实例和数据库组成。一般情况下,一个MongoDB Server机器上包含一个实例和多个与之对应的数据库,但是在特殊情况下,如硬件投入成本有限或特殊的应用需求,也允许一个Server机器上有多个实例和多个数据库。
MongoDB中一系列物理文件(数据文件、日志文件等)的集合或与之对应的逻辑结构(集合、文档等)称为数据库。简单来说,数据库是由一系列与磁盘有关的物理文件组成的。
2.1.1 数据逻辑结构
MongoDB数据逻辑结构是面向用户的,用户使用MongoDB开发应用程序使用的就是逻辑结构。MongoDB逻辑结构是一种层次结构,如图2-1所示,主要由文档(document)、集合(collection)、数据库(database)组成。
文档、集合、数据库三部分的关系如下:

  • MongoDB的文档相当于关系数据库中的一条记录。
  • 多个文档组成一个集合,相当于关系数据库的表。
  • 多个集合逻辑上组织在一起就是数据库。
  • 一个MongoDB实例支持多个数据库。


79c66efacab10c356c86ea3fdf60219ebfe23814

2.1.2 数据存储结构
MongoDB存储数据的默认目录是/data/db,这个目录负责存储所有MongoDB的数据文件。在MongoDB内部,每个数据库都包含一个ns文件和一些数据文件,这些数据文件会随着数据量的增加而变得越来越多。例如,系统中有一个名为kon的数据库,那么构成kon数据库的文件就由kon.ns、kon.0、kon.1、kon.2 等组成,如下面的代码所示:

[root@localhost db]# ll /data/db/
总计 196844
-rw------- 1 root root 16777216 04-15 16:33 admin.0
-rw------- 1 root root 33554432 04-15 16:33 admin.1
-rw------- 1 root root 16777216 04-15 16:33 admin.ns
//下面4个是数据库的文件
-rw------- 1 root root 16777216 04-21 17:30 kon.0
-rw------- 1 root root 33554432 04-21 17:30 kon.1
-rw------- 1 root root 67108864 04-21 17:30 kon.2
-rw------- 1 root root 16777216 04-21 17:30 kon.ns
-rwxr-xr-x 1 root root        6 04-21 17:16 mongod.lock
-rw------- 1 root root 16777216 04-15 16:30 test.0
-rw------- 1 root root 33554432 04-15 16:30 test.1
-rw------- 1 root root 16777216 04-15 16:30 test.ns
drwxr-xr-x 2 root root     4096 04-21 17:30 _tmp

MongoDB内部有预分配空间的机制,每个预分配的文件都用0进行填充,这使MongoDB始终保持额外的空间和空余的数据文件,有效避免了由于数据暴增而带来的磁盘压力过大的问题。如果想避免预分配,可以在mongod启动时,加上参数“--noprealloc”,这样,系统的预分配机制就失效了。
由于表中数据量的增加,数据文件每分配一次,它的大小都会是上一个数据文件大小的2倍,每个数据文件最大2GB,这样的机制有利于防止较小的数据库浪费过多的磁盘空间,同时又能保证较大的数据库有相应的预留空间使用。
数据库的每张表都对应一个命名空间,每个索引也有对应的命名空间,这些命名空间的元数据都集中在“*.ns”文件中。
图2-2是预分配机制的示意图,kon数据库包含3个文件,用于存储表和索引数据,kon.2文件属于预分配的空文件。kon.0和kon.1这两个数据文件分为相应的盘区对应不同的命名空间。


62e56dc4f158b67053cafb28dd5c6b00ac08d964

图2-2显示了命名空间和盘区的关系。每个命名空间可以包含多个不同的盘区,这些盘区并不是连续的。与数据文件的增长相同,每一个命名空间对应的盘区大小也是随着分配的次数不断增长的,这样做的目的不仅仅是为了平衡命名空间浪费的磁盘空间,也是为了保持某一个命名空间中数据的连续性。
图2-2中还有一个需要注意的命名空间:$freelist,这个命名空间用于记录不再使用的盘区(被删除的collection或索引)。每当命名空间需要分配新的盘区的时候,都会先查看$freelist是否有大小合适的盘区可以使用,这样就能回收空闲的磁盘空间。
2.1.3 日志系统
任何一种数据库都有各种各样的日志,MongoDB也不例外。MongoDB中有几种日志,分别是系统日志、Journal日志、oplog主从日志、慢查询日志等。这些日志记录着MongoDB数据库不同方面的踪迹。下面分别介绍这4种日志。

  1. 系统日志
    系统日志在MongoDB数据库中很重要,它记录着MongoDB启动和停止的操作,以及服务器在运行过程中发生的任何异常信息。

配置系统日志的方法比较简单,只需要在启动mongod时指定一个logpath参数即可,例如:

mongod -logpath=/data/db/log/serverlog.log -logappend

系统日志会向logpath指定的文件中持续追加。

  1. Journal日志
    Journal日志通过预写式的redo日志为MongoDB增加了额外的可靠性保障。开启该功能时,数据的更新会先写入Journal日志,定期集中提交(目前是每100ms提交一次),然后在真实数据上执行这些变更。如果服务器安全关闭,日志会被清除。在服务器启动时,如果存在 Journal日志,则会执行提交。这保证了那些已经写入Journal日志但在服务器崩溃前还没有提交的操作能在用户连接服务器前被执行,两次提交之间的 100ms时间窗口,在未来的版本中有望被缩小。

启用数据库的Journal功能非常简单,只需在mongod后面指定journal参数即可,例如:

mongod -journal

这样,系统的Journal信息都会放到数据库目录(默认是/data/db/)的journal文件夹中。

  1. oplog主从日志
    MongoDB的高可用复制策略中有一种叫做Replica Sets。Replica Sets复制过程中一个服务器充当主服务器,而一个或多个服务器充当从服务器,主服务器将更新写入一个本地的collection中,这个collection记录着发生在主服务器的更新操作,并将这些操作分发到从服务器上。

这个日志是一个Capped Collection(第5章会专门讲解这个概念)且有大小之分,所以最好在mongod启动时配置好大小(单位:MB)。例如以下语句:

mongod - oplogSize=1024
  1. 慢查询日志
    慢查询日志记录了执行时间超过所设定时间阈值的操作语句。慢查询日志对于发现性能有问题的语句很有帮助,建议开启此功能并经常分析该日志的内容。

要想配置这个功能只需要在mongod启动时指定profile参数即可。例如,想要将超过5秒的操作都记录,可以使用如下语句:
mongod --profile=1 --slowms=5
系统运行一段时间后, 可以通过查看db.system.profile这个collection来获取慢日志信息。
2.1.4 元数据的存储
元数据是一个预留空间,在对数据库或应用程序结构执行修改时,其内容可以由数据库自动更新。元数据是系统中各类数据描述的集合,是执行详细的数据收集和数据分析的主要途径。
元数据最重要的作用是作为分析阶段的工具。任何字典最重要的用途都是查询,在结构化分析中,元数据的作用是给数据流图上的每个节点加以定义和说明。换句话说,数据流图上所有节点的定义和解释的集合就是元数据,而且在元数据中建立严密一致的定义有助于提高需求分析人员和用户沟通的效率。
MongoDB跟其他数据库一样,有专门存储元数据的系统表。.system.* namespaces是一个特殊的对象,其中存储数据库的系统信息,通过这些表用户可以大概了解系统中数据库对象的情况,例如:

  • system.namespaces (存储命名空间信息)
  • system.indexes (存储索引信息)
  • system.profile (存储优化器信息)
  • system.users (存储用户信息)
  • local.sources (存储复制集的配置信息和状态信息)
    其他的命名空间和索引信息都存储在database.ns文件中,并且对用户是封装的。

注意 “$”是一个保留字符,不要在命名空间和列名中使用它。
2.1.5 数据类型
MongoDB中的文档可以理解为JSON 类型的对象。JSON的格式很简单,只支持6种数据类型,容易理解、解析和记忆。
MongoDB在采取了JSON键值对的同时,还支持很多额外的数据类型。虽然不同的语言支持的类型有所不同,但还是有很多共同的类型,如表2-2所示。
表2-2 MongoDB支持的数据类型


963fcdab1303827d36858bb87ab1a4f2eb6dbd31

尽管这些类型在一般场合下是足够的,但还是存在其他很多的数据类型JSON是不支持的。例如JSON 没有日期类型,对日期的处理要烦琐一些;它有数字类型,但无法区分浮点型和整型的数值,更不用说严格区分32位和64位了;此外,正则表达式和函数类型也无法表现。
接下来将介绍MongoDB的主要数据类型。

  1. number
    JavaScript 有一个number 类型,对应的MongoDB 有3个数据类型(4字节整数、8字节整数、8字节浮点数)。Shell 中的数字默认为浮点数。这意味着,如果从数据库取出一个4字节整数存进去,即使没有改变它,也会变成8字节浮点数。因此,建议不要把整个document插入到MongoDB中。

另外的一个问题是,一个8字节的整数是不能用8字节的浮点数来表示的。因此,如果保存一个8字节整数,要在Shell里查看它,Shell 将会显示为一个嵌套的document来精确地描述它。在Shell 里面查看的代码如下:

> doc = db.nums.findOne()
{
"_id" : ObjectId("4c0beecfd096a2580fe6fa08"), 
"myInteger" : {"floatApprox" : 3}
}

这个数字在数据库里不会改变,这个嵌套的文档只是用Shell显示一个8字节整数的浮点近似值,并且只有一个key。
如果插入一个不能用浮点数来精确表示的8字节整数,Shell会加上2个key:top 和bottom,分别代表高位和低位的32位值。例如9223372036854775807,如下面的代码所示:

> db.nums.findOne()
{
"_id" : ObjectId("4c0beecfd096a2580fe6fa09"), 
"myInteger" : {"floatApprox" : 9223372036854776000, 
"top" : 2147483647,"bottom" : 4294967295}
}
  1. date
    JavaScript的数据类型中,Date 对象用来表示MongoDB 的日期类型。创建日期对象要用 new Date(),而不是用Date(),后者只是返回一个字符串,并不是一个Date对象,如下面的代码所示:
//日期类型
> Date()
Sun Jul 01 2010 16:17:26 GMT+0800 (CST)
//日期对象
> new Date()
ISODate("2010-07-01T08:17:29.752Z")
//经查看后,确认是一个对象
> typeof(new Date())
Object
//经查看后,确认是一个类型
> typeof(Date())
string
>

这不是MongoDB的问题,因为JavaScript就是这样处理的,如果不注意就会弄混字符串和日期类型,在删除、更新查询时造成问题。
Shell里用本地区域设置来显示日期,但在数据库里只是记录从纪元开始到现在所过去的毫秒数,所以并没有把区域设置保存进去。

  1. array
    数组的值可以进行有序处理,类似于列表、堆栈、队列;也可以无序处理,类似于集合。如下面的代码所示:

{"things" : ["pie", 3.14]}
这里看到,数组成员类型是允许不一样的,可以是任意的类型,包括嵌套的数组。
MongoDB的一个好处是,它理解数组里的结构并知道怎么进入内部执行操作,所以可以执行查询操作和索引操作。例如上例中,MongoDB可以查询所有文档中things包括3.14的文档,也可以为things建立索引以提高查询速度。MongoDB还允许数组内部元素的原子更新,例如把pie改为pi。

  1. embedded document
    嵌套文档就是将一个key 的值表示为另外一个文档,这样可以让document 看起来比一个平面的结构更自然。

例如,用一个文档表示一个人,其中有他的地址信息,嵌套表示如下面的代码所示:

{
"name" : "John Doe", "address" : {"street" : "123 Park Street", 
"city" : "Anytown","state" : "NY"}
}

跟数组一样,MongoDB也理解嵌套文档的结构,可以执行内部的查询和更新。
如上所示,嵌套文档改变了处理数据的方式。传统数据库中这两个信息将会存放在两个表的两条记录中,但MongoDB可以用一个文档来表示。从另一方面来看,这种方式不是很正规,会造成数据冗余。假设一个地址两个人使用,那么关系数据库里可以用一条记录表示,通过join来关联,但MongoDB只能分别存放、分别更新。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
5月前
|
存储 NoSQL MongoDB
MongoDB 助力移动式汽车保养运营模式优化,将开发请求减少 90%
MongoDB针对初级,中级及熟练的技术开发人员推出系列技术文章与行业案例。深入浅出地剖析MongoDB产品基础原理,使用技巧,典型行业场景及应用,还有Code Demo及线上线下活动推荐!
4846 1
MongoDB 助力移动式汽车保养运营模式优化,将开发请求减少 90%
|
5月前
|
存储 NoSQL 算法
国泰航空利用MongoDB和Device Sync开发飞机上的移动应用
作为中国香港本土的航空公司,国泰航空提供的客运和货运服务覆盖全球不同目的地。国泰航空清楚这个流程及其他许多关键业务级流程都需要进行数字化转型。国泰航空积极寻找可提高其运营效率、工作效率和可持续性能力的重大机会,优先开发创新性的数字解决方案。
国泰航空利用MongoDB和Device Sync开发飞机上的移动应用
|
8月前
|
NoSQL Linux MongoDB
开发中MongoDB遇到的各种问题
开发中MongoDB遇到的各种问题
128 0
|
8月前
|
存储 NoSQL MongoDB
如何用MongoDB来进行开发
如何用MongoDB来进行开发
164 0
|
8月前
|
缓存 NoSQL Java
Spring Session MongoDB管理会话
Spring Session MongoDB管理会话
62 0
|
10月前
|
NoSQL 前端开发 JavaScript
MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(8)-Ant Design Blazor前端框架搭建
MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(8)-Ant Design Blazor前端框架搭建
124 0
|
10月前
|
NoSQL MongoDB 数据库
mongodb用户权限管理
用户权限管理简要说明
623 0
|
12月前
|
存储 NoSQL Cloud Native
【活动报名】阿里云MongoDB在游戏行业的开发实践
本期研讨会将MongoDB本身特性与游戏行业的场景相结合,简述阿里云数据库MongoDB版如何助力游戏行业应用的开发与架构优化,从而助力行业的发展,并分享相关案例作为参考。
|
存储 运维 NoSQL
阿里云数据库MongoDB助力南瓜电影提升开发效率——为超8000万观众量身打造沉浸式体验
阿里云数据库MongoDB助力南瓜电影提升开发效率——为超8000万观众量身打造沉浸式体验
257 0