当前位置:网站首页>MongoDB内部的存储原理
MongoDB内部的存储原理
2022-07-07 11:17:00 【cui_yonghua】
基础篇(能解决工作中80%的问题):
进阶篇:
其它:
存储引擎
本文介绍默认存储引擎WiredTiger
WiredTiger架构
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m6gvgNNr-1657024774196)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1226)]](/img/bc/7901f9639b2fbf4f0d86e4d0168dd9.png)
WiredTiger的写操作会先写入Cache,并持久化到WAL(Write ahead log),每60s会做一次Checkpoint,将当前的数据持久化,每,产生一个新的快照。Wiredtiger连接初始化时,首先将数据恢复至最新的快照状态,然后根据Checkpoint恢复数据,以保证存储可靠性
btree与b+tree
虽然遍历数据的查询是相对常见的,但是 MongoDB 认为查询单个数据记录远比遍历数据更加常见,由于 B 树的非叶结点也可以存储数据,所以 查询一条数据所需要的平均随机 IO 次数会比 B+ 树少,使用 B 树的 MongoDB 在类似场景中的查询速度就会比 MySQL 快。
这里并不是说 MongoDB 并不能对数据进行遍历,我们在 MongoDB 中也可以使用范围来查询一批满足对应条件的记录,只是需要的时间会比 MySQL 长一些。MySQL 认为遍历数据的查询是常见的,所以它选择 B+ 树作为底层数据结构
cache
内部缓存和文件系统缓存,默认情况下内部缓存取50%(RAM-1 GB)或256M较大者,文件系统缓存使用所有当前可用的RAM。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f6pKa5SR-1657024774197)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1227)]](/img/80/d3ae353d9fee255ab439ad568102b6.png)
Wiredtiger的Cache采用Btree的方式组织,每个Btree节点为一个page,root page是btree的根节点,internal page是btree的中间索引节点,leaf page是真正存储数据的叶子节点;btree的数据以page为单位按需从磁盘加载或写入磁盘,btree的每个page以文件里的extent形式(由文件offset + size标识)存储
page
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MUI3Noms-1657024774198)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1228)]](/img/9c/7116bd70d9d6aa5e3effcfd459b97d.png)
ROW_ARRAY: 每个数组单元(wt_row)存储的是这个 kv row 在存储在磁盘上的 page kv cell 行集合数据缓冲区偏移的位置和编码方式(这个位置和编码方式在 WT 上定义成一个 wt_cell 对象),通过这个信息偏移位置信息就可以访问到这一样在缓冲区中的 K/V 内容值
ROW_UPDATE_ARRAY: 一个 mvcc list 对象,mvcc_list 与 wt_row 是一一对应的,mvcc list 当中存储对 wt_row 修改的值,修改的值包括值更新和值删除,是一个无锁单向链表
写操作
- 遍历btree,找到需要更新的page
- 如果cache中没有对应的page,会从磁盘中加载page,键值对存入WT_ROW
- 如果是insert操作,更新WT_INSERT,如果是update/delete操作,更新WT_UPDATE
- 如果需要,将操作记录写入journal
我们通过一个实例来说明:
假如一个 page 存储了一个 [0,100] 的 key 范围,磁盘上原来存储的行 key=2, 10 ,20, 30 , 50, 80, 90,他们的值分别是value = 102, 110, 120, 130, 150, 180, 190。
在 page 数据从磁盘读到内存后,分别对 key=2 的 value 进行了两次修改,两次修改的值是分别 402,502。对 key = 20 ,50 的 value 做了一次修改,修改后的 value = 122, 155,后有分配 insert 了新的 key = 3,5, 41, 99,value = 203,205,241,299。
那么在内存中的 page 就是如下图组织数据的:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ew70Kjzs-1657024774198)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1229)]](/img/da/1400f318dee6ca030579066a85db46.png)
相邻的两 wt_row 之间可能不是连续的,他们之间可以插入新的单元,例如 row1(key = 2) 和 row2(key=10) 可以插入 3 和 5,这两个 row 之间需要有一个排序的数据结构(WT用 skiplist 数据结构)来存储插入的 K/V,就需要一个 skiplist 对象数组 page_insert_array与row array对应。这里需要说明的是 图6 当中红色框当中的 skiplist8,它是用于存储 row1(key=2) 范围之前的 insert 数据,图中如果有 key =1 的数据 insert,那么这个数据会新增到 skiplist8 当中。
那么图中row与 insert skiplist 的对应关系就是:
- row1 之前的范围对应 insert 是 skiplist8
- row1 和 row2之间对应的 insert 是 skiplist1
- row2 和 row3之间对应的 insert 是 skiplist3
- …
- row7 之后的范围对应的 insert 是 skiplist7
checkpoint
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FAoNj9By-1657024774199)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1230)]](/img/bc/7901f9639b2fbf4f0d86e4d0168dd9.png)
一个Checkpoit包含如下元数据:
root page地址,地址由文件offset,size及内容的checksum组成
alloc extent list地址,存储从上次checkpoint起新分配的extent列表
discard extent list地址,存储从上次checkpoint起丢弃的extent列表
available extent list地址,存储可分配的extent列表,只有最新的checkpoint包含该列表
file size 如需恢复到该checkpoint的状态,将文件truncate到file size即可
WAL(journal)
日志文件记录的是从上一个checkpoint之后的实际操作,该文件每100ms或文件大小到达100M就从缓存同步到磁盘
整体关系
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MVHYqJxR-1657024774199)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1231)]](/img/80/d3ae353d9fee255ab439ad568102b6.png)
存储引擎原理补充
分布式存储
架构
架构图:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oFTkWPep-1657024774200)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1232)]](/img/ce/541d80d75cb449ff9cb65b46e60ede.png)
写数据流程:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LBfsoU1L-1657024774200)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1233)]](/img/22/2bf7855e9308d48c7e75b7b341efd2.png)
读数据流程:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDG49n7y-1657024774201)(evernotecid://B1CD39FE-B044-413D-A086-0649DB3F0070/appyinxiangcom/26430792/ENResource/p1234)]](/img/8e/59a612bd9c87e9cd345d2f584bd116.png)
边栏推荐
- Leetcode skimming: binary tree 23 (mode in binary search tree)
- 博文推荐|Apache Pulsar 跨地域复制方案选型实践
- “新红旗杯”桌面应用创意大赛2022
- Milkdown 控件图标
- 为租客提供帮助
- Steps of building SSM framework
- - Oui. Migration entièrement automatisée de la Sous - base de données des tableaux d'effets sous net
- PACP学习笔记三:PCAP方法说明
- leecode3. 无重复字符的最长子串
- 【无标题】
猜你喜欢

Blog recommendation | Apache pulsar cross regional replication scheme selection practice

为租客提供帮助

MySQL master-slave replication

单片机原理期末复习笔记

Awk of three swordsmen in text processing

MySQL入门尝鲜

Milkdown 控件图标

DETR介绍

Leetcode brush question: binary tree 24 (the nearest common ancestor of binary tree)

.Net下極限生產力之efcore分錶分庫全自動化遷移CodeFirst
随机推荐
Leetcode skimming: binary tree 22 (minimum absolute difference of binary search tree)
The difference between cache and buffer
centso7 openssl 报错Verify return code: 20 (unable to get local issuer certificate)
货物摆放问题
MongoDB命令汇总
MongoDB的用户管理总结
Leetcode skimming: binary tree 20 (search in binary search tree)
.Net下极限生产力之efcore分表分库全自动化迁移CodeFirst
《开源圆桌派》第十一期“冰与火之歌”——如何平衡开源与安全间的天然矛盾?
Day22 deadlock, thread communication, singleton mode
Practical example of propeller easydl: automatic scratch recognition of industrial parts
[untitled]
Smart cloud health listed: with a market value of HK $15billion, SIG Jingwei and Jingxin fund are shareholders
How does MySQL create, delete, and view indexes?
MySQL入门尝鲜
AUTOCAD——大于180度的角度标注、CAD直径符号怎么输入?
PHP calls the pure IP database to return the specific address
测试下摘要
共创软硬件协同生态:Graphcore IPU与百度飞桨的“联合提交”亮相MLPerf
Leetcode brush question: binary tree 24 (the nearest common ancestor of binary tree)