IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 是否要在数据库系统中使用mmap? -> 正文阅读

[大数据]是否要在数据库系统中使用mmap?

andy在cmu15-445中提出了不要在数据库系统中使用mmap

因为这个,在网络上找了许多关于 mmap 的文章,无一例外都是对 mmap 的褒奖, 对于mmap可能带来的负面影响少之又少,因此整理了一下andy的论文。

andy的论文

大佬的整理

Ravendb‘s ceo的回应

问题引出

通常情况下,数据库系统对于文件IO管理有两种选择:

  • 开发者自己实现buffer pool来管理文件io读入内存的数据
  • 使用linux实现的mmap系统调用将文件直接映射到用户地址空间, 并且利用对开发者透明的page cache来实现页面的换入换出

由于第二种方案,开发者不需要手动管理内存,实现起来简单,因此很多数据库系统曾经使用MMAP来代替buffer pool
但是由于一些问题导致它们最终弃用了MMAP(这一点也是论文的一个重要的论据),改为自己管理文件I/O。

理论介绍

buffer pool的原理

基于传统的IO方式,底层实际上通过调用read()write()来实现。

  • 将文件数据从硬盘读取到 bufferpool
  • 将数据复制到缓冲区中
  • 对于脏页面需要重新写回磁盘中,通过合理的置换算法清除缓冲区缓存

在不考虑socket的情况下,上述的过程发生了下面变化:用户态内核态的变化。

  • 用户进程通过read()方法向操作系统发起调用。上下文:用户态 -->内核态
  • 将数据从硬盘拷贝到缓冲区(buffer pool)
  • cpu将缓冲区数据拷贝到用户缓冲区中,上下文:内核态–>用户态,read()结束

以上过程发生了 2次上下文切换2次拷贝

mmap的原理

对于mmap的原理,基于 0拷贝技术 。通过优化将数据从系统缓存复制到用户缓存这个过程,减少了1次拷贝。

使用 mmap 系统调用,可以将用户空间的 虚拟内存地址 与文件进行映射, 对映射后的虚拟内存地址进行读写 就等价于 对文件进行读写操作。

基本原理:mmap直接映射了缓存区的页缓存,而非磁盘中的文件本身。

im1
论文中介绍了程序使用MMAP访问文件,流程如下

  1. 程序开始调用 mmap (上下文:用户态–>内核态)
  2. 操作系统保留一部分虚拟地址空间(进程地址空间中),此时没有开始加载文件。
  3. 数据从硬盘中拷贝到了 读缓冲区中(系统缓存)
  4. 操作系统尝试在系统缓存中找到所需的 页面的物理地址
  5. 由于 内存页 不存在(缺页),因此触发了页错误,开始从外部存储将第3步获取的那部分内容加载到物理内存页中
  6. 操作系统在页表中添加一个条目,将虚拟地址映射到新的物理地址
  7. 上述操作使用的cpu核心将页表项加载到页表缓存(TLB)中(上下文: 内核态 --> 用户态 )

上面可以看出发生了,2次上下文切换,1次拷贝

当程序访问不在内存中的页面,os会将他们加载到内存中。如果页面缓存已满,会根据置换算法逐出页面。

  • 操作系统从页表和每个cpu内核的tlb中删除映射

访问tlb很简单,但是删除tlb需要os法成 昂贵的处理器间中断 刷新,这被称为TLB击落。 TLB击落 对后面实验有很大的影响。

mmap的api

作者给出了内存映射文件io的POSIX系统调用

  • mmap:介绍了MAP_SHAREDMAP_PRIVATE在可见性上的区别
  • madvise:介绍了MADV_NORMALMADV_RANDOMMADV_SEQUENTIAL在预读上的区别
  • mlock:可以尝试性的锁住内存中的页面,一定程度上防止被写回存储。(然而并不是确定性的锁住)
  • msync:将页面从内存写回存储的接口

mmap

主要讲述了MAP_SHAREDMAP_PRIVATE的区别。

此调用导致文件映射到DBMS的虚拟地址空间,然后DBMS可以使用普通的内存操作读取写入文件内容。

  • MAP_SHARED:将修改后的文件 重写 回底层文件
  • MAP_PRIVATE:创建一个只有调用者可以访问的写时复制映射,不会重写回 底层文件。

madvise

介绍了MADV_NORMALMADV_RANDOM,MADV_SEQUENTIAL三种标志的区别

  • MADV_NORMAL:告诉linux系统执行默认操作,系统将会返回接下来前15个页面后16个页面
    即使只需要一个页面,系统也会返回32个页面,带来了极大的系统开销
  • MADV_RANDOM:告诉系统,访问页面是随机的。
  • MADV_SEQUENTIAL:告诉系统,我们将要顺序执行。

mlock

该调用允许dbms将页面固定在内存中,并保证操作系统永远不会驱逐他

但是根据POSIX标准和linux实现,即使被固定了,操作系统随时会将脏页重写回磁盘中。因此,mlock只能保证页面不会被驱逐,不能够保证脏页不会被重写回磁盘中,这对于事务安全有很大的影响。

msync

