数据库内部存储结构探索

 本文是左耳耗子推荐的Medium上的一篇关于MySQL的文章Some study on database storage internals,本人以为文章十分好,就取得了做者的许可,自行进行了翻译,原文连接见文末。本文是一篇介绍性的文字,因此文中并无对一些概念进行详细介绍,好比说Sorted Strings Table结构和Bloom filters算法等专业概念,感兴趣的小伙伴能够学习参考中给出的连接或持续关注本人后续文章。算法

 我一直以来都在不断的研究和探索数据库的内部存储原理。我认为这个话题是很是巨大且复杂的,我努力所学也只占其千万分之一。在这篇文章中,我将会讲解一些数据库存储的内部机制,数据库是如何进行优化操做来提供惊人速度及其优点和缺点。数据库

 当咱们谈起数据库内部存储结构时,人们都会想到B树或者B+树,可是咱们在这里并不会谈论这些数据结构的原理,咱们会展现这些数据结构为何适合做为数据库存储的内部结构以及使用这些数据结构的目的。apache

 传统的关系型数据将数据以B树的形式存储在磁盘上,它们也会在RAM上使用B树维护这些数据的索引,来保证更快的访问速度。插入的行存储在B树的叶子节点上,全部的中间节点用来存储用于导航查询语句的原数据。所以,当有数以百万计的数据被插入到数据库中时,索引和数据存储会变得十分大。所以,为了快速的访问,须要从磁盘中加载全部数据到内存,可是RAM通常没有这么大的空间来存储全部的数据。所以,数据库必须从磁盘中读取部分数据。这种加载数据的场景以下图所示:缓存

B树示意图

 磁盘I/O花费的时间很长,是影响数据库性能的主要缘由之一。B树是支持随机读写,in-place 替换,十分紧凑而且自平衡的数据结构,可是受磁盘I/O速度的限制。随机读意味着当访问磁盘数据时,磁头必须移动到柱面上的指定位置,所以会消耗大量时间。微信

 B树被设计为使用block的形式存储数据,由于操做系统读取读取一个block的数据要比读取单独字节数据要快的多。MySQL的InnoDB存储引擎的block大小为16KB。这意味着每次你读取或者写入数据时,大小为16KB的block数据会被从磁盘加载到RAM中,它会被写入新的数据,而且再次写回到磁盘上。假设数据库表的每一行数据为128字节(实际大小会变化),一个block(叶子节点)为16KB,存储了(16 * 1024) / 128 = 128行数据。B树的高度通常小于10,可是每一层的节点数量却不少,由此能够管理数以万计的数据。基于上述特性,B树适合做为数据内部存储结构。数据结构

 所以,在B树上进行读操做是相对来讲比较快速的,由于该操做只须要遍历一些节点而且进行较少次数的磁盘I/O请求。并且,范围查询由于能够将数据以block的形式进行获取和操做而速度更快。你能够进行下列操做来让基于B-Tree的数据库性能更好:并发

  • 减小索引节点数量:这是提高关系型数据库性能的经常使用策略。索引越多,插入和更新操做须要管理的索引数量也越多。当数据库数据运行时间愈来愈久时,就须要删除一些老旧或者无用的索引,而且谨慎地添加新的索引。可是你也要注意,索引越少意味着查询性能越差,你须要在查询性能和插入更新性能之间进行取舍(译者注:能够考虑数据库的读写比率)。
  • 顺序插入:若是你能以主键大小为基础进行大量数据的顺序插入,那么插入数据的速度会十分的快。由于在插入过程当中,插入行所属的block已经在内存中,因此数据库能够直接将行插入到内存的数据结构中,而后经过一次磁盘I/O提交到数磁盘中。固然,这些都取决于数据库的具体实现,可是我认为现代的数据库通常都会进行相似的优化。

 可是B树并非适合全部情景的最优存储结构。对B树结构的写操做性能不好,比随机读还要差,由于数据库必须从磁盘中加载数据对应的页,而后修改它并冲洗新写入到磁盘中。随机写入时平均有100字节每秒写入速度,这个限制是因为磁盘的基本工做原理。事实上,简单依赖于缓存的使用,索引搜索和更多的内存能够处理更多的读操做,可是应付更多的写操做就比较麻烦。当你须要写入或更新大量的数据时,B树结构并非最正确的选择。长久以来,传统数据库进行了大量的优化,好比说InnoDB尝试使用缓冲来减小磁盘I/O操做。具体操做以下所示:app

