raidiops
高速缓存 (Cache) 在当下的各种存储产品中, 按照速度从快到慢应该就是 内存 >闪存 >磁盘 >磁带 了, 然而速度越快也就意味着价格越高,闪存虽然说是发展势头很好,但目前来说却还是因为价格问题无法普及,因此现在还是一个磁盘作霸王的时代。与 CPU和内存速度相比,磁盘的速度无疑是计算机系统中最大的瓶颈了,所以在必须使用磁盘而又想提高性能的情况下,人们想出了在磁盘中嵌入一块高速的内存用来保存经常访问的数据从而提高读写效率的方法来折中的解决,这块嵌入的内存就被称为高速缓存。说到缓存,这东西应用现在已经是无处不在,从处于上层的应用,到操作系统层,再到磁盘控制器,还有CPU内部,单个磁盘的内部也都存在缓存,所有这些缓存存在的目的都是相同的,就是提高系统执行的效率。 当然在这里我们只关心跟 IO 性能相关的缓存, 与 IO 性能直接相关的几个缓存分别是文件系统缓存 (File System Cache)、磁盘控制器缓存 (Disk Controller Cache) 和磁盘缓存 (Disk Cache,也称为 Disk Buffer) ,不过当在计算一个磁盘系统性能的时候文件系统缓存也是不会考虑在内的,因此我们重点考察的就是磁盘控制器缓存和磁盘缓存。不管是控制器缓存还是磁盘缓存,他们所起的作用主要是分为三部分:缓存数据、预读 (Read-ahead) 和回写 (Write-back) 。缓存数据首先是系统读取过的数据会被缓存在高速缓存中,这样下次再次需要读取相同的数据的时候就不用在访问磁盘, 直接从缓存中取数据就可以了。 当然使用过的数据也不可能在缓存中永久保留的,缓存的数据一般那是采取 LRU算法 来进行管理,目的是将长时间不用的数据清除出缓存,那些经常被访问的却能一直保留在缓存中,直到缓存被清空。预读预读是指采用预读算法在没有系统的 IO 请求的时候事先将数据从磁盘中读入到缓存中, 然后在系统发出读 IO 请求的时候, 就会实现去检查看看缓存里面是否存在要读取的数据, 如果存在 (即命中)的话就直接将结果返回,这时候的磁盘不再需要寻址、旋转等待、读取数据这一序列的操作了, 这样是能节省很多时间的; 如果没有命中则再发出真正的读取磁盘的命令去取所需要的数据。缓存的命中率跟缓存的大小有很大的关系,理论上是缓存越大的话,所能缓存的数据也就越多,这样命中率也自然越高,当然缓存不可能太大,毕竟成本在那儿呢。如果一个容量很大的存储系统配备了一个很小的读缓存的话,这时候问题会比较大的,因为小缓存缓存的数据量非常小,相比整个存储系统来说比例非常低,这样随机读取(数据库系统的大多数情况)的时候命中率也自然就很低,这样的缓存不但不能提高效率(因为绝大部分读 IO 都还要读取磁盘),反而会因为每次去匹配缓存而浪费时间。执行读 IO 操作是读取数据存在于缓存中的数量与全部要读取数据的比值称为缓存命中率 (Read Cache Hit Radio) ,假设一个存储系统在不使用缓存的情况下随机小 IO 读取能达到 150IOPS,而它的缓存能提供 10%的缓存命中率的话,那么实际上它的 IOPS 可以达到 150/(1-10%)=166 。回写首先说一下,用于回写功能的那部分缓存被称为 写缓存 (Write Cache) 。在一套写缓存打开的存储中, 操作系统所发出的一系列写 IO 命令并不会被挨个的执行, 这些写 IO 的命令会先写入缓存中,然后再一次性的将缓存中的修改推到磁盘中, 这就相当于将那些相同的多个 IO 合并成一个, 多个连续操作的小 IO 合并成一个大的 IO, 还有就是将多个随机的写 IO 变成一组连续的写 IO, 这样就能减少磁盘寻址等操作所消耗的时间,大大的提高磁盘写入的效率。读缓存虽然对效率提高是很明显的, 但是它所带来的问题也比较严重, 因为缓存和普通内存一样,掉点以后数据会全部丢失, 当操作系统发出的写 IO 命令写入到缓存中后即被认为是写入成功, 而实际上数据是没有被真正写入磁盘的,此时如果掉电,缓存中的数据就会永远的丢失了,这个对应用来说是灾难性的,目前解决这个问题最好的方法就是给缓存配备电池了,保证存储掉电之后缓存数据能如数保存下来。和读一样, 写缓存也存在一个写缓存命中率 (Write Cache Hit Radio) , 不过和读缓存命中情况不一样的是,尽管缓存命中,也不能将实际的 IO 操作免掉,只是被合并了而已。控制器缓存和磁盘缓存除了上面的作用之外还承当着其他的作用, 比如磁盘缓存有保存 IO 命令队列的功能,单个的磁盘一次只能处理一个 IO 命令,但却能接收多个 IO 命令,这些进入到磁盘而未被处理的命令就保存在缓存中的 IO 队列中。top RAID(Redundant Array Of Inexpensive Disks) 如果你是一位数据库管理员或者经常接触服务器,那对 RAID应该很熟悉了,作为最廉价的存储解决方案,RAID早已在服务器存储中得到了普及。在 RAID 的各个级别中,应当以 RAID10和 RAID5(不过 RAID5已经基本走到头了, RAID6正在崛起中,看看 这里 了解下原因)应用最广了。下面将就 RAID0, RAID1, RAID5,RAID6, RAID10这几种级别的 RAID展开说一下磁盘阵列对于磁盘性能的影响,当然在阅读下面的内容之前你必须对各个级别的 RAID 的结构和工作原理要熟悉才行, 这样才不至于满头雾水, 推荐查看 wikipedia 上面的如下条目: RAID, Standard RAID levels , Nested RAID levels 。RAID0RAID0将数据条带化 (striping) 将连续的数据分散在多个磁盘上进行存取, 系统发出的 IO 命令 (不管读 IO 和写 IO 都一样) 就可以在磁盘上被并行的执行, 每个磁盘单独执行自己的那一部分请求,这样的并行的 IO 操作能大大的增强整个存储系统的性能。假设一个 RAID0阵列有 n(n>=2) 个磁盘组成, 每个磁盘的随机读写的 IO 能力都达到 140 的话, 那么整个磁盘阵列的 IO 能力将是 140*n 。同时如果在阵列总线的传输能力允许的话 RAID0的吞吐率也将是单个磁盘的 n 倍。RAID1RAID1在容量上相当于是将两个磁盘合并成一个磁盘来使用了,互为镜像的两个磁盘里面保存的数据是完全一样的, 因此在并行读取的时候速度将是 n 个磁盘速度的总和, 但是写入就不一样了,每次写入都必须同时写入到两个磁盘中,因此写入速度只有 n/2 。RAID5我们那一个有 n(n>=3) 个磁盘的 RAID5阵列来看,首先看看 RAID5阵列的读 IO, RAID5是支持并行 IO 的,而磁盘上的数据呈条带状的分布在所有的磁盘上,因此读 IO 的速度相当于所有磁盘速度的总和。 不过这是在没有磁盘损坏的情况下, 当有一个磁盘故障的时候读取速度也是会下降的,因为中间需要花时间来计算丢失磁盘上面的数据。读取数据的情况相对就要复杂的多了,先来看下 RAID5奇偶校验数据写入的过程,我们把写入的数据称为 D1,当磁盘拿到一个写 IO 的命令的时候,它首先会读取一次要入的地址的数据块中修改之前的数据 D0,然后再读取到当前条带中的校验信息 P0,接下来就根据 D0, P0, D1 这三组数据计算出数据写入之后的条带的奇偶校验信息 P1,最后发出两个写 IO 的命令,一个写入 D1,另一个写入奇偶校验信息 P1。可以看出阵列在实际操作的时候需要读、读、写、写一共 4 个 IO 才能完成一次写 IO 操作,也就是实际上的写入速度只有所有磁盘速度总和的 1/4 。从这点可以看出RAID5是非常不适合用在要大批量写入数据的系统上的。RAID6RAID6和 RAID5很类似,差别就在于 RAID6多了一个用于校验的磁盘。就写 IO 速度上来说这两个是完全一样的,都是所有磁盘 IO 速度的总和。在写 IO 上也很是类似, 不同的是 RAID将一个命令分成了三次读、 三次写一共 6 次 IO 命令才能完成,也就是 RAID6实际写入磁盘的速度是全部磁盘速度之和的 1/6 。可以看出从写 IO 看 RAID6比RAID5差别是很大的。RAID10RAID0读写速度都很好, 却没有冗余保护; RAID5 和 RAID6都有同样的毛病就是写入的时候慢,读取的时候快。那么 RAID1呢?嗯,这里要说的就是 RAID1,其实不管是 RAID10 还是 RAID01,其实都是组合大于 2 块磁盘时候的 RAID1,当先镜像后条带时候就称为 RAID10,先条带后镜像的时候称为 RAID01。从性能上看 RAID01和 RAID10都是一样的,都是 RAID1嘛,但是 RAID10 在重建故障磁盘的时候性能比 RAID01 要快。因为 RAID10 其实就是 RAID1,所以它的性能与 RAID1也就是一样的了,这里不需要再做过多的讨论。top 四个性能指标的变化topIO 响应时间 (IO Response Time) 在任何时候 IO 响应时间值得都是单个 IO 的响应时间, 因此, 不管磁盘是否组成了磁盘阵列, 它的 IO 响应时间应该都是一样的。从前面的计算中我们可以看到,如果 IO 响应时间在 10ms左右的话是很正常的,但是当 IO 响应时间比这个值超出太多的时候, 你就要开始注意了, 很可能就意味着此时你的磁盘系统已经成为了一个瓶颈。topIOPS 综合上面两个部分的讨论我们来估算一下阵列下的磁盘总体 IOPS,在这里我们先假设组成阵列的单个磁盘的随机读写的 IOPS为 140,读写缓存命中率都为 10%,组成阵列的磁盘个数为 4。因为不管是那种阵列,磁盘的读取性能都是所有磁盘之和,所以可以得出下面的读取 IOPS:read IOPS = disk_IOPS / ( 1- read_cache_hit_ratio ) * disk_num = 140 / ( 1- 10 %) * 4 = 622而写入性能就完全不一样了,根据上面的讨论我们可以得出下面结论:RAID0 : 1IOrequest => need 1actualIO on diskRAID1 : 1IOrequest => need 2actualIO on diskRAID5 : 1IOrequest => need 4actualIO on diskRAID6 : 1IOrequest => need 6actualIO on disk由此我们也可以计算出写入 IOPS 估算公式:RAID0 write IOPS = disk_IOPS / ( 1- write_cache_hit_ratio ) * disk_num / acture_IO_num = 140 / ( 1- 10 %) * 4/ 1 = 622RAID1 write IOPS = disk_IOPS / ( 1- write_cache_hit_ratio ) * disk_num / acture_IO_num = 140 / ( 1- 10 %) * 4/ 2 = 311RAID5 write IOPS = disk_IOPS / ( 1- write_cache_hit_ratio ) * disk_num / acture_IO_num = 140 / ( 1- 10 %) * 4/ 4 = 155RAID6 write IOPS = disk_IOPS / ( 1- write_cache_hit_ratio ) * disk_num / acture_IO_num = 140 / ( 1- 10 %) * 4/ 6 = 103实际上从通过上面的计算方法我们还可以估算当给定一个要求的 IOPS的情况下, 估计下使用各个阵列级别所需要的磁盘的数量。当然我们上面的计算方法只是一个估算,我们忽略很多其他的因素,得出的只是一个大概的数值,不过在实际的应用还是有一定的参考作用的。本篇最后附送一个计算磁盘系统 IOPS 的网站―― wmarow’ s disk & disk array calculator ,这个网站提供的计算公式还考虑了诸如阵列条带大小以及主机方面的因素,很有参考价值,至于怎么选择合适的条带大小,请参考【延伸阅读】部分。top 传输速度 (Transfer Rate)/ 吞吐率 (Throughput) 实际上估算除了随机读写的 IOPS 也就知道了随机读写的吞吐率。 对于顺序读写的呢, 还是跟前一篇所讲的一样,主要受限于磁盘的限制,不能再拿 IOPS来衡量了。random_throughtput = random_IOPS * IO_chunk_size