将内存范围更改显示刷新到 外部存储中 ,如果没有这个方法,DBMS就没有其他方法将 更新 刷新到 外部存储中

两者的对比

表面上来看,两种io操作带来的开销

  • buffer pool:2次上下文切换,2次拷贝
  • mmap:2次上下文切换,1次拷贝

看起来,似乎 mmap 更有吸引力,但下面将会给出 mmap 将会引发的问题。

同时,越来越多的数据库都在使用 mmap 之后,改用buffer pool
iiii

问题陈述

论文列举了四个使用MMAP可能引发的问题

问题一:事务安全

在基于MMAPDBMS中修改页面会带来很大的挑战。

由于透明分页,操作系统可以随时将脏页重写回外部设备, 而不管写入事务是否已经提交。
DBMS无法阻止刷新,并且不会在刷新时收到任何警告。因此,必须要用复杂的协议来确保透明分页不会 违反事务安全保证

我们将更新的方法分为:

  1. 操作系统写时复制
  2. 用户空间写时复制
  3. 影子分页

操作系统写时复制(copy-on-write)

使用MAP_PRIVATE标识位创建一个独立的写空间(物理内存复制),写操作在这个写空间执行,读操作仍读取原来的空间。同时使用WAL保证写入操作被持久化。 事务提交后,将写空间新增内容复制到读空间,将相应的WAL复制到辅助存储中。

注意: 操作系统必须确保所有更新都写入到读空间中,才会删除私有空间。操作系统可以使用mremap来定期收缩私有空间

用户空间写时复制(copy-on-write)

类似操作系统写时复制,不过写空间在用户空间开辟,同样写入WAL保证持久性。事务提交后,从用户空间写回读空间。

影子分页

影子分页类似第一种方法,不过没有WAL的参与,而是直接出来两份分页,一份只读的,另一份可写,事务提交就是在可写页表做msync之后再让只读页表可以读到最新的页。

具体流程:

  • 分出两个页面,一个为主页面,一个为影子页面
  • 对影子页面进行修改,将对应的修改重写回外部存储中
  • 以影子页面作为新的主页面,原来的主页面作为影子页面

问题二:io停顿

缓冲池:可以使用异步io来避免查询执行期间阻塞线程。

mmap:可以会带来下面问题

  • dbms不能异步读取。
  • 操作系统可以对页面透明操作,会无警告的将页面逐出内存。导致缺页错误。

即,由于缓存的页面置换是由os控制的,所以无法控制page cache的换入换出,导致io停顿。

操作系统使用页缓存没有对数据库场景进行特别优化,所以使用的时候会影响性能

问题三:错误处理

缓冲池对于文件内容的校准可以以多个页面来做,mmap只能以单个页面来做,因为当前页面不受控制,可能随机被换出。

另外,指针错误可能会导致页面错误,缓冲池可以在刷新前检查文件内容来避免出错,而mmap只能直接刷新,不能检查

还有,mmap应对的系统调用会出现sigbus信号报错,而其他io方式的buffer pool可以更好的解决io错误

问题四:性能问题

业界普遍认为MMAP比传统的read/write更快,主要基于以下两点原因:

  1. 操作系统会在后台负责文件映射和页面错误,负责文件映射操作,并处理page falut的是内核,而不是应用程序
  2. MMAP帮助避免了用户空间的额外的复制操作,相应的减少了内存占用

接下来作者提出了他们的发现:MMAP相对于传统read/write I/O在目前高带宽的存储设备上是更差的。并指出了三点原因:

  1. 页表竞争
  2. 单线程的页面换出:页面换出是单线程的(使用kswapd),这点与cpu相关
  3. TLB击落 :当一个页面失效,每次都需要一个中断来做刷新操作,但是对于一个中断会损耗几千个时钟周期,是非常耗时的

实验说明

在这里,作者使用了两个访问方式来做实验:随机访问循序访问

随机访问

im
IM11
如图给出了随机访问中,io读取和mmap三种读取方式中,100个线程每秒读取的页面数

可以看到,传统io读取显然更优,作者给出了三种原因解释

  • tlb击落
  • MMAP中操作系统仅使用单个进程(kswapd)进行页面驱逐,这会受到cpu的限制
  • MMAP中操作系统必须同步页表,同步操作会与多个并发线程竞争

对于上面的三个问题,传统io都可以通过DBMS控制来给予 进程优先级 和 多进程并发

循序访问

iiii

主要带来的性能问题在于

  • 随机访问的三个缺点
  • 在循序访问中,MMAP不能访问多个SSD,而缓冲池在人为操作下可以

总结

mmap主要优点在于更好实现,但是性能相比于传统io设备,随着多角度分析会逐渐显露出来。

作者给予db开发人员以下建议
当你不应该在dbms中使用mmap的情况

  • 需要事务安全的方式执行更新
  • 希望在不阻塞慢速io的情况下处理页面错误,或者需要控制内存中的数据
  • 关心错误处理并需要返回正确的结果
  • 需要快速持久存储设备的高吞吐两

在使用mmap时需要注意

  • 数据库或者工作集 适合内存并且工作负载是只读的
  • 不关心数据一致性或长期的工程难题
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:43:14  更:2022-04-22 18:45:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:37:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码