0


MongoDB 架构

优质博文:IT-BLOG-CN

一、存储数据格式

MongoDB

作为主流的

NoSQL

数据库之一,使用面向文档的数据存储方式,将数据以

JSON

和

BSON

的方式存储在磁盘中。

BSON Binary JSON

是一种基于

JSON

的二级制序列化格式,用于

MongoDB

存储文档并进行远程过程调用,作为网络数据交互的一种存储形式,类似于

Protocol Buffer

和

Thrift

。

BSON

是一种

schema-less

的存储形式,它的优点是灵活性高,但它的缺点是空间利用率不是很理想

一个

Collection

包含一个

JSON

和

BSON

文档:

JSON

和

BSON

之间最主要的区别如下表所示:

JSON
BSON
JSON

是

javascript

对象表示法

BSON

是二进制

JSON

是一种轻量级的、基于文本的、开放的数据交换格式是一种二进制序列化文档格式

JSON

包含一些基本数据类型,如字符串、数字、布尔值、空值除了支持

JSON

中的类型外,

BSON

还包含一些额外的数据类型,例如日期

Date

、二进制

BinData

等

AnyDB

、

Redis

等数据库将数据存储为

JSON

格式

MongoDB

中将数据存储为

BSON

格式主要用于传输数据主要用于存储数据没有响应的编码和解码技术有专用的编码和解码技术如果想从

JSON

文件中读取指定信息,需要遍历整个数据在

BSON

中,可以使用索引跳过到指定内容

JSON

格式不需要解析,因为它是人类可读的

BSON

需要解析,因为它是二进制的

JSON

是对象和数组的组合,其中对象是键值对的集合,而数组是元素的有序列表

BSON

是二进制数据,在其中可以存储一些附加信息,例如字符串长度、对象类型等

二、架构视图

MongoDB

与

MySQL

中的架构相似,底层都使用了可插拔的存储引擎以满足用户的不同需要。用户可以根据程序的数据特征选择不同的存储引擎,在最新版本的

MongoDB

中使用了

WiredTiger

作为默认的存储引擎,

WiredTiger

提供了不同粒度的并发控制和压缩机制,能够为不同种类的应用提供了最好的性能和存储率。

在存储引擎上层的就是

MongoDB

的数据模型和查询语言了,由于

MongoDB

对数据的存储与

RDBMS:Relational Database Management System

有较大的差异,所以它创建了一套不同的数据模型和查询语言。虽然

MongoDB

查询语言非常强大,支持的功能也很多,同时也是可编程的,不过其中包含的内容非常繁杂、

API

设计也不是非常优雅,所以还是需要一些学习成本的,对于长时间使用

MySQL

的开发者肯定会有些不习惯。

**数据模型

Data Model

:**
【1】内嵌: 内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。

MongoDB

的文档结构允许一个字段或者一个数组内的值作为一个嵌套的文档。通常如下场景选择内嵌:
■ 数据对象之间有包含关系,一般是数据对象之间有一对多或者一对一的关系。
■ 需要经常一起读取的数据。
■ 有

map-reduce/aggregation

需求的数据放在一起,这些操作都只能操作单个

collection

。
【2】引用: 引用方式通过存储数据引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引用来访问相关数据。通常如下场景选择内嵌引用:
■ 当内嵌数据会导致很多数据的重复,并且读性能的优势又不足于覆盖数据重复的弊端。
■ 需要表达比较复杂的多对多关系的时候。
■ 大型层次结果数据集嵌套不要太深。

三、存储引擎

存储引擎是

MongoDB

的核心组件,负责管理数据如何存储在硬盘和内存上。

MongoDB

支持的存储引擎有:

MMAPv1

、

WiredTiger

、

InMemory

。

InMemory

存储引擎用于将数据只存储在内存中,只将少量的元数据

meta-data

和诊断日志

Diagnostic

存储到硬盘文件中,由于不需要

Disk

的

IO

操作,就能获取所需的数据,

InMemory

存储引擎大幅度降低了数据查询的延迟

Latency

。从

mongodb3.2

开始默认的存储引擎是

WiredTiger

,

3.2

版本之前的默认存储引擎是

MMAPv1

,

mongodb4.x

版本不再支持

MMAPv1

存储引擎。

