`

数据库如何抵抗随机IO:问题、方法与现实(zz)

阅读更多
from:http://wangyuanzju.blog.163.com/blog/static/13029201132154010987/

随机IO几乎是令所有DBA谈虎色变的一个问题,这个问题,往往在数据量小的时候不出现,在数据量超过内存大小时,才陡然出现,令没有经验的DBA促不及防,也令有经验的DBA寝食难安。

传统的数据库架构对随机IO几乎没有还手之力。传统数据库的核心通常是页级缓存、B+树、堆或索引组织表,这些机制,对随机IO的抵抗能力,都无一例外的可悲的差。页级缓存有很强的“连坐”效应,就是为了要缓存一条有价值的记录,顺带可能要同时缓存百条无价值的记录。传统上这一点自豪的称之为locality,是用来减少IO的,但往往会导致内存缓存的利用率很差。在记录的级别,应用的访问模式通常符合Zipf分布,其中10%的记录所占的访问概率超过90%。如果我们用记录级的缓存,用相当于数据量10%的内存,就可以消除90%的IO,但用页级缓存,这10%的热点记录,很可能就分布在70%的页面上,这样同样10%的内存,很可能只能消除可悲的30%的IO。B+树的情况也好不了,如果索引大于内存量,每次随机的索引搜索、插入和删除,几乎都将带来一次随机IO(假设索引的非叶节点都在内存中)。

新的SSD硬件可以缓解随机读问题,但对随机写依然是无能为力。SSD的技术比较成熟了,期望它哪一天能魔术般的也搞定随机写,是不现实的。但我们可以从数据库架构上来想办法,谢天谢地,其实有很多办法,虽然未必能马上就用上。

先说记录的随机IO。之前已经说过,用记录级的缓存是很好的,我们NTSE的测试表明这一招很有效。但似乎不太有公开的数据库支持类似的功能。退而求其次,大家可以用Memcached,但两者有重大区别。用Memcached时,很难保证Memcached与数据库的一致性,除非用数据库事务来保证,但这样会导致在两个系统之间进行每个事务毫秒级的锁定。虽然数据库内置的记录级缓存也需要用某种加锁机制来保证一致性,但这个锁定时间是微秒级的,并发度不可同日而语。但最重要的一点是,Memcached通常只能消除随机读IO,对随机写无能为力。而数据库内置的记录级缓存,则可以很好的解决这个问题。数据库内置记录缓存的设计,常用的有几招:
1、最基本的一招是,如果要访问的记录在记录缓存中,就不去读底层的堆文件。当然这是废话,如果不这样,那还叫记录级缓存吗?但如果仅仅是这样,记录缓存跟Memcached是一样的,还不如用Memcached,更灵活。但接下来数据库内置记录级缓存的招数,基本上都是Memcached搞不定的。
2、如果仅仅如果更新命中了记录缓存中的记录,则只更新记录缓存,不更新底层的堆等存储。具体细化下来有UPDATE和DELETE两种,NTSE暂时只能搞定UPDATE;
3、记录缓存里的东西,总是要有周期的持久化的,否则恢复时间不能保证。这个第三招,就是持久化也就是把记录缓存中的脏记录dump出去的时候,不要去更新对应的堆中的记录,否则短时间就会爆发大规模的随机读写,做法应该是像内存数据库那样,把脏记录用顺序写IO dump出来。NTSE就是这么做的,刷记录缓存脏记录时,我们先看看对应的页面在页面缓存中在不在,在,则更新堆,否则顺序dump到log中。
4、在更新时,可以只把UPDATE后的后像插入到记录缓存中,根本不去读原来的记录,当然这个要看具体情况,如果后像是依赖于前像的那这招就不灵,但很多时候是可以用的,比如根据主键找到一条记录,不管3721把其中一些属性改掉。NTSE暂时还搞不定这招,有待改进。

记录缓存的这4招,消除数据库中记录操作带来的随机IO是很有效的。遗憾的是这不是必杀技,如果记录的访问确实的纯随机的就会失效,幸运的是这样的情况不常出现。

索引的随机IO问题要更复杂一点。我们简单点,只说涉及到单个索引项的操作。传统的B+树,无论是搜索、插入还是删除(更新相当于插入+删除,就不额外讨论了),理论上都是O(log(B)(N))次IO(其中B是页面包含的键值数,N是总键值数),但实际情况下可以假设非叶节点都在内存中,因此是1次IO。磁盘一般只能有每秒几百次随机IO,因此对大的索引,每秒只能有几百次操作,这个性能真是低的可怜。B+树是70年代的老怪物,但直到今天,大多数数据库里仍然用得是它,但实际上,有比传统B+树更能对付随机IO的东西。

1996年,P O'Neil等提出的LSM-Tree是一个重大突破。LSM-Tree主要有两种变形,最简单的LSM-Tree,是一个内存中的小索引加上外存中的大索引,更新先缓存在小索引中,再批量更新到大索引,这样就有望合并对属性同一页面的多次更新的IO。复杂的LSM-Tree,是划分为多个level的很多的小索引,每个level的大小,近似的是前一个level大小的r倍,如果一个level有r个小索引,则合并形成一个下一level的较大的索引,这样随机插入或删除的平均IO开销可以降低到log(N)/B次,是一个很大的提升。但带来的问题是,搜索的时候,就要搜索这么多个小索引,而这样的索引会有O(log(N/B))个,那是可能有几十个,搜索的性能就可能下降几十倍,这往往也带来问题。LSM-Tree已经有不少的现实应用,BigTable、Cassandra、Lucene等这些用的是复杂的那种LSM-Tree,InnoDB的change buffer可以说是那种一大一小的简单LSM-Tree。NTSE想在做多版本事务的时候顺便实现change buffer。

2000年,MA Bender等提出的Cache Oblivious B-Tree是第二个重大突破。这个跟LSM-Tree有些类似,也是索引从小到大分成相邻大小翻倍的多个索引,因此随机插入或删除的平均IO开销也是log(N)/B次,但它用了Fractional Cascading的技术,使得搜索的性能较传统B+树相关不多。虽然论文发表了10年了,这种索引似乎现在只有TokuDB一家实现,它是称之为Fractal Tree。我们拿来试了试,效果果然出奇的好。

有没有可能将来搞出一个比Fractal Tree更好的东西呢,遗憾的是如果硬件不发生根本改变,已经证明Fractal Tree已经是最理想的了。

但LSM-Tree或Fractal Tree,其实只是消除索引的随机插入和删除带来的随机IO,对随机搜索没什么帮助。这个剩下的索引的随机搜索问题比较复杂,要分解来看。一种是真正的来自于应用需求的搜索,另一种是检查唯一性带来的搜索。这两种处理方法是不同的。

对于真正的来自于应用需求的搜索,处理还得借助于记录级缓存类似的技术,但这时变成索引项的缓存了。InnoDB中的Adaptive Hash Index就是这个东西。但对检查唯一性带来的搜索,Bloomfilter是个好方法,经常可以消除98%以上不必要的检查。所以BigTable里就用。但对传统B+树由于索引是实时更新的,Bloomfilter不好用,对Fractal Tree,索引是在merge的时候再批量更新的,可以用Bloomfilter。我们试了TokuDB,根据性能表明看,它对索引性索引的随机插入,也能轻松对付,估计也是用了Bloomfilter类似的技术。

因此,我们可以看到,随机IO这个老大难的问题,其实还是有不少的技术可以解决的。然而,现实是悲摧的,我们经常在用的主流数据库,无论是商业的Oracle、DB2、SQL Server,还是开源的MySQL、PostgreSQL,都基本上还在用最老土的技术,InnoDB里搞了一点change buffer,就能让人津津乐道半天。NoSQL系统走在前面,用上了LSM-Tree,但也并不是最先进的,搜索的性能经常令人担忧。在索引这方面,TokuDB走在前面,但还没为大众接受。记录方面,不清楚为什么大家不作记录级缓存,这不是很难的事,莫非认为用Memcached就可以了,“因为善小而不为”?

相信未来,总有改善的一天。
分享到:
评论

相关推荐

    Oracle数据库优化之数据库磁盘IO

    具体来说,优化数据库磁盘IO的方法包括: 1. 监控数据库的性能:使用TIMED_STATISTICS和ALTER SESSION SET STATISTICS参数来监控数据库的性能。 2. 检查系统的I/O问题:使用sar-d工具检查整个系统的I/O statistics...

    Oracle数据库服务器IO高的分析方案.docx

    通过上述方法,我们可以有效地诊断和解决Oracle数据库服务器的IO性能问题。重要的是,不仅要关注硬件升级或扩展,还需要从软件层面出发,通过优化SQL查询等方式减少不必要的IO操作,从而从根本上改善系统的IO性能。

    Oracle数据库服务器IO高的分析方案和案例探讨.pdf

    本文旨在提供一些实用的解决方案和方法,帮助系统管理员和存储管理员更好地理解 Oracle 数据库服务器 IO 高的问题,并提高 Oracle 数据库服务器的性能。 知识点: * BLOCK 是 Oracle 数据文件的最小分配单元,类似...

    MySql数据库连接+IO

    ### MySQL 数据库连接与 IO 流操作 #### 一、概述 本文将详细介绍如何通过 Java 程序实现与 MySQL 数据库的连接,并利用输入输出流(IO 流)进行图片数据的读写操作。本示例适用于需要在数据库中存储和检索二进制...

    如何判断数据库IO是否慢

    本月远程支持的一个项目中出现了数据库响应缓慢的问题,最终发现这是由于操作系统层面的IO性能不佳所致。为了确保解释充分、具有说服力,本文将深入探讨如何利用Oracle自带的工具来判断数据库IO是否过慢,从而为后续...

    metablocklabs.github.io:打破虚拟与现实之间的鸿沟

    metablocklabs.github.io:打破虚拟与现实之间的鸿沟

    数据库设计准则及方法论.pdf

    数据库设计准则及方法论.pdf 数据库设计是数据库开发的关键步骤,对于数据库的设计直接影响到系统的性能和可扩展性。本文将从数据库设计的角度,讨论数据库设计的准则和方法论。 一、数据库设计准则 数据库设计的...

    异步IO:Python中的并发编程革命

    ### 异步IO:Python中的并发编程革命 Python 自问世以来,就因其简洁优雅的语法、易学且功能强大等特点迅速赢得了程序员们的喜爱。随着计算机技术的发展与应用场景的不断拓展,传统的同步IO模型逐渐难以满足高并发...

    commons-io-2.4.jar包 官方免费版

    这个库提供了一系列与输入输出操作相关的实用工具类,极大地简化了Java程序员处理IO任务的复杂性。标题提到的"commons-io-2.4.jar"是这个库的一个版本,版本号为2.4,表明它是官方发布的稳定版本,对先前版本进行了...

    系统环境:linux主流分发版本,建议使用ubuntu14.04LTS版本 数据库环境:mysql5.6 postgres9.6

    系统环境:linux主流分发版本,建议使用ubuntu14.04LTS版本 数据库环境:mysql5.6 postgres9.6 数据库表结构文件:db目录下postgres下的main.sql... npm install socket.io 代码存放在websocket目录下 前端环境: jquery

    63 案例实战:线上数据库莫名其妙的随机性能抖动优化(下)l.pdf

    数据库性能优化是确保在线业务高效稳定运行的重要环节,尤其是在处理线上数据库莫名其妙的随机性能抖动问题时,优化策略显得尤为重要。性能抖动是数据库性能问题的一种,通常表现为即使在负载较低的情况下,SQL语句...

    oracle IO问题解析

    Oracle IO 问题的解决方法包括优化数据库的物理结构,调整数据库的参数,使用索引和分区表等方法。这些方法可以有效地解决 Oracle 数据库中的 IO 问题,从而提高数据库的性能。 Oracle IO 问题的解决方法还包括...

    IO模拟数据库图书管理系统

    在本项目中,"IO模拟数据库图书管理系统"是专为Java初学者设计的一个实践项目,旨在帮助学习者理解和掌握Java的输入输出(IO)操作,同时实现简单的图书管理功能。这个系统模仿了真实数据库的工作原理,尽管没有使用...

    oracle基本知识+内存分析+数据库IO深入分析

    首先,"oracle基本知识.pdf"将涵盖Oracle数据库的基础概念,包括但不限于数据模型、SQL语言、数据库实例与进程、表空间和数据文件的创建与管理。这部分内容是学习Oracle的基石,理解这些基础知识能够帮助我们构建对...

    Io流上传图片到数据库

    Io流上传图片到数据库

    commons-io-2.4.jar 包 (工具类包)

    fileupload组件依赖的commons-io组件

    oracle IO 使用情况

    通常,我们可以通过以下方式来监控Oracle数据库的IO: 1. **V$SESSION_WAIT** 视图:这个视图提供了当前会话正在等待的事件信息,包括I/O相关的等待事件,如“db file sequential read”(顺序读取数据库文件)和...

    Visual Basic 2005文件IO与数据存取秘诀(数据库连接)

    2. **数据库连接**:连接字符串是与数据库建立连接的关键。例如,对于SQL Server,连接字符串可能如下: ```vbnet Dim connectionString As String = "Data Source=myServerAddress;Initial Catalog=myDataBase;...

    Lola-Lumings.github.io:数据库..

    在“Lola-Lumings.github.io:数据库..”这个标题中,我们可以推断出这是一个关于个人网站,特别是Lola Lumings的个人网站,并且可能涉及到数据库相关的内容。在这个网站中,Lola Lumings可能分享了关于数据库的知识...

Global site tag (gtag.js) - Google Analytics