Tachyon

Tachyon是分布式文件系统,也就是说Tachyon实现了文件的存储结构,比如inode节点,数据block,以及文件查询的API,比如某个文件在哪个block上面,并且能以文件流的形式对数据进行读写,可以理解为这个是和NTFS、EXT4这些进行比较的,只是Tacyon的数据都放在内存中,不在硬盘中,快快快!而Redis就是个内存数据库,是的,是个数据库,数据库是构建在存储系统之上的,Redis用了内存和文件系统,和Tachyon不在一个层次上。Redis和Tachyon都是可以作为分布式cache层对系统进行加速,唯一不同在于Redis是kv接口,Tachyon是文件系统接口



Tachyon是Spark生态系统内快速崛起的一个新项目。 本质上, Tachyon是个分布式的内存文件系统, 它在减轻Spark内存压力的同时,也赋予了Spark内存快速大量数据读写的能力。Tachyon把内存存储的功能从Spark中分离出来, 使Spark可以更专注计算的本身, 以求通过更细的分工达到更高的执行效率。 本文将先向读者介绍Tachyon在Spark生态系统中的使用, 也将分享百度在大数据平台上利用Tachyon取得的性能改善的用例,以及在实际使用Tachyon过程中遇到的一些问题和解决方案。最后我们将介绍一下Tachyon的一些新功能。



Tachyon简介
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的部署



图1显示了Tachyon的部署结构。Tachyon被部署在计算平台(Spark,MR)之下以及存储平台(HDFS, S3)之上,通过全局地隔离计算平台与存储平台, Tachyon可以有效地解决上文列举的几个问题,:



当两个Spark作业需要共享数据时,无需再通过写磁盘,而是借助Tachyon进行内存读写,从而提高计算效率。
在使用Tachyon对数据进行缓存后,即便在Spark程序崩溃JVM进程退出后,所缓存数据也不会丢失。这样,Spark工作重启时可以直接从Tachyon内存读取数据了。
当两个Spark作业需要操作相同的数据时,它们可以直接从Tachyon获取,并不需要各自缓存一份数据,从而降低JVM内存压力,减少垃圾收集发生的频率。
Tachyon系统架构
在上一章我们介绍了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写入到本地的内存存储里,这样就可以保证下次同样的请求可以由本机完成。



Tachyon在百度内部的使用
在百度内部,我们使用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的一些新功能
我们把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,到社区里进行技术讨论以及功能开发。

Tachyon是一个以内存为核心的开源分布式存储系统,也是目前发展最迅速的开源大数据项目之一。Tachyon为不同的大数据计算框架(如Apache Spark,Hadoop MapReduce, Apache Flink等)提供可靠的内存级的数据共享服务。此外,Tachyon还能够整合众多现有的存储系统(如Amazon S3, Apache HDFS, RedHat GlusterFS, OpenStack Swift等),为用户提供统一的、易用的、高效的数据访问平台。本文首先向读者介绍Tachyon项目的诞生背景和目前发展的情况;然后详解Tachyon系统的基本架构以及目前一些重要的功能;最后,分享一个Tachyon在百度大数据生产环境下的几个应用案例。



1.Tachyon简介
随着技术的发展,内存的吞吐量在不断地提高,单位容量的内存价格在不断降低,这为“内存计算”提供可能。在大数据计算平台领域,采用分布式内存计算模式的Spark验证了这一点。Spark相比于MapReduce大大提升了大数据的计算性能,受到了业界和社区的广泛关注。然而,还是有很多问题在计算框架层难以解决,如:不同的Spark应用或不同计算框架(Spark,MapReduce,Presto)间仍需通过基于磁盘的存储系统(如HDFS,Amazon S3等)交换数据;当Spark计算任务崩溃,JVM缓存的数据会丢失; JVM中大量缓存的数据增加了Java垃圾回收的压力。



Tachyon最初出现是为了有效地解决了上述问题,它计划构建一个独立的存储层来快速共享不同计算框架的数据,实现方式上将数据置于堆外(off-heap)内存以避免大量垃圾回收开销。例如,对应Spark应用而言,可以带来以下作用:



不同Spark应用,甚至不同计算平台上的应用需要数据共享时,通过Tachyon进行内存读写,避免缓慢的磁盘操作。
使用Tachyon进行数据缓存,当Spark任务崩溃,数据仍缓存在Tachyon内存中,任务重启后能够直接从Tachyon中读取数据。
多个Spark应用理论上甚至可以共享同一份Tachyon缓存的数据,避免内存资源的浪费,减轻Java垃圾回收的压力。
图片描述