storage:journal:enabled:truedbPath: /data/mongo/ 
    #是否一个库一个文件夹 directoryPerDB:true##数据引擎 engine: wiredTiger 
    ##WT引擎配置 WiredTiger:engineConfig:##WT最大使用cache(根据服务器实际情况调节) cacheSizeGB:2##是否将索引也按数据库名单独存储 directoryForIndexes:true 
            journalCompressor:none (默认snappy) 
    ##表压缩配置 collectionConfig:blockCompressor: zlib (默认snappy,还可选none、zlib) 
    ##索引配置 indexConfig:prefixCompression:true

WiredTiger优势

【1】文档空间分配方式:

WiredTiger

使用的是

BTree

存储;

MMAPV1

线性存储需要

Padding

;
【2】并发级别:

WiredTiger

文档级别锁;

MMAPV1

引擎使用表级锁;
【3】数据压缩:

snappy

默认和

zlib

,相比

MMAPV1

无压缩空间节省数倍;
【4】内存使用:

WiredTiger

可以指定内存的使用大小,从

MongoDB 3.2

版本开始,

WiredTiger

内部缓存的使用量,默认值是:

1GB

或

60%of RAM - 1GB

,取两值中的较大值(不同版本会有区别,具体参考版本配置文件说明);文件系统缓存的使用量不固定,

MongoDB

自动使用系统空闲的内存;
**【5】

Cache

使用:**

WT

引擎使用了二阶缓存

WiredTiger Cache

,

File System Cache

来保证

Disk

上的数据的最终一致性。而

MMAPv1

只有

journal

日志;
【6】文档级别的锁:

MongoDB

在执行写操作时,

WiredTiger

在文档级别进行并发控制,就是说,在同一时间,多个写操作能够修改同一个集合中的不同文档;当多个写操作修改同一个文档时,必须以序列化方式执行;这意味着,如果该文档正在被修改,其他写操作必须等待,直到在该文档上的写操作完成之后,其他写操作相互竞争,获胜的写操作在该文档上执行修改操作;
【7】检查点机制: 类似关系数据库的

CheckPoint

,在

Checkpoint

操作开始时,

WiredTiger

提供指定时间点

point-in-time

的数据库快照

Snapshot

,该

Snapshot

呈现的是内存中数据的一致性视图。当向

Disk

写入数据时,

WiredTiger

将

Snapshot

中的所有数据以一致性方式写入到数据文件中。同样

MongoDB

借助

Journal

日志文件也可以还原数据;

【1】

WiredTiger.basecfg

: 存储基本配置信息,与

ConfifigServer

有关系;
【2】

WiredTiger.lock

: 定义锁操作;
【3】

table*.wt

: 存储各张表的数据;
【4】

WiredTiger.wt

: 存储

table*

的元数据;
【5】

WiredTiger.turtle

: 存储

WiredTiger.wt

的元数据;
【6】

journal

: 存储

WAL(Write Ahead Log)

;

WiredTiger存储引擎实现原理

Transport Layer

是处理请求的基本单位。

Mongo

有专门的

listener

线程,每次有连接进来,

listener

会创建一个新的线程

conn

负责与客户端交互,它把具体的查询请求交给

network

线程,真正到数据库里查询由

TaskExecutor

来进行。

写请求:

WiredTiger

的写操作会默认写入

Cache

,并持久化到

WAL (Write Ahead Log)

,每

60s

或

Log

文件达到

2G

做一次

checkpoint

(当然我们也可以通过在写入时传入

j: true

的参数强制

journal

文件的同步,

writeConcern: { w: , j: , wtimeout: })

产生快照文件。

WiredTiger

初始化时,恢复至最新的快照状态,然后再根据

WAL

恢复数据,保证数据的完整性。

Cache

是基于

BTree

的,节点是一个

page

,

rootpage

是根节点,

internal page

是中间索引节点,

leaf page

真正存储数据,数据以

page

为单位读写。

WiredTiger

采用

Copy on write

的方式管理写操作

insert、update、delete

,写操作会先缓存在

cache

里,持久化时,写操作不会在原来的

leaf page

上进行,而是写入新分配的

page

,每次

checkpoint

都会产生一个新的

rootpage

。

checkpoint

流程:
【1】对所有的

table

进行一次

checkpoint

,每个

table

的

checkpoint

的元数据更新至

WiredTiger.wt

【2】对

