Tachyon是Spark生态系统内快速崛起的一个新项目。 本质上, Tachyon是个分布式的内存文件系统, 它在减轻Spark内存压力的同时,也赋予了Spark内存快速大量数据读写的能力。Tachyon把内存存储的功能从Spark中分离出来, 使Spark能够更专一计算的自己, 以求经过更细的分工达到更高的执行效率。 本文将先向读者介绍Tachyon在Spark生态系统中的使用, 也将分享百度在大数据平台上利用Tachyon取得的性能改善的用例,以及在实际使用Tachyon过程当中遇到的一些问题和解决方案。最后咱们将介绍一下Tachyon的一些新功能。 node
Spark平台以分布式内存计算的模式达到更高的计算性能,在最近引发了业界的普遍关注,其开源社区也十分活跃。以百度为例,在百度内部计算平台已经搭建并运行了千台规模的Spark计算集群,百度也经过其BMR的开放云平台对外提供Spark计算平台服务。然而,分布式内存计算的模式也是一柄双刃剑,在提升性能的同时不得不面对分布式数据存储所产生的问题,具体问题主要有如下几个:算法
当两个Spark做业须要共享数据时,必须经过写磁盘操做。好比:做业1要先把生成的数据写入HDFS,而后做业2再从HDFS把数据读出来。在此,磁盘的读写可能形成性能瓶颈。缓存
因为Spark会利用自身的JVM对数据进行缓存,当Spark程序崩溃时,JVM进程退出,所缓存数据也随之丢失,所以在工做重启时又须要从HDFS把数据再次读出。服务器
当两个Spark做业需操做相同的数据时,每一个做业的JVM都须要缓存一份数据,不但形成资源浪费,也极易引起频繁的垃圾收集,形成性能的下降。网络
仔细分析这些问题后,能够确认问题的根源来自于数据存储,因为计算平台尝试自行进行存储管理,以致于Spark不能专一于计算自己,形成总体执行效率的下降。Tachyon的提出就是为了解决这些问题:本质上,Tachyon是个分布式的内存文件系统,它在减轻Spark内存压力的同时赋予了Spark内存快速大量数据读写的能力。Tachyon把存储与数据读写的功能从Spark中分离,使得Spark更专一在计算的自己,以求经过更细的分工达到更高的执行效率。架构
图1: Tachyon的部署app
图1显示了Tachyon的部署结构。Tachyon被部署在计算平台(Spark,MR)之下以及存储平台(HDFS, S3)之上,经过全局地隔离计算平台与存储平台, Tachyon能够有效地解决上文列举的几个问题,:分布式
当两个Spark做业须要共享数据时,无需再经过写磁盘,而是借助Tachyon进行内存读写,从而提升计算效率。性能
在使用Tachyon对数据进行缓存后,即使在Spark程序崩溃JVM进程退出后,所缓存数据也不会丢失。这样,Spark工做重启时能够直接从Tachyon内存读取数据了。大数据
当两个Spark做业须要操做相同的数据时,它们能够直接从Tachyon获取,并不须要各自缓存一份数据,从而下降JVM内存压力,减小垃圾收集发生的频率。
在上一章咱们介绍了Tachyon的设计,本章咱们来简单看看Tachyon的系统架构以及实现。 图2显示了Tachyon在Spark平台的部署:总的来讲,Tachyon有三个主要的部件:Master, Client,与Worker。在每一个Spark Worker节点上,都部署了一个Tachyon Worker,Spark Worker经过Tachyon Client访问Tachyon进行数据读写。全部的Tachyon Worker都被Tachyon Master所管理,Tachyon Master经过Tachyon Worker定时发出的心跳来判断Worker是否已经崩溃以及每一个Worker剩余的内存空间量。
图2: Tachyon在Spark平台的部署
图3显示了Tachyon Master的结构,其主要功能以下:首先,Tachyon Master是个主管理器,处理从各个Client发出的请求,这一系列的工做由Service Handler来完成。这些请求包括:获取Worker的信息,读取File的Block信息, 建立File等等;其次,Tachyon Master是个Name Node,存放着全部文件的信息,每一个文件的信息都被封装成一个Inode,每一个Inode都记录着属于这个文件的全部Block信息。在Tachyon中,Block是文件系统存储的最小单位,假设每一个Block是256MB,若是有一个文件的大小是1GB,那么这个文件会被切为4个Block。每一个Block可能存在多个副本,被存储在多个Tachyon Worker中,所以Master里面也必须记录每一个Block被存储的Worker地址;第三,Tachyon Master同时管理着全部的Worker,Worker会定时向Master发送心跳通知本次活跃状态以及剩余存储空间。Master是经过Master Worker Info去记录每一个Worker的上次心跳时间,已使用的内存空间,以及总存储空间等信息。
图3: Tachyon的Master设计
图4显示了Tachyon Worker的结构,它主要负责存储管理:首先,Tachyon Worker的Service Handler处理来自Client发来的请求,这些请求包括:读取某个Block的信息,缓存某个Block,锁住某个Block,向本地内存存储要求空间等等。第二,Tachyon Worker的主要部件是Worker Storage,其做用是管理Local Data(本地的内存文件系统)以及Under File System(Tachyon如下的磁盘文件系统,好比HDFS)。第三,Tachyon Worker还有个Data Server以便处理其余的Client对其发起的数据读写请求。当由请求达到时,Tachyon会先在本地的内存存储找数据,若是没有找到则会尝试去其余的Tachyon Worker的内存存储中进行查找。若是数据彻底不在Tachyon里,则须要经过Under File System的接口去磁盘文件系统(HDFS)中读取。
图4: Tachyon的Worker设计
图5显示了Tachyon Client的结构,它主要功能是向用户抽象一个文件系统接口以屏蔽掉底层实现细节。首先,Tachyon Client会经过Master Client部件跟Tachyon Master交互,好比能够向Tachyon Master查询某个文件的某个Block在哪里。Tachyon Client也会经过Worker Client部件跟Tachyon Worker交互, 好比向某个Tachyon Worker请求存储空间。在Tachyon Client实现中最主要的是Tachyon File这个部件。在Tachyon File下实现了Block Out Stream,其主要用于写本地内存文件;实现了Block In Stream主要负责读内存文件。在Block In Stream内包含了两个不一样的实现:Local Block In Stream主要是用来读本地的内存文件,而Remote Block In Stream主要是读非本地的内存文件。请注意,非本地能够是在其它的Tachyon Worker的内存文件里,也能够是在Under File System的文件里。
图5: Tachyon的Client设计
如今咱们经过一个简单的场景把各个部件都串起来:假设一个Spark做业发起了一个读请求,它首先会经过Tachyon Client去Tachyon Master查询所须要的Block所在的位置。若是所在的Block不在本地的Tachyon Worker里,此Client则会经过Remote Block In Stream向别的Tachyon Worker发出读请求,同时在Block读入的过程当中,Client也会经过Block Out Stream把Block写入到本地的内存存储里,这样就能够保证下次一样的请求能够由本机完成。
在百度内部,咱们使用Spark SQL进行大数据分析工做, 因为Spark是个基于内存的计算平台,咱们预计绝大部分的数据查询应该在几秒或者十几秒完成以达到互动查询的目的。但是在Spark计算平台的运行中,咱们却发现查询都须要上百秒才能完成,其缘由如图6所示:咱们的计算资源(Data Center 1)与数据仓库(Data Center 2)可能并不在同一个数据中内心面,在这种状况下,咱们每一次数据查询均可能须要从远端的数据中心读取数据,因为数据中心间的网络带宽以及延时的问题,致使每次查询都须要较长的时间(>100秒)才能完成。更糟糕的是,不少查询的重复性很高,一样的数据极可能会被查询屡次,若是每次都从远端的数据中心读取,必然形成资源浪费。
为了解决这个问题,咱们借助Tachyon把数据缓存在本地,尽可能避免跨数据中心调数据。当Tachyon被部署到Spark所在的数据中心后,每次数据冷查询时,咱们仍是从远端数据仓库拉数据,可是当数据再次被查询时,Spark将从同一数据中心的Tachyon中读取数据,从而提升查询性能。实验代表:若是从非本机的Tachyon读取数据,耗时降到10到15秒,比原来的性能提升了10倍;最好的状况下,若是从本机的Tachyon读数据,查询仅需5秒,比原来的性能提升了30倍,效果至关明显。
在使用了这个优化后,热查询性能达到了互动查询的要求,但是冷查询的用户体验仍是不好。分析了用户行为后,咱们发现用户查询的模式比较固定:好比不少用户天天都会跑同一个查询,只是所使用过滤数据的日期会发生改变。借助此次特性,咱们能够根据用户的需求进行线下预查询,提早把所须要的数据导入Tachyon,从而避免用户冷查询。
图6: Tachyon在百度大数据平台的部署
在使用Tachyon过程当中,咱们也遇到了一些问题:在刚开始部署Tachyon的时候, 咱们发现数据彻底不能被缓存,第一次与后续的查询耗时是同样的。如图7的源代码所示:只有整个数据Block被读取后,这个Block才会被缓存住;不然缓存的操做会被取消。好比一个Block是256MB,若是你读了其中的255MB,这个Block仍是不会被缓存,由于它只需读取整个block中的部分数据。在百度内部,咱们不少数据是用行列式存储的,好比ORC与Parquet文件,每次查询只会读其中的某几列, 所以不会读取完整的Block, 以至block缓存失败。为了解决这个问题,咱们对Tachyon进行了修改,若是数据Block不是太大的话,冷查询时即便用户请求的只是其中几列,咱们也会把整个Block都读进来,保证整个Block能被缓存住,而后再次查询的话就能够直接从Tachyon读取了。在使用了修改的版本后,Tachyon达到了咱们期待的效果,大部分查询能够在10秒内完成。
图7: Tachyon缓存数据逻辑
咱们把Tachyon看成缓存来使用,可是每台机器的内存有限,内存很快会被用完。 若是咱们有50台机器,每台分配20GB的内存给Tachyon,那么总共也只有1TB的缓存空间,远远不能知足咱们的须要。在Tachyon最新版本有一个新的功能: Hierarchical Storage,即便用不一样的存储媒介对数据分层次缓存。如图8所示,它类于CPU的缓存设计:内存的读写速度最快因此能够用于第0级缓存,而后SSD能够用于第1级缓存,最后本地磁盘能够做为底层缓存。这样的设计能够为咱们提供更大的缓存空间,一样50台机器,如今咱们每台可贡献出20TB的缓存空间,使总缓存空间达到1PB,基本能够知足咱们的储存需求。与CPU缓存相似,若是Tachyon的block Replacement Policy设计得当,99%的请求能够被第0级缓存(内存)所知足,从而在绝大部分时间能够作到秒级响应。
图8: Tachyon Hierarchical Storage
当Tachyon收到读请求时,它首先检查数据是否在第0层,若是命中,直接返回数据,不然它会查询下一层缓存,直到找到被请求的数据为止。数据找到后会直接返回给用户,同时也会被Promote到第0层缓存,而后第0层被替换的数据Block会被LRU算法置换到下一层缓存。如此一来,若是用户再次请求相同的数据就会直接从第0层快速获得,从而充分发挥缓存的Locality特性。
当Tachyon收到写请求时,它首先检查第0层是否有足够空间,若是有,则直接写入数据后返回。不然它会查询下一层缓存,直到找到一层缓存有足够空间,而后把上一层的一个Block用LRU算法推到下一层,如此类推,直到把第0层有足够空间以写入新的数据,而后再返回。这么作的目的是保证数据被写入第0层,若是读请求立刻发生在写请求后,数据能够快速被读取。但是,这样作的话写的性能有可能变的不好:好比头两层缓存都满的话,它须要把一个Block从第1层丢到第2层,再把一个Block从第0层丢到第1层,而后才能写数据到第0层,再返回给用户。
对此咱们作了个优化, 与其层层类推腾出空间,咱们的算法直接把数据写入有足够空间的缓存层,而后快速返回给用户。若是缓存全满,则把底层的一个Block置换掉,而后把数据写入底层缓存后返回。通过实验,咱们发现优化后的作法会把写延时下降约50%,大大的提升了写的效率。可是读的效率又如何呢,因为在TACHYON里,写是经过Memory-Mapped File进行的,因此是先写入内存,再Flush到磁盘,若是读是立刻发生在写以后的话,其实会从操做系统的Buffer,也就是内存里读数据,所以读的性能也不会降低。
Hierarchical Storage很好地解决了咱们缓存不够用的问题,下一步咱们将继续对其进行优化。好比,如今它只有LRU一种置换算法,并不能知足全部的应用场景, 咱们将针对不一样的场景设计更高效的置换算法,尽可能提升缓存命中率。
我我的相信更细的分工会达到更高的效率,Spark做为一个内存计算平台,若是使用过多的资源去缓存数据,会引起频繁的垃圾收集,形成系统的不稳定,或者影响性能。在咱们使用Spark的初期,系统不稳定是咱们面临的最大挑战,而频繁的垃圾收集正是引发系统不稳定最大的缘由。好比当一次垃圾收集耗时过长时,Spark Worker变的响应很是不及时,很容易被误认为已经崩溃,致使任务从新执行。Tachyon经过把内存存储的功能从Spark中分离出来,让Spark更专一在计算自己,从而很好的解决了这个问题。随着内存变的愈来愈便宜,咱们能够预期将来一段时间里,咱们的服务器里可以使用的内存会不断增加,Tachyon会在大数据平台中发挥愈来愈重要的做用。如今仍是Tachyon发展的初期,在本文完成时Tachyon才准备发布0.6版,还有不少功能亟需完善,这也是一个好机遇,有兴趣的同窗们能够多关注Tachyon,到社区里进行技术讨论以及功能开发。
刘少山
百度美国硅谷研发中心高级架构师,主要研究方向分布式系统以及大数据计算与存储平台。