图1. Tachyon在生态系统的位置
图1给出了Tachyon部署时所处的位置。Tachyon被部署在计算平台之下和现有的存储系统之上,能够在不同计算框架间共享数据。同时,现有的海量数据不需要进行迁移,上层的计算作业仍能通过Tachyon访问到底层存储平台上的数据。Tachyon作为一个以内存为中心的中间存储层,不仅能极大地提升上层计算平台的性能,还能充分利用不同特性的底层存储系统,更可以有效地整合两者的优势。



Tachyon最初是由李浩源博士发起的源自UC Berkeley AMPLab的研究项目(该实验室也是Mesos和Spark的发源地)。自2013年4月开源以来,Tachyon社区不断壮大,已经成为发展速度最快的开源大数据项目之一,目前已有来自超过50个组织机构的200多人参与到了对Tachyon项目的贡献中,也有超过100家公司部署了Tachyon。于此同时,Tachyon的核心创建者和开发人员创立了Tachyon Nexus公司,其中不乏UC Berkeley、CMU等博士以及Google, Palantir, Yahoo!等前员工。 2015年3月美国华尔街日报报道了Tachyon Nexus获得硅谷著名风投Andreessen Horowitz 的750万美元A轮投资。



图片描述



图2. Tachyon项目贡献者的增长情况
在学术界, 国内的南京大学PASA大数据实验室一直积极关注并参与到Tachyon项目的开发中,共向Tachyon社区贡献了100多个PR,近300次commit,包括为Tachyon实现性能测试框架tachyon-perf,增加LFU、LRFU等多个替换策略,改进WebUI页面,以及其他一些性能优化的工作。此外,我们还撰写了Tachyon相关的中文博客,以便中文读者和用户能够更深入地了解和使用Tachyon。



在工业界,百度也把Tachyon运用到其大数据系统中, Tachyon在过去一年中稳定的支持着百度的可交互式查询业务,令百度的交互式查询提速30倍。在验证了Tachyon的高性能以及可靠性后,百度在内部使用Tachyon的0.9版成功部署了1000个worker的世界最大Tachyon集群,总共提供50TB的内存存储。此集群在百度内部已经稳定运行了一个月,也验证的Tachyon的可扩展性。于此同时,百度的另外一个Tachyon部署中用Tachyon层次化数据管理了2PB数据。



2.Tachyon系统架构
这一章中我们简介Tachyon系统的基本架构,包括Tachyon的基本组件及其功能。



图片描述



图3. Tachyon的系统架构
图2是Tachyon系统的基本架构,主要包括4个基本组件:Master、Worker和Client,以及可插拔的底层存储系统(Underlayer Storage System)。每个组件的具体功能职责如下:



Tachyon Master主要负责管理两类重要信息。第一,Tachyon Master中记录了所有数据文件的元数据信息,包括整个Tachyon命名空间(namespace)的组织结构,所有文件和数据块的基本信息等。第二,Tachyon Master监管着整个Tachyon系统的状态,包括整个系统的存储容量使用情况,所有Tachyon Worker的运行状态等。



Tachyon Worker负责管理本地节点上的存储资源,包括内存、SSD和HDD等。Tachyon中的所有数据文件被划分为一系列数据块,Tachyon Worker以块为粒度进行存储和管理,如:为新的数据块分配空间、将热数据块从SSD或HDD移至内存、实时或定期备份数据块到底层存储系统。同时,Tachyon Worker定时向Tachyon Master发送心跳(heartbeat)以告知自身的状态信息。



Tachyon Client是上层应用访问Tachyon数据的入口。访问过程可以包括如下几步:①Client向Master询问数据文件的基本信息,包括文件位置,数据块大小等;②Client尝试从本地Worker中读取对应数据块,若本地不存在Worker或者数据块不在本地Worker中,则尝试从远程Worker中读取;③若数据还未被缓存到Tachyon中,则Client会从底层存储系统中读取对应数据。此外,Tachyon Client会向所有建立连接的Tachyon Master和Tachyon Worker定时发送心跳以表示仍处于连接租期中,中断连接后Tachyon Master和Tachyon Worker会回收对应Client的临时空间。



底层存储系统既可以被Tachyon用来备份数据,也可以作为Tachyon缓存数据的来源,上层应用在使用Tachyon Client时也能直接访问底层存储系统上的数据。底层存储系统保证了Tachyon Worker在发生故障而崩溃后不会导致数据丢失,同时也使得上层应用在迁移到Tachyon的同时不需要进行底层数据的迁移。目前Tachyon支持的底层存储系统有HDFS,GlusterFS,Amazon S3,OpenStack Swift以及本地文件系统,且能够比较容易地嵌入更多的现有存储系统。



在实际部署时, Tachyon Master通常部署在单个主节点上(Tachyon也支持多个节点上部署Tachyon Master,并通过使用ZooKeeper来防止单点故障);将Tachyon Worker部署在多个从节点;Tachyon Client和应用相关,可以位于任何一个节点上。



