分布式系统硬件基础之漫谈存储设备

我们在分析各种分布式系统场景时不可避免地会讨论到数据的读写,很多时候我们会对数据的读写做很多的优化和特殊处理,而这些操作的背后根源都离不开数据存储的硬件,本文就来和大家谈一谈这其中设计的各种硬件和相应的技术。

Cache和读写

我们都知道把数据放到内存中,这样有读请求过来的时候就可以直接从内存中读取到相关数据(hit cache的情况),而不需要去访问具体的物理磁盘,从而减少了disk I/O的操作。同样地,写也可以写到内存中,只是和读不同的是,内存写终究只是一个中间状态,你最终还是要写到磁盘中才行,所以内存到写操作来说只起到一个delay的作用(当然假如你没有persist保存的情况下,可能也不需要写到磁盘,但我们讨论正常的需要persist保存的情况)。

不过当我们再仔细想一下,其实cache对写并不仅仅是一个delay的作用,它其实还有一些别的好处:

  • 多次写,一次flush:我们很容易就可以想到假如我们对一个数据进行了多次更新,然后再进行一次flush到磁盘,那么这些多次的更新操作其实就只要一次磁盘的写就好了。这从另一个角度减少了磁盘的写操作。
  • I/O Merge另外一个好处,就是我们可能有多个数值在内存中被修改了,但我们可以把这些数值集合在一起,一次性更新,这样真正的物理写就可以看成是一次磁盘操作了。

理解了这一点之后,我们再来想想我们之前提到的Write-ahead的logging策略。在write-ahead logging中,内存的修改并没有立即flush到disk中(减少了Random IO的操作),而是写到了一个sequential的log文件中(速度比较快),然后再通过一个后台进程来进行优化写(比如合并之类的)。

这里有人会问为什么Random I/O的操作没有Sequential I/O写的速度快,这是因为对物理磁盘来说,磁头移动是需要时间的,Random I/O就意味着每次要写的偏移地址之间有很大的差别,所以这个磁头需要不停地移动,这显然是很费时间的。而Sequential I/O则不尽然,假如偏移地址是连续的,磁头就不需要不停的移动寻找新的写的偏移,这样就减少了磁头偏移的时间(这里还要看各个厂家的fw的设置,就是sequential写之间的间隔对这个也是有影响的,因为假如sequential写之间间隔时间比较长,那么磁头可能会被reset,所以我们一般认为overlap sequential写是最佳的方案)。

SSD

其实我们上文提到的磁盘准确来讲是HDD,事实上在我们现如今的系统中HDD是最后一层存储,在其和Memory之间还存在另外一种存储介质:SSD。它和HDD不同,不再使用磁头和磁盘来进行存储,它是基于固态电子存储芯片阵列制成的硬盘。简单来说,它有以下优点:

  • 和HDD相比来说,它的random读写的速度都要快很多。一般来说,它的读要比写稍微快一点点。稍后我们来解释这个原因。
  • Sequential的读写也比HDD速度要快。但是因为HDD的Random 读写比Sequential要差很多,所以单纯比较Sequential的读写速度,SSD提升倍数没有Random读写提升得那么明显,但也有很大的提升。
  • 同步操作有很大的提升。因为HDD只有一个磁头(现在有新的HDD可以支持多个磁头,但是每个磁头也只能访问特定的扇区),所以对于同步操作来说就不能做到真正的同步,说白了还是一个单线程的操作。而SSD则没有这样的限制。

对SSD来说,读操作比较简单,你可以不停地读一个小的单元。但是写操作就比较复杂了,在写之前你必须做一个擦除的操作,而且每次擦除只能是一个block,比如512KB。这个擦除操作还是比较慢的,而且最终会把这个block擦坏了(想象一下,你在一张纸上不停用铅笔写,不停要橡皮擦,最终这张纸的命运就是被擦破)。所以我们对HDD一般讨论的是I/O,而对SSD则一般研究的是寿命。

提到block的擦除,我们就不得不聊一聊SSD的GC(Garbage Collection),其实也很好理解,就是为了让一些block预先准备好了,SSD会回收一些block。这个时候就会有一个数据搬移的过程,比如把几个block中的少量数据(就是数据量不到一个block,但是占用了一个block)移到同一个block中,然后这几个block就可以空出一些出来。这种搬移的操作,其实也是一个新的写的循环,我们称之为Write amplification。你也可以想象,这里的GC操作是需要reserve一些空间来进行的,比如有一个空的block,我们就可以很容易把几个block中的数据搬运过去,假如空的block越来越少,那么搬运的代价就越大。

这也是为什么我们发现当SSD要写满的情况下,性能就会急剧下降。比如你写110GB文件到160GB的SSD和写到同样的320GB的SSD得到的速度可能会有差别,究其根源还是因为需要等待擦除操作。一般来说直接写到一个空的block只需要几百微秒,但是擦除则可能需要几毫秒的时间。

RAID

RAID全称廉价磁盘冗余阵列(Redundant Arrays of Independent Disk),它有不同级别的设置,我们可以简单看看几个它的常见的级别:

  • RAID0: 这个级别是最便宜的也是性能最好的RAID设置。因为他其实没有冗余,一般来说用来存储一些你不怎么在意的数据,比如replica或者即将废弃的数据。所以不是所有的RAID都有这个R(Redundant)的,这种情况下,如果磁盘发生了损坏,是没有办法恢复数据的(除非你有别的redundant在别的机器上)
  • RAID1: RAID的读性能是很好的,同时它会duplicate数据到不同磁盘上,所以这个设置终于有了真正的R的出现。一般来说对于类log系统可以使用这一配置。
  • RAID5: 这个配置可以保证一个磁盘发生损坏的情况下,数据还可以恢复。从每个单元的存储消耗来看,它是最经济的做法。因为你其实只额外多了一个磁盘就可以达到redundant的效果。它的写的效率其实比较低,因为要把额外的校验位写到磁盘中。所以一般来说它比较适合读比较重的场景。另外这种配置下,性能最大的问题点其实在于磁盘出问题时的恢复。
  • RAID6:相对RAID5的只能有一个磁盘出问题的场景,RAID6能支持两个磁盘同时出问题。
  • RAID10:RAID10对数据存储来说是一个不错的选择,它的读写效率都不错。所以和RAID5类似,生产场景中使用得也比较多,它的安全性比较高,但是空间利用率相对比较低。
  • RAID50: 其实就是一系列RAID5,对大得数据集可以使用。(比如data warehouse等)

简单的比较可以见下表:

最后在简单提一下,RAID中cache其实也是一个比较重要的概念,只是说这个cache和我们常见的benefit读不太一样,它更多地会被用来帮助写。

总结

至此,我们就简单介绍了数据存储的几种常见的硬件HDD,SSD,RAID。理解他们有助于我们在今后的工作中优化数据读写,尤其是性能研究的时候会有很大的帮助。

You may also like...

Leave a Reply

Your email address will not be published.