010-82449668

EN 中文

新生代工程师手把手教你玩转Alluxio+ML(下)

作者简介

 

a邱 璐:机器学习工程师@alluxio,Alluxio PMC maintainer, 有多年开源贡献经验。Alluxio机器学习、深度学习、POSIX API方向负责人。熟悉Alluxio选举机制、日志、指标系统等核心组件。

孙守拙:毕业于杜克大学计算机系,目前在Alluxio研发团队担任研发工程师,主要负责机器学习场景下的数据供给开发,及Alluxio的容器化应用。

 

Part 1 Alluxio POSIX API自测性能

使用Alluxio POSIX读文件速度能到多少?

和从云上读取数据相比,使用Alluxio POSIX接口:
① 更快吗?
② 快多少?

上篇中提到了很多Alluxio为了加速读取数据做的各种各样的优化,那么对于用户来说还有一个非常重要的问题——在机器学习训练中使用Alluxio读数据到底有多快? 比如说数据是储存在云上的,那从Alluxio读会不会比直接从云上读更快,具体能快多少?有了比较我们才能判断出使用Alluxio到底能不能获得训练性能提升,能提升多少。

Alluxio自建性能测试工具:StressBench

StressBench:一套Alluxio自带的性能测试,用来测试不同环境下Alluxio各个部分的处理速度。
优点:不依赖外部组件,只需要运行的Alluxio集群

在Alluxio中有一个自己的性能测试工具,叫StressBench,它可以通过在一定时间内进行一系列操作,比如读、写或者元数据操作,来测试不同环境下Alluxio各个部分的处理速度。它的优点在于不依赖外部组件,只需要一个运行的Alluxio集群,这个集群可以是只有一个节点,一个master,一个worker,也可以是一个更大的集群,有更多的节点。

Alluxio POSIX API性能测试工具:Fuse StressBench

