硬件技术的发展给存储和数据库软件技术提供了新的机会。近年来SSD开始流行,那么SSD能否给Hadoop/HBase带来性能的提升呢?来自Facebook数据团队的工程师们做了相关的研究和实验工作。
本文是http://hadoopblog.blogspot.com/2012/05/hadoop-and-solid-state-drives.html (需自备梯子)的翻译并加上了一些自己的思考,版权归原博客作者所有。
先说下SSD吧,SSD没有传统机械硬盘的机械寻道时间而带来的延迟,所以IOPS性能可以达到100-200K(而15K的SAS一般在100左右),所以能提供相对于机械硬盘100+倍的的小文件读取性能,而且在连续读取方面也能带来3倍左右的性能提升。但是在写入性能方面,SSD由于擦除等因素的存在,导致写入性能提升并不是很大,而且顺序写性能明显由于随机写,所以实践中要尽量避免随机写SSD。SSD的读写性能差距较大,而机械硬盘读写性能差距不大。
Use case:
Hadoop在Facebook主要有两种使用场景:基于MapReduce的OLAP类分析型应用和简单的key-value存储。
前者的场景下 数据基本上是顺序读取的,不会所以用SSD可能获益不多。多数的MapReduce任务是CPU密集型的(decompression,deserialization等),瓶颈在于data shuffle过程中的map-output-fetch,加快从HDFS中读取文件的IO速度并不能显著提高MapReduce任务的执行速度。可以把Map任务的输出写到SSD上,这样能够加快data shuffle中map-output-fetch的速度 ,所以说这是一个优化思路。
对于后者的场景,SSD能够提升online-transaction-process-workload的速度是有理论依据的,所以说也是一个优化思路。
Background:
SSD的读写延迟和机械硬盘相比是有数量级的差距的,特别是在随机读写的时候。例如在随机读上,SSD的随机读取延迟大概是30 micro-seconds(微秒),而机械硬盘随机读取延迟大概在5-10 milli-secondes(毫秒)。SSD能支撑100k-200k的OPS,而机械硬盘仅能支撑200-300的OPS。这意味着随机读写在SSD上不是瓶颈。(这是Dhruba Borthakur的博客中的说法,但是我认为随机写在SSD上还是要尽量避免的。)另外一方面,现有的数据库架构都是基于机械硬盘设计的,没有考虑到SSD的IO代价模型。那么SSD能否给现有基于机械硬盘设计的数据库带来性能的提升呢?Facebook的数据团队做了实验。他们分别做了基于HDFS和HBase的随机读取实验,看到底SSD能够跑出什么样的性能。
HDFS random-read on cached data:
这个实验中,他们创建了一个两节点的集群,一个NameNode,一个DataNode。创建一个2G的HDFS文件,文件的block大小是256M,拷贝数是1,所以一共有8个block。DataNode配置了CPU超线程,同时本地文件系统用的是XFS存放block文件。Benchmark程序也在DataNode上跑,同时打开了hdfs-read-shortcircuit功能(https://issues.apache.org/jira/browse/HDFS-2246),这样DFSClient就会绕过与DataNode的网络通信而直接从本地磁盘文件系统读取数据。把这2G文件都放在操作系统的缓存中,所以整个测试过程没有磁盘IO。用这样的测试场景来模拟SSD的。然后分别用不同的client线程数测试,每个client线程从HDFS中读取16K的数据。由于一共就8个block,所以DFSclient缓存了所有的BlockLocations,所以这个过程没有与NameNode的通信。
在开始的几轮实验中,最大的随机读吞吐量大概在50K OPS,但是CPU还很空闲。他们发现在hdfs-read-shortcircuit过程中花费了非常可观的时间在DNS查询和metric-counters的更新上。在修改了这部分的代码之后,他们的最大随机读吞吐量已经达到了 92K OPS,同时CPU接近95%的利用率。下图是实验结果,从中可以看出基于HDFS的数据库并不能完全利用SSD提供的IOPS。
然后他们用profile的形式来跑HDFS的代码显示,DFSClient端的代码路径太长了,对缓存的数据随机读取产生了相当大的影响。使用机械硬盘的数据读取磁盘IO时间在毫秒的数量级,那么DFSClient读取流程的开销可能不是那么明显。但是当数据被存储在操作系统的cache或者在SSD中时,DFSClient的读取流程的开销就比较大了,这部分需要重新设计读取流程。另外一个思路是用C/C++实现一个read-only的client,避免现在基于Java实现的DFSClient的开销。
HBase random-get on cached data:
然后他们做了类似的实验在HBase上。创建了一个表,只有一个region,并且这个region所有的数据都是缓存在一台RegionServer操作系统的cache中。同样用这样的方法模拟SSD。用4个客户机做random-get操作。RegionServer配置最大2000个线程,HBase的table使用lzo压缩算法并开启delta-encoding-fast-diff功能。同样整个过程没有磁盘IO。HBase的吞吐量在35K OPS左右,并且同时CPU使用没有超过45%。在RegionServer上严重的锁竞争和上下文切换使得CPU的利用率比较低。实验结果如下图所示。
What dose this mean
两个实验表明,HDFS和HBase都不能完全利用SSD提供的高效IOPS。所以要想把HDFS/HBase用在SSD上跑出很好的性能,需要对代码进行重构,但是这需要花大量的时间。而且这个结论同样适用于其他数据库应用,因为现有数据库都是基于机械磁盘的IO代价模型设计的,不适用与SSD硬盘。能够完全利用SSD磁盘的数据库架构需要从头开始设计。
也有些人对这个实验提出了一些讨论和意见:
Q:35K OPS的HBase操作代表着多少次磁盘IO的OPS,一般情况下一次HBase操作并不是一次磁盘IO操作,也就是所谓的IO放大(IO amplification)。大多数数据库IO amplification大概是1:5到1:10,主要包括record相应的索引的查询和更新,transaction commit,index rebuild, multi-versioning checkpoints, archiving, WAN replication等。同时IO amplification也是负载相关的。
A:35K HBase OPS就代表着35K的磁盘IOPS,因为workload是纯随机读取,没有其他操作。
Q:可以考虑在HDFS中增加存储设备信息作为API开发给上层。例如对于HBase应用来说,把数据文件存放在机械硬盘上,把WAL和flush file等生命周期短、经常访问的数据存放在SSD上。有点类似于EMC他们经常说的分层存储的概念。
A:这种思路很好,可行性也很高。但是这样的话,瓶颈就会落到CPU核心数目越来越多,这些核心不能被高效利用。(http://pdos.csail.mit.edu/multicore/ 这个项目研究了操作系统和软件在多核处理器上的可扩展性问题)
Q:有人提出混合存储,可以把HDFS的block的第一个备份存在SSD上,另外两个备份存在机械硬盘上。甚至可以指定哪个表,哪个Region,哪个HFile block存放在SSD上。然后读取的时候首先尝试在SSD上的数据,这样就可以显著提升总的读取性能,而且不降低reliability。
A:混合存储的思路也很好,但是一个程序只能从HDFS DataNode上获得16K左右的随机读取OPS,并不能完全利用SSD提供的IOPS潜能。
Q:对于SSD来说,单一进程不能跑满SSD的IOPS,是否可以考虑多个进程实例来共享SSD所能提供的所有的200K+的IOPS呢?
A:是的,事实上在Facebook就是在每个SSD的机器上跑多个进程实例,为的就是提高IOPS的利用率。
总结与感想:SSD改变了传统的基于机械硬盘的IO代价模型,那么对于基于机械硬盘设计的数据库应用来说需要重构了。对于HDFS和HBase应用来说,需要优化的空间也很大,特别是LSM(http://www.springerlink.com/content/rfkpd5yej9v5chrp/?MUD=MP)模型的提出和使用,给HBase设计和优化提供了很大的空间。同时SSD带来了磁盘IOPS的数量级的提升,但是软件逻辑中锁操作使得CPU并不能跑满,所以就提出了单台server跑多个实例的概念,即多进程的概念。Redis也是单线程逻辑,单机多进程部署,从中可以看出软件特别是数据库软件开发的一种回归。多线程程序锁的争用导致CPU利用率低下,使得很多程序开始考虑单线程、多进程的概念,而且降低debug的成本,提高了鲁棒性。听说Amazon推出的DynamoDB也是基于SSD的,后面看看它是怎么用的。
转自 http://yanbohappy.sinaapp.com/?p=71