WiredTiger.wt

进行

checkpoint

,将该

tablecheckpoint

的元数据更新至临时文件

WiredTiger.turtle.set

【3】将

WiredTiger.turtle.set

重命名为

WiredTiger.turtle

【4】上述过程如果中间失败,

WiredTiger

在下次连接初始化时,首先将数据恢复至最新的快照状态,然后根据

WAL

恢复数据,以保证存储可靠性

Journaling:

在数据库宕机时,为保证

MongoDB

中数据的持久性,

MongoDB

使用了

Write Ahead Logging

向磁盘上的

journal

文件预先进行写入。除了

journal

日志,

MongoDB

还使用检查点

checkpoint

来保证数据的一致性,当数据库发生宕机时,我们就需要

checkpoint

和

journal

文件协作完成数据的恢复工作。
【1】在数据文件中查找上一个检查点的标识符;
【2】在

journal

文件中查找标识符对应的记录;
【3】重做对应记录之后的全部操作;

丢数据的情况: 写入数据时,引擎内部是先将数据存在内存中,每隔

60s

或内存存储容量达到

2G

后提交一次到磁盘中,因此在这

60s

期间如果机器宕机,则有极大的可能性会丢失数据

不丢数据的情况: 写入数据时,引擎内部是先将数据存在内存中,同时也会写一份操作日志到内存中,该日志会每个

100ms

持续化到磁盘文件,这种日志成为

Journaling

。

Journaling

类似于关系数据库中的事务日志。

Journaling

能够使

MongoDB

数据库由于意外故障后快速恢复。

MongoDB2.4

版本后默认开启了

Journaling

日志功能,

mongod

实例每次启动时都会检查

journal

日志文件看是否需要恢复。由于提交

journal

日志会产生写入阻塞,所以它对写入的操作有性能影响,但对于读没有影响。

四、写入策略

MongoDB

的写入策略有多种方式,写入策略是指当客户端发起写入请求后,数据库什么时候给应答,

MongoDB

有三种处理策略:客户端发出去的时候,服务器收到请求的时候,服务器写入磁盘的时候。

【1】

Unacknowledged

:客户端发出请求丢到

socket

的时候就收到响应,这个时候客户端不需要等服务器的应答,但是的本地的驱动还是尽可能的通知客户端网络的异常,这和客户端操作系统的配置有关。

【2】

Acknowledged

:这种方式客户端发送接口会等待服务器给的确认,这种方式一定能确保服务器收到了客户端的请求,并且当服务器能够异常时,响应客户端。

【3】

Journaled

:

Journaled

方式相比

Acknowledged

的方式是要保证服务器端已经写入到硬盘文件了。对于

Acknowledged

的方式有可能服务收到请求数据相应客户端后的一瞬间当机了,这个数据就丢失了,但是对于

Journaled

方式,服务器保证写入到磁盘后再相应客户端,即使当机了,也不会导致数据丢失。

【4】

Replica Acknowledged

:这个方式和

Acknowledged

是一样的意思,适用于

Replica sets

模式。

Acknowledged

模式下只有一台机器收到了请求就返回了,对于复制集模式有多台机器的情况,可以要求有多台机器收到写入请求后再相应客户端。这种更安全,但是导致了客户端耗时增加,所以要结合自己的场景设置合适的策略。

可以通过下面的方式设置默认的策略,

majority

表示多数节点写入成功后才相应客户端,也可以替换成具体的数子,比如

w:2

表示至少写入

2

个节点才返回。

wtimeout

表示超时时间,还有一个参加

j

可以设置

true

,

false

表示是否是写入日志才返回。

cfg = rs.conf()
cfg.settings.getLastErrorDefaults ={ w:"majority", wtimeout:5000}
rs.reconfig(cfg)

也可以通过客户端来指定具体的策略,如下: 至少要写入两个节点,超时时间是

5s
db.products.insert({ item:"envelopes", qty :100, type:"Clasp"},{ writeConcern:{ w:2, wtimeout:5000}})

如果复制集是

3

台机器,写入两台机器,流程如下:
在这里插入图片描述


本文转载自: https://blog.csdn.net/zhengzhaoyang122/article/details/129766302
版权归原作者 程序猿进阶 所有, 如有侵权,请联系我们删除。

“MongoDB 架构”的评论:

还没有评论