3.Tachyon的特色功能
本节我们简介Tachyon面向上层应用的特色功能。



3.1 支持多种部署方式



作为大数据系统中的存储层,Tachyon为用户提供了不同的启动模式、对资源管理框架的支持、以及目标运行环境,能够部署多种大数据平台环境中:



启动模式:以正常模式启动单个Tachyon Master;以高级容错模式启动多个Tachyon Master,并使用ZooKeeper进行管理;
资源管理框架:以Standalone方式直接运行在操作系统之上;运行在Apache Mesos之上;运行在Apache Hadoop Yarn之上;
目标运行环境:部署在本地集群环境中;部署在Virtual Box虚拟机中;部署在容器(如Docker)中;部署在Amazon EC2云平台上(Tachyon社区正在开发支持Tachyon部署在阿里云OSS上)
用户可以自由选择不同的启动模式、资源管理框架和目标运行环境,Tachyon为多种组合都提供了相应的启动脚本,能够很方便地将Tachyon部署在用户的环境中。



3.2 层次化存储



Tachyon的层次化存储充分利用了每个Tachyon Worker上的本地存储资源,将Tachyon中的数据块按不同热度存放在了不同的存储层中。目前Tachyon所使用的本地存储资源包括MEM(Memory,内存)、SSD(Solid State Drives,固态硬盘)和HDD(Hard Disk Drives,磁盘)。在Tachyon Worker中,每一类存储资源被视作一层(Storage Tier),每一层又可以由多个目录(Storage Directory)组成,并且用户可以设置每个存储目录的容量。



在读写Tachyon数据时,分配器(Allocator)负责为新的数据块选择目标存储目录,替换器(Evictor)负责将冷数据从内存剔至SSD和HDD,同时将热数据从SSD和HDD提升至内存中。目前分配器所使用的分配策略包括Greedy、MaxFree和RoundRobin。替换器所使用的替换策略包括Greedy、LRU/PartialLRU、LRFU。额外地,Tachyon还为用户提供了Pin功能,支持用户将所需要的数据始终存放在内存中。关于如何配置Tachyon层次化存储,可以进一步参考Tachyon官方文档。



3.3 灵活的读写机制



为了充分利用多层次的存储资源和底层存储系统,Tachyon为用户提供了不同的读写类型(ReadType/WriteType)API,用于灵活控制读写数据时的行为方式,不同的读写类型及其含义如表1所示。



表1. 读写类型(ReadType/WriteType)的取值及其含义
图片描述



除了上述的读写类型外,Tachyon还提供了另一套控制方式:TachyonStorageType和UnderStorageType,用于分别控制在Tachyon存储和底层存储系统上的读写行为,具体取值及其含义如表2所示。实际上,这种控制方式是Tachyon-0.8之后新增的,控制粒度更细,功能也更多,因此推荐用户采用这种方式控制读写行为。



表2. TachyonStorageType/UnderStorageType的值及其含义
图片描述



3.4 文件系统层的Lineage容错机制



在Tachyon中,Lineage表示了两个或多个文件之间的世系关系,即输出文件集B是由输入文件集A通过怎样的操作得到的。有了Lineage信息后,在文件数据意外丢失时,Tachyon就会启动重计算作业,根据现有的文件重新执行同样的操作,以恢复丢失的数据。图3给出了一个Lineage示例,文件集A通过一个Spark作业生成文件集B;文件集C通过另一个Spark作业生成文件集D;B和D作为同一个MapReduce作业的输入,输出为文件集E。那么,如果文件集E意外丢失,并且没有备份,那么Tachyon就会重新启动对应的MapReduce作业,再次生成E。



图片描述
图4. Tachyon的Lineage机制
3.5 统一命名空间



对于Tachyon的用户而言,通过Tachyon提供的接口所访问到的是Tachyon文件系统的命名空间。当用户需要访问Tachyon以外的文件和数据时,Tachyon提供了Mount接口,能够将外部存储系统的文件或目录挂载到Tachyon的命名空间中。这样用户就能够在统一的Tachyon命名空间中,使用相同或者自定义的路径,访问其他存储系统上的文件和数据。



图片描述



图5. Tachyon的统一命名空间
3.6 HDFS兼容接口



在Tachyon出现之前,诸如Hadoop MapReduce以及Apache Spark的应用大多使用HDFS、Amazon S3等存储文件。Tachyon为这些应用提供了一套HDFS兼容的接口(确切地说,是兼容了org.apache.hadoop.fs.FileSystem的接口),用户可以在不改动应用源码的情况下,通过以下3个步骤,将目标文件系统更改为Tachyon:



1.将对应版本Tachyon Client的jar包添加至运行环境的CLASSPATH中;
2.添加Hadoop配置项<“fs.tachyon.impl”, “tachyon.hadoop.TFS”>;
3.将原先的”hdfs://ip:port/file/X”路径更改为”tachyon://ip:port/file/X”。



通常,用户可以结合使用“HDFS兼容接口”和“统一命名空间”这两个特性,将原先的大数据应用直接运行在Tachyon之上,而不需要进行任何代码和数据的迁移。



3.7 丰富的命令行式工具



Tachyon自带了一个名为 “tfs”的命令行工具,能够让用户以命令行的方式与Tachyon交互,而不需要编写源码来查看、新建、删除Tachyon文件。例如:



图片描述



“tfs”工具提供的全部命令使用方式详见Tachyon官方文档。



3.8 方便管理的WebUI



除了“tfs”工具外,Tachyon还在Tachyon Master和每个Tachyon Worker节点上启动了一个网页管理页面,用户可以通过浏览器打开对应的WebUI(默认为http://:19999和http://:30000)。WebUI上列举了整个Tachyon系统的基本信息、所有Tachyon Worker的运行状态、以及当前Tachyon系统的配置信息。同时,用户可以直接在WebUI上浏览整个Tachyon文件系统、预览文件内容、甚至下载具体的某个文件。



图片描述



图6. Tachyon的WebUI
3.9 实时指标监控系统



图片描述



图片描述
图7. Tachyon监控的实时指标(WebUI模式、JSON格式)
对于高级用户和系统管理人员,Tachyon提供了一套实时指标监控系统,实时地记录和管理了Tachyon中一些重要的统计信息,包括存储容量使用情况、现有Tachyon文件数、对文件的操作次数、现有的数据块数、对数据块的操作次数、总共读写的字节数等。根据用户的配置,这些指标能够以多种方式进行输出:标准控制台输出、以CSV格式保存为文件、输出到JMX控制台、输出到Graphite服务器以及输出到Tachyon的WebUI。



3.10支持Linux FUSE



Tachyon-FUSE是Tachyon最新开发版的新特性,由Tachyon Nexus和IBM共同主导开发。在Linux系统中,FUSE(Filesystem in Userspace,用户空间文件系统)模块使得用户能将其他文件系统挂载到本地文件系统的某一目录下,然后以统一的方式进行访问。Tachyon-FUSE的出现使得用户同样可以将Tachyon文件系统挂载到本地文件系统中。通过Tachyon-FUSE,用户/应用可以使用访问本地文件系统的方式来访问Tachyon。这更加方便了用户对Tachyon的管理和使用,以及现有基于FUSE接口的应用通过Tachyon进行内存加速或者数据共享。



4.Tachyon在百度大数据平台的应用案例
在百度,我们从2014年底开始关注Tachyon。当时我们使用Spark SQL进行大数据分析工作,由于Spark是个基于内存的计算平台,我们预计绝大部分的数据查询应该在几秒或者十几秒完成以达到交互查询的体验。然而,我们却发现实际查询几乎都需要上百秒才能完成,其原因在于我们的计算资源与数据仓库可能并不在同一个数据中心。 在这种情况下,我们每一次数据查询都可能需要从远端的数据中心读取数据,由于数据中心间的网络带宽以及延时的问题,导致每次查询都需要较长的时间(>100秒)才能完成。更糟糕的是,很多查询的重复性或相似性很高,同样的数据很可能会被查询多次,如果每次都从远端的数据中心读取,必然造成资源浪费。



为了解决这个问题,在一年前我们借助Tachyon管理远程及本地数据读取和调度,尽量避免跨数据中心读数据。 当Tachyon被部署到Spark所在的数据中心后,每次数据冷查询时,我们还是从远端数据仓库拉数据,但是当数据再次被查询时, Spark将直接从同一数据中心的Tachyon中读取数据, 从而提高查询性能。在我们的环境和应用中实验表明:如果是从非本机的Tachyon读取数据的话,耗时降到10到15秒,比原来的性能提高了10倍; 最好的情况下,如果从本机的Tachyon读数据,查询仅需5秒,比原来的性能提高了30倍, 效果很明显。除了性能的提高,更难能可贵的是Tachyon运行稳定,在过去一年中很好的支持着百度的交互式查询业务, 而且社区在每一版迭代更新中都不断提供更多的功能以及不断提高系统的稳定性,让业界对Tachyon系统更有信心。



在过去一个月,百度在为大规模使用Tachyon做准备,验证Tachyon的可扩展性。我们使用Tachyon的最新版成功部署了1000个worker的Tachyon集群,在本文完成时这应该是世界最大的Tachyon集群。此集群总共提供超过50TB的内存存储,在百度内部已经稳定运行了一个月,现在有不同的百度业务在上面试运行以及压力测试。在百度的图搜变现业务上,我们与社区合作在Tachyon上搭建了一个高性能的Key/Value存储,提供线上图片服务。同时由于图片直接存在Tachyon里,我们的线下计算可以直接从Tachyon中读取图片。 这使得我们将线上以及线下系统整合成一个系统,既简化了开发流程,也节省了存储资源,达到了事半功倍的效果。本文篇幅有限,期待在后期给大家详细介绍百度是1000 worker的Tachyon 集群的实用案例,包括如何使用Tachyon整合线上线下的存储资源等。



5.结语
作为一个以内存为中心、统一的分布式存储系统,Tachyon极大地增强了大数据生态中存储层的功能。虽然Tachyon项目相对还比较年轻,但已经很成熟稳定,并且已经在学术界以及工业界取得了成功。随着整个计算机产业的发展,内存变的越来越便宜,在计算集群中可使用的内存容量会不断增长,我们相信Tachyon也必将会在大数据平台中发挥越来越重要的作用。



现在Tachyon项目发展迅速,更多的功能也在逐步得到完善,应用前景也颇为广阔。Tachyon正不断地在支持更多的底层存储系统(特别地,社区中已经有人正在实施支持阿里云OSS存储系统以及百度开放云平台,这对国内的用户和开发者来说是个很好的机会);同时Tachyon也在实现安全性相关的支持,以充分满足业界生成环境的需要;更进一步地,Tachyon目前更多地被视为文件系统,而作为一个统一存储系统,Tachyon也将支持更多的数据结构,以满足不同计算框架的需要。在本文完成时Tachyon已经准备发布下一版,有兴趣的读者们可以多关注Tachyon,到社区里进行技术讨论以及功能开发。



版本选择
Tachyon目前的最新发布版为0.5.0,最新开发版为0.6.0-SNAPSHOT。由于两者向上层提供的API有了不小的差异,这里以最新的0.6.0-SNAPSHOT开发版为基础进行介绍。它具有更多功能,更多新特性,更方便用户使用。在介绍时,我们也会标注出那些和0.5.0版本兼容的部分,让大家能够同时Hold住不同的版本。



官方资料: Tachyon-0.5.0; 最新开发版。(本文章介绍的Tachyon基于的版本是0.6.0-SNAPSHOT,2014-12-27)



  1. Tachyon的安装
    由于目前Tachyon使用了RamFS作为内存层,因此推荐在Linux环境下安装Tachyon。



第①步——下载&编译
对于已经发布的版本,如Tachyon-0.5.0或更早的版本,可以直接下载已经编译好的包,并解压。下载地址为https://github.com/amplab/tachyon/releases



为了更好地契合用户的本地环境,如java版本、hadoop版本或其他一些软件包的版本,可以下载Tachyon源码自行编译。Tachyon开源在GitHub上,可以很方便地获得其不同版本的源码:Tachyon-0.5.0;最新开发版。Tachyon项目采用Maven进行管理,因此可以采用 mvn package 命令进行编译打包。在Tachyon-0.6.0-SNAPSHOT版本中,默认依赖的java版本为1.6,默认依赖的hadoop版本为1.0.4,如果要更改这些依赖的版本号可以在编译时加入选项,如:



1
mvn clean package -Djava.version=1.7 -Dhadoop.version=2.3.0 -DskipTests
完成这一步后,我们就得到了能够运行在用户本地环境的Tachyon,下面我们分别介绍如何在单机和分布式环境下配置和启动Tachyon。



1.1 单机安装Tachyon
这里要注意一点,Tachyon在单机(local)模式下启动时会自动挂载RamFS,所以请保证使用的账户具有sudo权限。



第②步——配置
在conf/workers文件中配置需要启动TachyonWorker的节点,默认是localhost,所以在单机模式下不用更改。(在Tachyon-0.5.0版本中,该文件为conf/slaves)



将conf/tachyon-env.sh.template复制为conf/tachyon-env.sh,并在conf/tachyon-env.sh中修改具体配置,下面列举了一些重要的配置项,稍后会详细地介绍更多的配置项。



JAVA_HOME —— 系统中java的安装路径
TACHYON_MASTER_ADDRESS —— 启动TachyonMaster的地址,默认为localhost,所以在单机模式下不用更改
TACHYON_UNDERFS_ADDRESS —— Tachyon使用的底层文件系统的路径,在单机模式下可以直接使用本地文件系统,如”/tmp/tachyon”,也可以使用HDFS,如”hdfs://ip:port”
TACHYON_WORKER_MEMORY_SIZE —— 每个TachyonWorker使用的RamFS大小



第③步——启动
完成配置后,即可以单机模式启动Tachyon,格式化、启动和停止Tachyon的命令分别为:



1
2
3
bin/tachyon format
bin/tachyon-start.sh local
bin/tachyon-stop.sh
1.2 分布式安装Tachyon
这里我们以一个三个节点的集群为例,分别为slave201,slave202和slave203。三个节点都运行TachyonWorker,slave201运行TachyonMaster。



第②步——配置(该过程在TachyonMaster节点,即slave201上完成)
在conf/workers文件中配置需要启动TachyonWorker的节点,即



1
2
3
slave201
slave202
slave203
将conf/tachyon-env.sh.template复制为conf/tachyon-env.sh,并在conf/tachyon-env.sh中修改具体配置。不同于单机模式,这里需要修改TachyonMaster地址以及底层文件系统路径



1
2
export TACHYON_MASTER_ADDRESS=slave201
export TACHYON_UNDERFS_ADDRESS=hdfs://slave201:9000
完成配置文件的修改后,将整个tachyon文件夹复制到每个节点的相同路径下



1
2
scp –r tachyon-master slave202:/home/…/
scp –r tachyon-master slave203:/home/…/



第③步——启动
在分布式模式下,格式化和停止Tachyon的命令仍然为:



1
2
bin/tachyon format
bin/tachyon-stop.sh
但启动Tachyon有了更多的选项:



bin/tachyon-start.sh all Mount #在启动前自动挂载TachyonWorker所使用的RamFS,然后启动TachyonMaster和所有TachyonWorker。由于直接使用mount命令,所以需要用户为root
bin/tachyon-start.sh all SudoMount #在启动前自动挂载TachyonWorker所使用的RamFS,然后启动TachyonMaster和所有TachyonWorker。由于使用sudo mount命令,所以需要用户有sudo权限
bin/tachyon-start.sh all NoMount #认为RamFS已经挂载好,不执行挂载操作,只启动TachyonMaster和所有TachyonWorker
因此,如果不想每次启动Tachyon都挂载一次RamFS,可以先使用命令 bin/tachyon-mount.sh Mount workers 或 bin/tachyon-mount.sh SudoMount workers 挂载好所有RamFS,然后使用 bin/tachyon-start.sh all NoMount 命令启动Tachyon。



单机和分布式模式的区别就在于配置和启动步骤,事实上,也可以在分布式模式下只设置一个TachyonWorker(伪分布式),在这种情况下两者就基本一样了。



第④步——查看&测试
启动Tachyon后,可以用 jps 命令查看TachyonMaster和TachyonWorker进程是否存在



也可以在浏览器内打开Tachyon的WebUI,如 http://slave201:19999 ,查看整个Tachyon的状态,各个TachyonWorker的运行情况,各项配置信息,浏览文件系统等。



此外,还能在任一启动了TachyonWorker的节点上执行 bin/tachyon runTests 命令来测试Tachyon是否运行正常。



步骤①-④即完成了Tachyon的安装和启动,之后我们也会给出具体地如何使用Tachyon。




  1. Tachyon的配置
    Tachyon的可配置项远不止上面步骤②的配置文件中的那些,用户可以根据自己的需求更改Tachyon的各项配置。这里以0.6.0-SNAPSHOT版本为例,介绍Tachyon中可配置参数的具体含义。(Tachyon-0.5.0的可配置项基本上是Tachyon-0.6.0-SNAPSHOT的一个子集)



Tachyon中的可配置项分为两类,一种是系统环境变量,用于在不同脚本间共享配置信息;另一种是程序运行参数,通过-D选项传入运行Tachyon的JVM中。程序运行参数又分为通用配置(Common Configuration)、TachyonMaster配置(Master Configuration)、TachyonWorker配置(Worker Configuration)和用户配置(User Configuration)。要修改或添加这些可配置项,请修改conf/tachyon-env.sh文件。



2.1 Tachyon环境变量
JAVA_HOME:系统中java的安装路径
TACHYON_RAM_FOLDER:配置ramfs挂载的文件目录,默认为/mnt/ramdisk。
TACHYON_MASTER_ADDRESS:启动TachyonMaster的地址,默认为localhost,所以在单机模式下不用更改
TACHYON_UNDERFS_ADDRESS:Tachyon使用的底层文件系统的路径,本地文件系统(单机模式下),如”/tmp/tachyon”,或HDFS,如”hdfs://ip:port”
TACHYON_WORKER_MEMORY_SIZE:每个TachyonWorker使用的RamFS大小,默认为1GB
2.2 通用配置
tachyon.underfs.address:Tachyon在底层文件系统的的路径,默认为$TACHYON_UNDERFS_ADDRESS
tachyon.home:Tachyon的安装路径,启动Tachyon时为当前 tachyon 文件夹的路径
tachyon.data.folder:Tachyon数据在底层文件系统的存放路径,默认为$TACHYON_UNDERFS_ADDRESS/tmp/tachyon/data
tachyon.workers.folder:TachyonWorkers在底层文件系统的工作路径,默认为$TACHYON_UNDERFS_ADDRESS/tmp/tachyon/workers
tachyon.usezookeeper:TachyonMaster是否使用ZooKeeper容错,默认为false。
tachyon.zookeeper.adress:如果启用,ZooKeeper的地址
tachyon.zookeeper.election.path:如果启用,Zookeeper的election文件夹路径,默认为/election
tachyon.zookeeper.leader.path:如果启用,Zookeeper的leader文件夹路径,默认为/leader
tachyon.underfs.hdfs.impl:实现HDFS的类,默认org.apache.hadoop.hdfs,DistributedFileSystem
tachyon.max.columns:Tachyon中RawTable允许的最大列数,默认为1000
tachyon.table.metadata.byte:Tachyon中RawTable元数据允许存储的最大字节数,默认为5242880,即5MB
tachyon.underfs.glusterfs.impl:如果使用GlusterFS为底层文件系统,实现GlusterFS的类,默认为org.apache.hadoop.fs.glusterfs.GlusterFileSystem
tachyon.underfs.glusterfs.mounts:如果使用GlusterFS为底层文件系统,GlusterFS卷的挂载目录
tachyon.underfs.glusterfs.volumes:如果使用GlusterFS为底层文件系统,GlusterFS的卷名
tachyon.underfs.glusterfs.mapred.system.dir:如果使用GlusterFS为底层文件系统,GlusterFS用于存放MapReduce中间数据的可选子目录,默认为glusterfs:///mapred/system
tachyon.web.resources:Tachyon WebUI可用的资源,默认为$tachyon.home/core/src/main/webapp
tachyon.async.enabled:是否启用异步模式,默认为false
tachyon.underfs.hadoop.prefixes:底层使用hadoop文件系统的前缀列表,默认为”hdfs://”,”s3://”,”s3n://”,”glusterfs:///”
tachyon.test.mode:是否启用测试模式,默认为false
tachyon.master.retry:连接重试次数,默认为29



2.3 TachyonMaster配置
tachyon.master.worker.timeout.ms:TachyonMaster和TachyonWorker心跳包失效时长,默认为60000ms
tachyon.master.journal.folder:TachyonMaster的journal日志存放路径,默认为$TACHYON_HOME/journal/
tachyon.master.hostname:TachyonMaster的主机名
tachyon.master.port:TachyonMaster的远程调用通讯端口,默认为19998
tachyon.master.web.port:TachyonMaster的WebUI端口,默认为19999
tachyon.master.web.threads:TachyonMaster的WebUI线程数,默认为9
tachyon.master.whitelist:可缓存的路径前缀列表,列表以逗号隔开,表示该路径下的文件能够被缓存至内存,默认为/,即根目录
tachyon.master.temporary.folder:TachyonMaster的临时文件夹,默认为/tmp
tachyon.master.heartbeat.interval.ms:TachyonMaster心跳包间隔时间,默认为1000ms
tachyon.master.selector.threads:TachyonMaster的thrift监听线程数,默认为3
tachyon.master.queue.size.per.selector:TachyonMaster的thrift消息队列长度,默认为3000
tachyon.master.server.threads:TachyonMaster节点的thrift服务线程数,默认为CPU核数的2倍
tachyon.master.pinlist:常驻内存的文件列表,以逗号隔开,表示该路径下的文件不会从内存中剔除,默认为null
2.4 TachyonWorker配置
tachyon.worker.data.folder:TachyonWorker在RamFS中的工作路径,默认为$TACHYON_RAM_FOLDER/tachyonworker/
tachyon.work.port:TachyonWorker的远程调用通讯端口,默认为29998
tachyon.worker.data.port:TachyonWorker的数据传输服务的端口,默认为29999
tachyon.worker.memory.size:TachyonWorker所使用的RamFS大小,默认为$TACHYON_WORKER_MEMORY_SIZE
tachyon.worker.heartbeat.timeout.ms:TachyonWorker心跳包失效的时长,默认为10000ms
tachyon.worker.to.master.heartbeat.interval.ms:TachyonWorker向TachyonMaster发送心跳包的时间间隔,默认为1000ms
tachyon.worker.selector.threads:TachyonWorker的thrift监听线程数,默认为3
tachyon.worker.queue.size.per.selector:TachyonWorker的thrift消息队列长度,默认为3000
tachyon.worker.server.threads:TachyonWorker的thrift服务线程数,默认为CPU核数
tachyon.worker.user.timeout.ms:TachyonWorker和用户之间心跳包失效时长,默认为10000ms
tachyon.worker.checkpoint.threads:TachyonWorker的checkpoint线程数,默认为1
tachyon.worker.per.thread.checkpoint.cap.mb.sec:TachyonWorker的checkpoint的速度,默认为1000MB/s
tachyon.worker.network.type:TachyonWorker在传输文件数据时使用的传输方式,默认为NETTY,可选为NIO或NETTY
2.5 用户配置
tachyon.user.failed.space.request.limits:用户向文件系统请求空间失败时的最大重试次数,默认为3
tachyon.user.quota.unit.bytes:客用户一次向TachyonWorker请求的最少字节数,默认为8388608,即8MB
tachyon.user.file.buffer.byte:用户读写文件时的缓存区大小,默认为1048576,即1MB
tachyon.user.default.block.size.byte:用户创建文件时的默认块大小,默认为1073741824,即1GB
tachyon.user.remote.read.buffer.size.byte:用户读远程文件时的缓冲区大小,默认为1048576,即1MB
tachyon.user.heartbeat.interval.ms:用户心跳包时间间隔,默认为1000ms
tachyon.user.file.writetype.default:用户在使用tachyon.hadoop.TFS时的默认写类型,默认为CACHE_THROUGH



  1. Tachyon的使用
    受益于Tachyon良好的设计和兼用性,用户可以很方便地将现有的利用HDFS进行存储的程序移植至Tachyon。同时,Tachyon也提供了自己的命令行工具和一套完整的文件系统API,用户可以灵活地使用Tachyon。



3.1 从HDFS到Tachyon
对于现有的运行在Hadoop MapReduce或者Spark上,使用 “hdfs://ip:port/” 为存储路径的程序,能够很方便地移植至Tachyon。



3.1.1 Hadoop MapReduce
将tachyon-client jar包添加至$HADOOP_CLASSPATH,jar包位于 tachyon/client/target/tachyon-client-0.6.0-SNAPSHOT-jar-with-dependencies.jar(如果是Tachyon-0.5.0,则文件名为tachyon-client-0.5.0-jar-with-dependencies.jar)
添加配置项<”fs.tachyon.impl”, ” tachyon.hadoop.TFS”>,可以在core-site.xml文件中添加,也可以在程序中使用Configuration.set()方法添加
将原有的”hdfs://ip:port/path”路径更改为”tachyon://ip:port/path”
3.1.2 Spark
同样地,添加依赖包,添加配置项,然后更改文件系统路径。



额外地,添加配置项<”spark.tachyonStore.url”, “tachyon://ip:port/”>后,能够使用”rdd.persist(StorageLevel.OFF_HEAP)”语句将Spark RDD缓存至Tachyon中以减少Java GC的开销。



3.2 命令行工具
Tachyon提供了命令行工具为用户提供了简单的交互功能,使用方式为



1
bin/tachyon tfs [COMMAND]
具体的命令有:



cat:将文件内容输出到控制台
count:输出符合路径前缀的文件总数
ls:输出目录中的文件信息
lsr:递归输出目录中的文件信息
mkdir:创建指定目录包括路径中的父目录,如果目录已经存在则创建失败
rm:删除文件或者目录
tail:将文件的最末1KB输出到控制台
touch:在指定的位置创建空的文件
mv:将文件移动到指定位置
copyFromLocal:将文件从本地文件系统拷贝到Tachyon文件系统指定位置
copyToLocal:将文件从Tachyon文件系统拷贝到本地文件系统指定位置
fileinfo:打印指定文件的块信息
pin:将指定文件常驻内存
unpin:将常驻内存的文件撤销常驻状态
3.3 Java API
Tachyon是用Java开发实现的,因此提供的API也是Java函数。要使用这些API需要依赖tachyon-client jar包,位于 tachyon/client/target/tachyon-client-0.6.0-SNAPSHOT-jar-with-dependencies.jar (如果是Tachyon-0.5.0,则文件名为tachyon-client-0.5.0-jar-with-dependencies.jar)此外,如果是已发布的Tachyon-0.5.0并且目标项目由Maven管理,可以在 pom.xml 文件中添加如下内容以获取依赖包:



org.tachyonproject
tachyon-client
0.5.0

(Tachyon-0.5.0和Tachyon-0.6.0-SNAPSHOT提供的Java API一大不同之处在于Tachyon-0.6.0-SNAPSHOT中新增了tachyon.TachyonURI类,用来表示Tachyon文件系统中的路径,类似于Hadoop中的org.apache.hadoop.fs.Path。Tachyon-0.5.0中的大部分API在Tachyon-0.6.0-SNAPSHOT中仍然存在,但被标记为@Deprecated)



Tachyon的Java API功能大部分集中于tachyon.client.TachyonFS和tachyon.client.TachyonFile两个类中



Category spark