Fuse StressBench:测试通过POSIX接口从Alluxio读取文件的速度。
需要额外在每一个Alluxio worker节点将Alluxio通过Fuse挂载到本地文件系统(https://docs.alluxio.io/os/user/edge/en/api/POSIX-API.html)

在StressBench中加入了fuse StressBench,就是一个对于fuse的测试,用来测试通过POSIX接口,从Alluxio中读取文件的速度。那么fuse StressBench除了需要一个Alluxio集群之外,还需要额外在每一个worker节点上都将Alluxio通过fuse挂载到本地文件系统。

既然要测试性能,最主要的一个目的就是可以量化读性能,在有这个测试工具之前,只能说从Alluxio POSIX接口读文件要比从云上读快很多,但是具体有多快,快多少,用户并没有办法测量,现在有了这个工具,就可以拿出数据证明确实快,也可以展示有多快。

Fuse StressBench-单机测试

设置:单节点,一个worker,一个读取挂载点

步骤:
① 将测试文件写进Alluxio worker
② 通过挂载点从Alluxio worker读测试文件
③ 获得读性能数据

最简单情况下,就是Alluxio集群只有一个节点,一个worker和一个读文件的挂载点,在测试中第一步我们将测试文件写入Alluxio worker,第二步通过POSIX API去读它们,测量在一段时间内读了多少字节,就可以返回在这段时间内读的速度。整个过程只需要跑两个命令,就可以看到单机情况下的读性能了。

Fuse StressBench-集群测试

设置:多节点,每个节点一个worker和一个读取挂载点

步骤:
① 将写测试文件写进worker,每个worker存储一部分文件
② 每个节点上都通过挂载点读取测试文件
③ 获得每个节点及集群的读性能数据

相比单机测试,集群测试更贴近实际生产中的机器学习场景。其中有多个节点运行了Alluxio worker,每个节点都通过fuse挂载了Alluxio,每个节点上都有自己从Alluxio中读取文件的任务,当然实际生产环境中训练还有计算的部分,我们这里fuse StressBench只是测试读取数据的行为。

我们利用了Alluxio的job service来模拟这个场景,可以理解为每台机器都有一个程序在读文件,就像实际训练中每个节点上的训练任务,每个节点上的fuse StressBench各自计算一定时间内自己读了多少字节,从而就可以知道每个节点读的速度,进而知道整个集群的速度。同样,整个过程只需要两个命令就可以完成。

Fuse StressBench单节点测试示例

这里用单节点情况做了一个简单的例子,有一个单节点的Alluxio集群,一个worker和一个本地用于读的挂载点,通过bin/alluxio runClass来跑StressBench测试工具,可以看到还同时提供了写的挂载点,这一步用来将测试文件写进Alluxio的路径,然后指定操作为写文件。我们还提供了线程的数量,一共将测试文件写进多少个文件夹,每个文件夹有多少文件,以及每个文件的大小,等待命令返回之后,这些文件就会全部储存到了Alluxio worker里面。

文件写好后进行读操作,在读测试文件时,用相同的这个 bin/alluxio runClass来启动测试。接下来指定读文件的挂载路径、读的方式、线程数量、测试时间,以及和刚才生成文件是一样的,文件夹数量,每个文件夹有多少个文件和文件大小。可能有人发现我们这个测试中读和写的本地路径不一样,是因为在生成测试文件的时候fuse就会有一些缓存,如果再去同一个文件夹读的话,这些缓存会影响测试读性能的准确性,所以用了不同的挂载点来避免这个问题。也就是在开始测试前挂载的时候,将Alluxio挂载到两个不同的路径,一个负责写,一个负责读。这样的话写文件时产生的缓存,就不会影响到读文件了。

这是读测试返回后生成的部分结果。可以看到这个单节点达到了每秒183.1兆的读取速度。我们刚才指定了一些参数,包括路径、文件大小等等,以及如果在测试中出现了任何错误,也会在这里显示。

Fuse StressBench测试限制

① 只支持读性能测试
② 只支持测试读自己生成的文件

目前这个fuse StressBench的测试工具有两个主要的限制,第一个是它只支持读性能的测试,暂时还不支持写数据或者元数据操作的测试。之前的写操作只是为了测试读性能生成的数据,它自己并不能作为一个测试。另外一个就是只支持读用它本身生成的文件,不能使用任意文件来进行测试,否则会报错,主要原因是因为如果用任意文件测试的话,很难保证资源平均分配,可能有些线程很早就结束了它的任务,但是有些线程后面又读了很久,那这样的话这个测试结果就不准确了。

Fuse StressBench官方文档

Fuse StressBench:https://docs.alluxio.io/os/user/edge/en/operation/StressBench.html#fuse-io-stress-bench

StressBench:https://docs.alluxio.io/os/user/edge/en/operation/StressBench.html

想了解更多关于fuse StressBench内容可以查看官方文档中关于fuse StressBench的部分,其中有对如何使用这个工具更为详细的介绍。接下来更为详细的介绍一下如何在Alluxio POSIX API中debug以及性能分析指南。

 

Part 2 Alluxio POSIX API debug&性能分析指南

故障排查-查看日志

首先故障排除,是fuse有个很大的问题,在于具体的故障原因不会显示在我们的命令输出中,这主要是fuse本身自带的一个限制,我们只能确定错误码是什么,但这个错误码可能翻译给用户之后,它并没有包含那么多的信息。比如说我们这个命令可能ls一个Alluxio fuse中的文件,然后会出现一个I/O报错,但无法具体知道到底是什么样的问题,而具体的问题显示在日志文档中,就包括如果单独起fuse进程的话,你需要查看fuse.log,而如果fuse起在worker进程中的话,你查看worker.log,它里面会显示具体的原因,有可能是因为没有办法去连接master,导致读不到数据之类的种种原因。

故障排查-日志等级修改

可以对日志进行等级修改,修改等级为debug之后,我们可以获得更加详细的信息。修改日志等级主要有两种方式,一种是通过修改Alluxio的conf/log4j.properties直接修改日志等级,我们可以对任意的包,把它修改成debug这种日志等级。

如果fuse起在worker进程中,可以动态地通过一个Alluxio的CLI的命令,然后开启debug级别的日志输出。比如说logLevel这个命令,它可以把worker中所有Alluxio.fuse包的所有日志变成一个debug级别的日志输出,就可以方便我们更好去排查出现的问题。这些日志通过修改为debug,可以看到fuse各种操作执行顺序以及耗费时间,有助于发现到底是哪一些fuse操作花了比较多的时间,以及是否有一些非预期的执行顺序。曾经有过一些故障就来源于一些非预期的执行顺序。

性能分析:应用,Fuse,Alluxio

当fuse使用了Alluxio POSIX API之后,发现可能性能不如预期,那性能不如预期这个问题到底出现在哪一个方面?

有几个层面:一个是应用,一个是fuse,还有Alluxio。性能不如预期的情况下,就要回过头来看这一整套东西。先了解一下整个fuse的工作流程,当用户发出了一个请求,比如说ls这个请求,它会把这个请求发送到fusekernel端,然后Kernel端进行一定的处理之后,再返回到应用端,发送给Libfuse,然后Libfuse把这些命令变成一个可以自定义的模式,通过实现Libfuse,来实现我们自己的文件系统。

然而Libfuse是写在C++上的,而Alluxio是写在Java里面的,就引入了另外一层抽象叫JNIFuse,通过JNIFuse之后, Alluxio fuse再定义每个操作具体要执行什么样的具体的内容。比如说Alluxio fuse接到底层fuse的一个命令说ok,这个用户做了一个ls操作,已经拿到了一系列的ls的指令相关内容,比如说你要读哪个文件的一些信息,然后Alluxio fuse要决定如何去应对这些操作,我们拿到ls操作之后,就会去Alluxio集群内去问,这个用户要读文件a,能不能给我文件a的信息,而Alluxio fuse拿到这部分信息之后,再通过一系列的fuse返回给用户。

所以这其中其实包含了三个方面,一方面是应用层,应用是与fuse如何进行交互的;另一方面就是 fuse层,包括fuse,kernel,Libfuse以及JNIFuse,这些都统称为fuse层,就是 fuse是如何把一个应用层的命令转化给Alluxio去具体地实现。最后一层就是Alluxio层,包括Alluxio是如何实现fuse的,以及Alluxio整个系统。

01 性能瓶颈来源于Alluxio POSIX API?

首先需要明确性能瓶颈是不是来源于Alluxio POSIX API,因为训练性能不佳,可能是来源于各种各样的原因,包括资源不足,包括算法和训练逻辑比较缓慢,以及包括应用的元数据延时长或者数据吞吐低。而我们就要分析这个性能不佳来源是不是跟数据或者元数据相关,如果与其无关可能性能瓶颈并就不在Alluxio POSIX API这一层,那研究它也就无济于事。

所以,需要先分析性能瓶颈是否来源于Alluxio POSIX API,我们可以对比Alluxio POSIX API与文件系统以及其他数据方案的性能差异,而且可以移除训练逻辑只留下数据相关操作,看看性能如何。

当我们发现可能性能瓶颈来源于Alluxio POSIX API之后,我们需要更多的去了解应用与Alluxio POSIX API之间的互动,比如说这个应用跑了哪些与POSIX API相关的指令,应用是如何呼叫这些指令的,它的呼叫顺序是怎么样的,呼叫的并发度是怎么样的,这些信息都是需要提前了解的。

02 Fuse还是Alluxio是性能瓶颈?

分析到底是fuse还是Alluxio是性能瓶颈,我们先使用了一个stack fuse来分析这部分性能。

Stack fuse是跟Alluxio fuse使用了相同的fuse组件,它也包括fuse kernel,Libfuse和JNIFuse,然而与Alluxio fuse不同的在于,它是直接对本地文件系统进行读写与以及元数据操作,不涉及任何的Alluxio组件。

可以通过一个命令能把本地文件系统mount在另外一个文件夹,然后对这个mount文件夹进行一系列的操作来对比性能,通过对比本地文件夹以及stack fuse,可以了解fuse这个层的性能损耗,通过对比stack fuse以及Alluxio fuse,可以得出Alluxio的性能损耗。

之所以要了解是fuse还是Alluxio的性能瓶颈,也是因为如果是fuse的性能损耗,其实在Alluxio这端是做不了过多的性能提升的,就是任何一个fuse的实现,包括s3 fuse之类的其他实现,它都会带有fuse原生的性能损耗,而fuse这种操作实现方式是很多年前就已经实现了的,近期也没有什么大的改变,也不会因为要把fuse应用在我们的训练中,进行一个大版本的升级。而如果发现是Alluxio的性能损耗,就可以进一步去分析到底是Alluxio中哪一部分出了问题,哪一部分可以进一步的优化来提升训练性能。

 

03 ALLUXIO FUSE分析
并发度

Alluxio fuse的分析包括几个方面,首先可以通过看一些指标,比如说Alluxio fuse的相关指标,发现有多少个文件正在并发读取,多少个文件正在并发写入,性能不好是不是由于有超高量的并发读取和写入的操作,而这个超高量的fuse方面的读取跟写入,可能并没有被Alluxio的线程池或者存储系统很好地支撑起来,这是第一步发现到底是什么性能问题的一个指标。

操作频繁度与耗时

也可以分析fuse相关操作的频繁度以及耗时。对于每个fuse操作都会记录相应的指标,比如说fuse每个读命令都会记录这个读命令被呼叫了多少次,平均的完成时间是多少?超过5%的读操作超过了多少时间?从这些信息中我们可以看出哪个fuse应用被呼叫的最多,而哪个fuse应用耗费了最长的时间,是平均时间长还是偶尔时间长,这些信息都对进一步分析性能瓶颈有非常重要的帮助。比如发现fuse的读操作花费时间最长,那我们可能就专注于在读操作上,看看是哪一步的性能有一定的损耗。如果是平均时间特别长的话,是不是涉及到配置或者涉及到存储系统的连接的问题?那如果是平均时间非常短,但是有1%或者5%的操作花了非常长的时间,是不是就涉及到资源的争夺?就可以进一步的去分析性能瓶颈在哪里了。

[Advanced]追踪性能瓶颈

还有一些更高级的追踪性能瓶颈的方式,可以通过指标系统进行时间追踪,比如fuse读这个操作非常的慢,就可以在fuse读操作里面加上一些timer metrics,然后一步一步的追踪下去,看看到底在哪里花了最长的时间,最后针对那个方面进行性能的提升。

除时间追踪之外,还可以进行CPU资源、内存资源以及锁资源的追踪,有个应用叫Async profiler,它可以帮助进行CPU memory以及锁的瓶颈的分析,可以让我们发现哪一个Alluxio的Java class花了最多的CPU资源或者最多的内存和锁资源,再或者可以对RPC指标进行追踪,目前支持gRPC和s3。

可以发现,比如说这些RPC操作非常的耗时,那究竟是在哪里耗时呢?我们的client对worker发送了一个请求,非常耗时,那到底是这个请求发送途中很耗时还是worker处理这个请求很耗时呢?就可以发现到底是worker处理慢,还是可能存在资源竞争的问题。这一整套分析都是比较有难度的,这里也放了一个性能分析的案例,也就是我们最近在一个百万小文件的场景下,通过性能分析,把最高的吞吐从2400小文件每秒提升到超过13,000小文件每秒。可以通过这个案例来具体看一下,我们是如何做整一套性能分析的,大家谢谢。

Alluxio在数据索引和模型分发中的核心价值与应用

在当前的技术环境下,搜索、推荐、广告、大模型、自动驾驶等领域的业务依赖于海量数据的处理和复杂模型的训练。这些任务通常涉及从用户行为数据和社交网络数据中提取大量信息,进行模型训练和推理。这一过程需要强大的数据分发能力,尤其是在多个服务器同时拉取同一份数据时,更是考验基础设施的性能。

南方科技大学分享:大数据技术如何赋能大模型训练及开发

南方科技大学是深圳在中国高等教育改革发展的时代背景下创建的一所高起点、高定位的公办新型研究型大学。2022年2月14日,教育部等三部委公布第二轮“双一流”建设高校及建设学科名单,南方科技大学及数学学科入选“双一流”建设高校及建设学科名单。