操做缓存示意图

 数据库写操做能够经过提高磁盘的带宽来提高速度,可是目前关系型数据库都没有这样作。并且关系型数据库管理系统通常都是十分复杂的,由于他们使用锁,并发,ACID事务等操做,这使得写入操做更加复杂。分布式

 当今信息时代,在好比消息、聊天、实时通信和物联网等客户为中心的服务和大量无结构化数据的分布式系统中,每小时都会进行数百万计的写入操做。所以,这些系统是以写为主的系统,为了迎合这些系统的须要,数据库须要可以拥有快速插入数据的能力。典型的数据库并不能很好的知足相似的场景,由于它们没法应付高可用性,尽量的最终一致性,无格式数据的灵活性和低延迟等要求。性能

 LSM树(Log Structured Merge Tree)应运而生。LSM并非一种相似于B树的数据结构,而是一个系统。在LSM系统中,并无对数据的in-place替换;一旦数据被写入磁盘,它就不再会被修改。显然,它是一种只能在末尾添加(append only)的写入系统。一些日志结构的文件系统好比ext3/4也使用相似的原理。所以,该系统就如同顺序的记录数据日志通常。基本上,LSM系统利用了顺序写的优点。传统的磁盘驱动的写操做最高能够达到100MB/s,现代的固态硬盘在顺序写时的速度则更快。事实上,固态硬盘驱动有一些内置的并行机制来让它能够同时写入16到32MB的数据。LSM树和固态硬盘的特性十分匹配。顺序写要比随机写快不少。

 为了正确地理解上述场景,让咱们简单的看一下Facebook的Cassandra数据库是如何使用LSM原则的。

LSM系统示意图

 Cassandra或者任何LSM系统都会维护一个或者多个用来在写入磁盘前存储数据的内存数据结构(如上图中的memtable),好比说子平衡树(AVL)、红黑树、B树或者跳表。该内存数据结构维护一个排序的数据集。不一样的LSM实现互使用不一样的数据结构来适应不一样的需求,并不存在标准的LSM实现。当内存中存储的数据超过配置的阈值时,内存中存储的数据就会被放置在将会被写入磁盘的队列中。为了flush数据,Cassandra顺序地写入排序的数据到磁盘中。磁盘维护一个叫作“SSTable”(Sorted Strings Table)的数据结构,该数据就是写入文件数据的有序的快照,SSTable是不可变的。LSM系统能够管理磁盘上的多个文件。

 所以,若是数据在内存中没有被发现,Cassandra须要扫描全部磁盘上的SSTables来搜索该数据。所以,Cassandra的读操做相对来讲要比写操做慢,可是这里有一些能够处理的方法。Cassandra或者其余LSM系统会在后台运行压缩程序来减小SSTable的数量。压缩程序对SSTable进行归并排序,在新的SSTable找那个插入新的排序数据而且删除老的SSTables。可是使用压缩程序有时候没法应付数据库中数以百万计的更新操做。

 所以,一些几率数据结构(probabilistic data structures)好比Bloom filters被应用来快速判断是否一些数据存在于SSTable。Bloom filters十分适合对内存中的数据进行判断,由于它须要进行大量的随机查询来进行数据是否存在的几率性判断。Bloom filters算法能够极大地减小遍历查询SSTables的花费。所以,LSM系统解决了在大数据中写操做须要花费大量时间的问题。LSM系统也有Read amplification的问题-会读取出比它实际须要更多的数据。所以,还有介于B Tree和LSM Tree之间的解决方法来给出咱们最优(不必定准确)的读写效率吗?

 Fractal Tree Index是基于B-Tree的数据结构。依据开发人员给出的benchmark,该数据结构有比B-Tree更优良的性能。Fractal tree支持在非叶节点上的信息缓存。MySQL的高性能存储引擎Tokudb就使用了Fractal tree。

Fractal Tree Index示意图

 如上图所示,在Fractal Tree中,你进行的添加列,删除列,插入,更新等任何操做都会被当作操做消息存储在非叶节点上。因为操做只是被简单地存储在缓存或者任何次级索引缓存(secondary index buffer)中,因此,全部的操做都会被迅速执行结束。当某一个节点的缓存满了以后,这些操做消息会依次从根节点,通过非叶节点,向叶节点进行传递。叶节点仍然存储着真实数据。当进行读时,读操做会考虑查询路径节点上的全部操做消息来获取真实的数据状态。可是因为tokudb会尽力将全部非叶节点缓存在内存中,因此这一过程也很快。

 tokubd中的block最大能够达到4MB,而不是InnoDB中的16KB。这样的大小能够容许一次I/O操做时加载或写回更多的数据,这也有助于一次压缩更多数据来减小磁盘上数据的存储大小。所以,tokudb强调借助更大的block大小可以实现更好的数据压缩和更少的磁盘I/O。tokudb宣称它们的存储引擎比InnoDB更快,提供比InnoDB更快的读写吞吐,而且tokudb也宣称本身有更少的碎片(fragmentation)问题,它也支持多集群索引等。下图是benchmark的相关统计图:

benchmark统计图

 只有你系统中的benchmark能够帮助你判断正确的数据点和需求解决方案。可是MySQL的存储引擎会持续地不断改进和支持新出现的需求。LSM树是为了高写入场景的系统,然而B树是为了传统的场景应用。Fractal树的索引改进了B树索引存在的一些缺陷。所以,将来会不断地出现技术上的革新,包括数据库存储技术,硬件,磁盘驱动和操做系统,让咱们拭目以待。

订阅最新文章,欢迎关注个人微信公众号

参考

相关文章
相关标签/搜索