磁盘:
一个 IO 的访问,大致分为三个步骤,第一是磁头到指定的磁道(寻道),第二是等待
需要读取的数据随盘片旋转到磁头(延迟),第三是读取数据。相比较前两个时间,读取数
据的时间可以忽略不计,所以一个 IO 的响应时间等于寻道时间+延迟时间决定(ssd 固态硬
盘除外,它的存储方式不一样),寻道时间由于是机械的动作,所以很难得到大幅度提高,
但是可以通过提高磁盘转速来提高延迟时间。所以转速越高的盘,可以承载更多的 IOPS。
磁盘的 IOPS 由磁盘的转速决定,比如 15000RPM 的磁盘,一般可以承受 150 个 IOPS。
和存储相关的三个性能参数:IOPS,吞吐量,响应时间
吞吐量:
吞吐量,则由磁盘的转速和接口决定,转速决定了内部传输率,接口则决定了外部传
输率,很明显前者肯定低于后者。常见的接口有 ATA,SCCI,SATA,SAS,FC 等等。FC
接口一般在高端存储中比较常见,而 SAS 和 SATA 多在服务器或者中低端存储中常见。
影响吞吐量的因素稍微复杂些,由磁盘的数量和存储的架构决定,当磁盘到达一定的
数量后,吞吐量主要受限于存储的架构。比如某高端存储,吞吐量最大就是 1.4GB,这是由
它内部的架构所决定的。另外还要注意存储与主机的接口,比如 HBA 卡,有 4Gb 和 2Gb
(这里是 bit,而不是 Byte),一般主机和存储都配有多块 HBA 卡
IOPS:
对于一个存储系统来说,IOPS 主要决定于 cache 的算法,以及磁盘的数量。有时候我
们往往会被厂商的数据给忽悠了,第一是 cache 命中率,厂商利用了某种手段,让 cache 命
中率非常高,IOPS 几乎可以随心所欲。另外一个因素就是磁盘的数量,厂家的数据是同型
号 1000 块磁盘的测试结果,而实际的系统只有几十或者几百块磁盘。
购买存储时,应该避免买高端的存储,而只配数量很少的磁盘,厂商非常喜欢你买一
个高端的 BOX,告诉你扩展性好,现在用不着可以少买点盘,以后可以扩容等等,这完全
是忽悠。建议不要超前消费,如果确实对性能追求很高,可以选用容量小一些的磁盘,而磁
盘的数量多一些。磁盘的数量可以计算得出,我们的经验,一般 OLTP 应用的 cache 命中率
在 20%左右,剩下的 IO 还是要到磁盘上的,根据磁盘的转速和类型,就可以知道一块盘能
够承载的 IOPS,磁盘数量就可以估算出来了,为了得到比较好的响应时间,建议每块磁盘
的 IOPS 不要超过 100。
响应时间:
除了 IOPS 与吞吐量,存储的另外一个重要性能指标就是单 io 的响应时间,单 io 的响
应时间与 IOPS 的当前值,吞吐量大小及 cache 命中率都有密切的关系,经验值表示,一个
io 的响应时间在 20ms 以后,应用基本可以正常工作,但对于高可用的核心 OLTP 系统,最
佳的 IO 时间是小 10ms。
Stripe:
Stripe 的作用就是尽可能的分散 IO,它在有些存储上是可以调节的,但是很多存储是
不可以调节的,一般在 128K-512K 之间。有一个错误的说法是,我在存储上做了 stripe,数
据库的一个 IO,所有的磁盘都会响应这个 IO。这个说法是错误的,对于 Oracle 来说,一个
随机 IO 的大小是 8K,一般条带的大小要比 8K 大得多,所以 Oracle 一个随机 IO 永远只会
落在一块磁盘上。一块磁盘在同一个时刻只能响应一个 IO,也就是说磁盘没有并发 IO 的概
念,但是从整个系统来看,不同的磁盘响应不同的 IO,宏观上 IO 还是分散的,所以我们看
到一个数据库在运行时,所有的磁盘都在忙,实际上每块磁盘是为不同的 IO 服务。对于顺
序 IO,Oracle 的默认设置是 128K,最大值由 OS 决定,一般是 1M,如果顺序 IO 的大小大
于 stripe,那么一个 IO 可能会有几块盘同时响应,但是很多存储的 stripe 都大于 128K,这
时一个 IO 还是只有一块磁盘响应,由于读是一个顺序的过程(在不同的 multiblock read 之
间,存在一定程度的并行。Oracle 每次同时向 OS 发送若干个 multiblock read IO 请求,然后
把返回的结果合并排序。整个 scattered read 应该是局部并行,宏观串行的过程),所以要在
数据库这个级别加上并发,才可以真正达到提高吞吐量的目的。
有人要问,stripe 到底多大合适?假设把 stripe 做得很小,这样不是很好吗?一个 IO
同时可以读很多块盘,大大提高了吞吐量。我们假设 stripe 为 1K,Oracle 一个 IO 要分布在
8 块不同的磁盘上,但是这时新的问题就出现了,因为一块磁盘是不具备并发 IO 能力的,
如果每个 IO 都占用很多块盘,这样整个系统的并发 IO 能力就下降了,而且一个 8K 的 IO
如果在一块盘上读,和从 8 块盘上并行读,不会有很大的差别(也许在一块盘上读还要更
快),所以 stripe 不能做的很小。stripe 到底设多大,我的观点是大比小好,不要小于 256K,
数据仓库应用可以设置的更大一些。ASM 对于数据文件的 stripe 默认是 1M,不要设置太小,
经验表明,1M 的性能更好,Oracle 也推荐用 1M。这说明对于数据库应用来说,stripe size
要稍微大一点,而不是我们想的越细或者越分散越好。
Raid:
RAID 一般比较常见的就是 RAID10 和 RAID5,对性能要求比较高的数据库应用一般
都采用 RAID10,RAID5 也可以用,但是别把 redo 放在 RAID5 上,因为 RAID5 的对于 redo
这种小 IO,性能非常差,很容易造成 log file sync 的等待。一个 RAID group 中的磁盘数量
不宜过多,不要超过 10 块,原因是 RAID group 中磁盘数量越多,坏盘的概率就越大(概率
问题)。一些高端存储对于 RAID group 中的磁盘数量都是固定的,这主要和存储的架构有
关。使用存储的过程中,你会发现,越是高端的东西,就越是死板,而中低端存储则非常灵
活,并不是说高端存储不好,而是说架构决定一切。
存储划分
划分好的 LUN 输出到主机后,我们怎么用?这个就比较灵活多变,首先要看我们的用
途,我们是追求 IOPS 还是吞吐量?我们用 file system,raw devices,ASM?存储输出的 LUN
跨在多少块盘上?一般的存储没有虚拟化功能,则输出的 LUN 只跨在一个 RAID group 上,
这时往往需要利用 OS 上的 LVM 来再次划分一次,比如有两个 raid group,每个 RAID goup
有四块磁盘,建立两个 LUN,输出到主机后,然后分别创建两个 VG,再创建 LV(stripe),
这下每个 LV 就完全跨在了所有的磁盘上。实际中考虑的问题要更多,有时候不仅仅要考虑
磁盘,还要考虑将负载分配在不同的控制器,前端卡后端卡和多路径的问题,相当复杂。有
些存储本身有虚拟化的功能,甚至可以输出一个 LUN,比如 3PAR 就可以输出一个虚拟卷,
这个卷已经跨在所有的磁盘上,我们直接使用就可以了(但实际工作中这么使用的比较少
见)。
Oracle 有了 ASM,问题就更加复杂了,我的建议是如果可以的话,存储只做 RAID1,stripe
交给 ASM 去做。如果有些存储必须要做 stripe,也没问题。存储划分是一个很有技术含量的
工作,必须建立在对存储,主机和数据库深入了解的基础上,才有可能做出一个好的规划。