分布式作业.docx
- 文档编号:26960599
- 上传时间:2023-06-24
- 格式:DOCX
- 页数:24
- 大小:1.09MB
分布式作业.docx
《分布式作业.docx》由会员分享,可在线阅读,更多相关《分布式作业.docx(24页珍藏版)》请在冰豆网上搜索。
分布式作业
1、优化基于FUSE分布式存储的本地文件存取访问
(摘自SC.Companion.2012.10,IEEE2013)
现在的分布式文件系统能够存储大量信息并持有高可靠性和高性能的优点,但大多数这些系统是以FUSE为原型,总是会经历由在本地文件访问时额外存储拷贝和上下文切换造成的I/O开销。
这笔不小的开销显著降低了数据密集型应用程序在分布式文件系统运行的性能。
在这篇文章中,提出了一种在基于FUSE分布式文件系统中通过减少内存拷贝和上下文切换的数目获得快速本地文件访问的机制。
1.1目前已有的几种分布式存储各有其特点,有Gfarm、FUSE和基于FUSE的Gfarm。
(1)Gfarm
一款日本开发的分布式文件系统,它是一个面向数据密集型网格应用程序的全局文件系统,支持对文件的并行I/O操作。
Gfarm包含元数据服务器和I/O服务器。
Gfarm结构流程图
客户端访问文件的工作原理如下:
①客户端发送一个打开请求到一个元数据服务器上;
②客户端收到来自元数据服务器端的文件位置;
③客户端发送一个打开请求到包含该文件的I/O服务器;
④I/O服务器与元数据服务器通信核对打开请求的有效性,文件信息也进行通信(如节点号、生成编号);
⑤客户发送更进一步的请求到I/O服务器(读、写);
⑥客户端发送关闭请求到元数据和I/O服务器。
特点:
通过读/写请求到I/O服务器的限制通信,减少了元数据服务器和网络的工作量。
但是大量使用的是本地存储。
(2)FUSE
用户空间文件系统,Linux用于支持用户空间文件系统的内核模块。
FUSE包含一个内核模块和用户态守护进程。
使用FUSE框架访问一个用户级水平文件系统的流程如下:
①应用程序发出一个系统调用到操作系统去访问基于FUSE的文件系统里的文件(发送到相应的FUSE模块);
②FUSE模块转发该请求到用户态守护进程;
③守护进程用一种方法处理请求(一些用本地文件,其它用远程服务器或网络通信);
④守护进程返回结果到FUSE模块;
⑤FUSE模块转发结果到应用程序。
特点:
由于额外的上下文切换和内存副本,性能偏低;
守护进程拷贝文件数据到FUSE模块缓冲区里,便于返回到应用程序。
使用FUSE流程图
(3)访问一个安装FUSE的Gfarm文件系统
Gfarm2fs是一个安装在虚拟客户端上的Gfarm文件系统里的基于FUSE的用户态守护进程。
使用Gfarm2fs访问一个文件系统的流程如下:
①应用程序为一个文件访问发出一个系统调用,FUSE收到一个文件系统访问的请求;
②FUSE模块转发该请求到Gfarm2fs守护进程,并通过一个元数据服务器和I/O服务器使用Gfarm库通信处理请求;
③请求结果返回到FUSE模块;
④FUSE模块转发结果到应用程序。
访问Grarm流程图
特点:
守护进程本身对于本地访问是不需要的,它构成了额外的I/O开销。
1.2提出的机制
目的:
消除上下文切换和内存拷贝;减少缓存的使用。
组成:
①打开组件;
②读/写组件。
这两个组件的工作流程如下表所示:
打开组件
读/写组件
①应用程序发送一个打开调用到用户级文件系统;②FUSE内核模块转发请求到gfarm2fs守护进程;③gfarm2fs发送打开请求到一个返回包含目标的I/O服务器位置的元数据服务器;④gfarm2fs访问输入输出服务器;⑤FUSE模块把本地打开的文件结构和目标文件的传统结构联系在一起。
①FUSE模块在收到读或写的系统调用后,收到由gfarm2fs打开的文件结构;②FUSE模块检查传统结构是否和这个收到的文件结构联系在一起。
联系,则FUSE模块发出一个读或写的请求到那个文件并返回结果到客户端程序;否则,FUSE模块放松请求到gfarm2fs。
打开组件图读/写组件图
1.3实验方法
机制结构:
基于FUSE的高层API
试验环境:
环境包含一个简单元数据服务器和三个客户端节点的集群;
每个节点包含两个IntelXeon2.40GHzCPUs(6-core),48GBRAM,600GB15,000rpmSASHDD。
节点之间由InfinibandQDR连接。
操作系统是64位CentOS5.6(内核2.6.18);Gfarm版本2.4.2,FUSE版本2.7.4,Gfarm2fs版本1.2.3。
实验测量标准:
读/写吞吐量(1GB的临时文件和8MB的标准记录)
实现方法:
修改gfarm2fs、FUSE模块、FUSE库、Gfarm库(轻微修改,添加接口获取隐藏在库中的文件描述符)
具体实现:
①Gfarm2fs:
为gfarm2fs所使用的打开请求处理程序创建一个扩展(通过参数传递结构);
②FUSE:
修改了的FUSE库和模块收到一个来自gfarm2fs的指向结构体的指针,FUSE模块获得该结构体打开了的文件的描述符;
为管理文件进行的内核数据结构的修改示意图
③函数:
FUSE在内核中注册了一个fuse文件系统,当发出读或写的系统调用时,FUSE模块调用通用的内核函数实现无缝工作。
修改的读函数图
其中,基于FUSE的具体修改比较如下:
过去的
FUSE模块收到系统调用后发出请求并等待结果,经过了一个写到/dev/fuse的操作,数据写进去时,该模块的处理程序被调用,数据被拷贝到一个缓冲区里。
扩展的
结构体进程位于处理程序中,拷贝结束时,FUSE模块获得文件描述符,若值为-1,则可知给文件是在一个远程I/O服务器里,否则是本地的文件。
实验对比:
使用传统FUSE框架
使用提出的机制
无FUSE直接访问
1.4结果分析
三个客户端节点中的一个得到的基准结果如下图所示:
①顺序读,传统FUSE的性能最高,提出的机制和直接访问的性能比其低了21%;
②顺序写,提出的机制比传统FUSE高63%;
③随机读或随机写,提出的机制分别比传统FUSE高26%和57%;
④顺序读、顺序写、随机读、随机写,提出的机制分别比直接访问低0.2%、2.6%、1.3%、1.4%。
由上述现象四种现象可以归纳出以下结论:
现象
结论
②、③
性能比传统机制有很大的提高
④
这种提出的机制性能上接近直接访问的性能
①
提出的机制和直接访问在顺序读时性能没有FUSE好
出现现象④的原因是:
通过gfarm2fs访问一个本地文件系统花费大量的时间可能是由于上下文切换和内存拷贝造成的。
出现现象①的原因是:
在FUSE框架下的预读算法被修改了。
虽然预读机制能够提高吞吐量,但是在直接访问和提出的机制中它被关闭了。
这是根据虚拟内核的资源代码和吴等人的论文中提到的,当页面缓存命中率高时,预读将会被关闭。
Rajgarhia等人的论文中也解释了这个现象。
1.5小结
提出的机制在读、写吞吐量上提高了26%~63%,在页面缓存上减少了50%。
但是这篇论文讨论的只是针对本地文件的访问,可以设计和实现一个内核驱动器进行一个远程I/O服务器访问,以减少不必要的上下文切换和内存拷贝为目的。
2、通过虚拟运行时间为基础的任务迁移算法在多核云服务器提供了公平共享调度
(摘自ICDCS.2012,2012IEEE)
由于云服务器带来的复杂性提高和规模,自然的产生了对云服务器提供者的艰巨挑战。
在这些挑战中,最迫在眉睫的是公平服务开通时产生的极端的和多样化的负载量。
Linux自身携带很多的工具链和软件包对云计算,很容易定制去满足各种用户的需求。
尽管Linux是基于开源云数据中心最受欢迎的操作系统,但当它面临公平共享多核调度时仍然达不到期望。
这是因为主线Linux内核的首要任务调度程序,称为完全公平调度器(CFS),在多核系统中不能提供公平的理想水平。
2.1CFS介绍
CFS的目标是通过它的权重给每个任务的CPU时间比例提供公平份额调度。
在单核系统里,很容易实现。
在多核系统里,CFS使用一个基于权重的负载平衡机制去获得公平共享调度,它为每个核心维持权重的总和,并试图平衡系统中所有核心之间的总和,但这种机制不能保证公平共享调度,这是由于在任务虚拟运行中平衡核之间的负载对边界差没有任何作用。
更糟的是,CFS有两个原因不能提供完美的负载平衡:
权重量化误差和不情愿的负载均衡。
多核系统里一个CFS未成功获得公平性的例子
在此例子中,五个CPU密集型任务在两个核里运行。
它们的权重在图的顶部左手侧被指定。
原则上,当任务分叉时,CFS在核上权重的总和最小分配一个任务。
τ1被首先创造并指派到其中的一个核里,另一个核里的任务则持续下去。
当负载平衡的数量比一个依靠给定的工作负载派生的阀值更大时CFS开始负载平衡。
由于在此例子中负载不平衡不够大,所有的任务仍然保持运行在同一个核中,他们的权重和分别是1024和1340。
虚拟运行时差在两个核中随着时间发散。
文献中已经有了一系列的针对多核系统的公平共享调度算法。
根据它们的运行序列结构,它们被划分为两类:
一类是基于一个中心的运行对列,另一类是依据分布式运行对列。
前者性能优于后者在一个具有少量核心的系统,因为它们通过利用可利用的资源中的信息做出全球化的调度决策。
但是,它们因核数增加而可扩展性缺乏受到了影响,因为集中运行队列的锁竞争成为了一个性能瓶颈。
大多数文献中发现的算法充分利用一种基于权重负载平衡机制,仅仅针对每一个核的权重之和的平衡。
正如上面提到的,基于权重的算法在实践中没有成功获得公平性,即使每个核给予的负载数量是确切的且相同。
正如我们所知道的,文献中仅存在一个已有的算法能够被归类为基于进度的算法。
分布式权重轮转算法(DWRR)由李等人提出的作为一个可扩展的多进程的公平共享调度算法,它经过每个核的权重轮转调度任务,核之间,它执行负载平衡以确保所有的任务通过同样的轮数。
但是,DWRR可能由于两个源于LinuxO
(1)调度器的运行队列受到低交互性的影响。
而本文提出的基于进程的多核公平共享调度算法在虚拟运行时表示每一个任务的进程的实例。
该算法充分利用在每个核上的一个单一的运行对列,因此不会有交互性问题。
2.2CFS的结构体系
①数据结构
CFS是对称多处理器调度算法与分布式运行队列中进行的结构。
为了减少运行队列操作的运行时间复杂性,Linux内核实现一个带有自平衡的二叉树的运行队列称为一颗红-黑树。
CFS能够选择复杂度为O
(1)的最小虚拟运行时,因为它在树的最左边的叶子结点处。
②每个核公平共享调度算法
CFS里一个重要的任务属性是一个任务的权重,因为CFS尝试根据每个任务的权重给它CPU时间比例。
在单核系统中,CFS试图调度可运行任务这样给出的核上有虚拟运行时的所有的任务仅仅有很小的区别。
这里w0是优秀值为0的权重,W(i)是任务τi的权重,假设PR(τi,t)表示时刻t任务τi的累计物理运行时的量,则VR(τi,t)为时刻t任务τi的虚拟运行时。
任务的虚拟运行时越小,任务被调度的需求越多。
为了在一个合理的运行时间成本上去执行公平共享调度,CFS利用了一个时间片的概念。
任务τi的时间片TSτi计算如下:
其中P作为给出的连续工作量如下所示:
n为任务数,在当前的Linux实现中,sysctl_sched_latency,nr_latency,min_gramularity是系统范围的常量,且值分别为6,8和0.75。
CFS的运行时间算法流程图如下图所示:
③基于权重的负载平衡机制
运行队列Qk计算式如(4)所示,Sk表示在队列Qk中的任务集合。
CFS在一个特定的时间间隔测量瞬间执行的负载平衡。
这个间隔用T表示,CFS为运行队列Qk维持最后的时间tlast,k负载平衡。
对于每一次调度,都通过当前时间tcurrent与tlast,k比较检查是否Qk需要被再平衡?
如果当前时间的更优,则触发负载平衡代码移动任务从繁忙的运行队列Qbusiest(运行队列的最大负载)到Qk。
CFS可能移动多任务,负载被移动的量如表达式(5)所示。
保守一点,CFS遇到状况(6)时不能移动任务。
CFS无论何时发现一个空的运行队列时触发额外的负载平衡。
在这种情况下,它抢断一些来自繁忙的运行队列中的任务,任务被移动的量如(5)所示。
2.3提出的关于CFS算法
为了克服当前CFS的缺点,因此本文提出了一个基于虚拟运行时间的任务迁移算法。
这个算法集中在一对核里提供公平性。
当虚拟运行时间差在所有可运行任务里在所有的时间段是0,完美的公平共享调度例如GPS可以满足。
由于在现实中GPS是不可实现的,因此尝试通过一小部分的任务队去绑定任意对的虚拟运行时差。
差值收敛到多个平衡期通过任务的速度差的上限。
注意到任何一个任务对里速度差是由一些常量限制的,因为在本算法中由最大的任务权重限制了负载差。
(1)系统模型和问题陈述
目标系统的体系结构(如下图)中,数据中心包含数百台服务器或数千。
每个服务器都配有一个SMP处理器,运行Linux操作系统。
云服务提供商根据服务水平协议分配一些任务给每个用户。
每个任务都是一个普通的Linux任务与特定的权值和优秀值。
在数据中心的服务器可以运行不同用户拥有的任务的广泛组合。
CFS根据它们的权重调度这些任务。
目标系统体系结构图
为了评估给出的多核调度算法的公平性,定义了一种度量方法,然后立即将问题公式化表示。
让S表示在一对核P1、P2上运行的任务序列集,它们的权重被定义为W,Di,j(t)是在时刻t集合S中的两个任务τi和τj的虚拟运行时差。
最大的Di,j(t)用Dmax(t)表示,它代表了根据它们的权重两个任务的进程缩放之间最大的跨度。
Dmax(t)=0时支持例如GPS的调度算法,但它确是不可实现的。
在实践中,如果Dmax(t)被绑定在一个恒定的C=αT(α是常数,T是一个平衡周期)上,则这种调度算法可以赢得强公平性。
C越小,算法就越公平。
当Dmax(t)发散的时候算法则未能成功获得公平性。
更糟的是,在CFS中Dmax(t)很容易发散,因为它考虑到一个持续不平衡的情况,一旦遇到不行等时它就不会移动任务。
正如下表所示,五个CPU密集型任务运行在P1、P2两个核上,CFS分配τ1到P1,其它的指派到P2上。
结果,τ1的虚拟运行时比别的任务快很多,并且它们间的差距无限发散。
任务设置规范,导致虚拟运行时在CFS发散示例图
(2)基于虚拟运行时的任务迁移
算法设置两个任务集S1、S2作为输入,分别执行在前面的周期[(k-1)T,kT]上的P1、P2。
然后输出S1’、S2’,它们将分别被新分配到P1、P2上。
该算法每T毫秒执行一次。
算法流程图及算法伪代码如下所示:
基于虚拟运行时的任务迁移算法的概述提出算法的伪代码
将虚拟运行时的任务降序存储在列表X里,然后连续执行分区算法和迁移算法。
在分区算法中,它将X中的任务集划分成两部分glarge和gsmall,使它们具有以下三种属性:
①在glarge中的任务大于等于虚拟运行时在gsmall中的任意任务;
②Llarge、Lsmall分别是glarge和gsmall的负载;
③Llarge-Lsmall是系统中最大权重的范围。
在while循环的每次中,删除一个X头部的任务并插入到glarge,直到Llarge变得比系统总负载的一半还大时跳出,将X中所有剩下的任务插入到gsmall。
迁移算法以减少任务迁移数的方式分配glarge和gsmall到P1、P2中。
首先分别计算glarge和gsmall被迁移到P1和P2所需的任务迁移数,同样的,再计算周围其它的任务迁移数。
然后选择一个导致任务迁移数较少的映射。
为了证明一对给定的核心边界范围Dmax(t)接近常数,首先定义下面的符号。
对于给定的时间间隔[kT,(k+1)T],虚拟运行时的增加的任务τi用ΔVRi(T)表示。
一对任务(τi,τj)之间的ΔVRi(T)差由ΔVRi,j(T)定义。
ωmax和ωmin分别表示系统中最大和最小的权重。
如果没有任务迁移发生在间隔内,每个任务的物理运行时间与由
(2)定义的时间片的倍数相等。
因此在时刻t集合S中的两个任务τi和τj的虚拟运行时差Di,j(T)推导计算如下所示:
ΔVRi(T)是以一个常数C=αT为界,其中α为负常熟,它满足任务中任意对Di,j((k+1)T)≤C。
同理,τi的虚拟运行时比τi的更小,这种情况的属性也满足,因为ΔVRi(T)≤C支持C=αT且α是一个正常数。
2.4实验结果
实现:
实现提出的算法是在Linux内核2.6.38.8和衡量任务的最大化的虚拟运行时差作为算法的运行时间开销。
评价提出算法的公平性,通过不同的负载平衡周期权衡公平性和运行时间开销。
实验平台:
Linux内核2.6.38.8实现算法,具体的软硬件组成如下表。
公平性上,运行一个由六个任务组成的CPU密集型任务集,它们被分别指定了不同的优秀值-5,5,0,0,0,0。
然后分别比较这些在传统的CFS和修改了的CFS的任务的Dmax(t)。
同时,也测量了每个任务的物理运行时,并将它和GPS里已经给出的任务的理想运行时比较。
运行时的开销,运行Kernbench机制程序,配置六个任务,并将它们全部的最优值置为0。
然后分别比较传统CFS和修改的CFS的全部运行时间。
描述公平性的实验结果如图所示
无修改和已修改的CFS的Dmax(t)的比较图
从这个结果中明显在传统CFS中Dmax(t)线性增加然而在修改的CFS中它保持在一个常数范围内。
同时,观察到负载平衡周期越小,产生更小的Dmax(t)。
任务物理运行时间如下表所示,修改了的CFS,每一个任务获得理想CPU时间至少97.04%,而传统的CFS少于理想CPU时间15.24%。
描述运行时间开销的实验结果如图所示:
竞争内核的运行时间比较图
本算法的实验结果提供了很好的效应。
当平衡周期设置为100毫秒时观察到最大的虚拟运行时差为50.53个时间单元。
它相当于转换为一个带有优秀值为0的任务的物理运行时50.53毫秒。
当T=100时,本算法的额外性能的开销仅仅是传统的CFS的0.14%。
这说明了本算法产生了一个可忽略的运行时间开销。
本算法比传统的CFS获得几乎相同的性能。
2.5小结
本算法包括两个子算法,分区,即依据虚拟运行时划分任务成两部分,和迁移,即在最小化任务的迁移数同时分配分区到专门的核中。
结果证明了本算法在多核系统中当运行时间的开销是可忽略时改善了公平性。
这个算法提供两个核之间成对的公平性,对于一个通用的超过两个核的多核系统来说,可以扩展多核数,将多核的数量超过2,使之成为一个通用的多核算法。
一个添加的虚拟运行时平衡政策是需要的,这样可以使它以分层方式反复运用提出的算法来获得全局的公平性。
同时,要保证获得不同对象的性能、交互性和能量功耗。
这种政策超出了这篇文章的范围,因此可以留作将来的工作。
3、HierKNEM:
一种自适应框架上的多核集群内核辅助和拓扑感知集体通讯
(摘自IPDPS.2012.9,IEEE2012)
在MPI集合通信的最新进展下,已经缓解了由深层存储暴露的性能问题,通过仔细考虑集合拓扑和内核距离之间的匹配,正如单核辅助内核机制的使用。
但是,分布式环境中,单层方法不能涵盖不仅在带宽和时延,而且在全双工通信或者操作多个同时并发副本的极端变化。
导热和功耗的担忧已经抑制了结点数量和处理器频率的增长。
在非统一内存访问的节点内,内存和共享缓存层次结构,摒弃了普通负载平衡和甚至连接带宽和时延的假设。
随着多核结点的引进,高性能和可移植性在MPI中受到威胁,为了环节这些问题,已经尝试使用混合编程模型,节点之间保留MPI和多核之间一个线程集中的方法(例如pthreads、OpenMP、TBB…)。
但是这种做法它对程序员的显著复杂性,呈现出违背便携性,并规定原有应用程序的重大改写的层次的显式管理。
多核共享内存的方法不能运用网络通信,正规的网络方法无法提取业绩关闭共享内存连接。
因此,本文提出了一种内核辅助拓扑感知集合框架:
HierKNEM,协调集体算法的多层之间的协作。
3.1当前已有的相关技术
传统基本的方法可以通过消息流水线,一种技术,其中较大的消息被分成更小的块,以最大限度地提高稳态带宽实现并行处理加以完善。
此外,运行时的决策模块可以用来选择最好的算法和调整参数,按邮件大小,通信大小,和其他输入变量。
调谐集体模块,在开放式MPI中,是标志性的做法,MPICH2等MPI库功能的实现类似的想法。
不幸的是,因为该调谐集体操作已设计了适应单处理器集群,这些参数中没有一个可以反映一个运行进程的拓扑视图的物理距离。
分层集体组件处理和内部节点间的通信不配合紧密,导致次优的流水线和有时相互矛盾的优化选择。
这个结果与本文的提出的区别在于节点内部通信主要是通过一个拷贝进/拷贝出的方法实现使用一个共享内存段。
为了减少使用双重内存拷贝即拷贝进/拷贝出的方法而产生的开销,已经有的方法包括SMARTMAP、LiMIC、KNEM集,虽然它们已作出努力,考虑到NUMA层次结构的过程中放置和优化节点内的集体算法,以适应建筑功能,但这些项目只关注在一个单一的共享内存多核节点内改善通信。
对于这些复杂算法,集合通信的节点间层合作的问题还没有得到解决。
3.2多核集群辅助内核分层集合通信
(1)框架
大多数已存在方法发展层次集合通信是依据一个多层的方法,顶层代表了最大领域的网络。
但这些尝试缺乏在为多核系统集群上提供分层集合操作的集群多核系统是表达一种多层次的算法有很紧的水平之间的互操作性。
从技术角度来看,在大多数的分级方法是将集体的通信之间和内部节点之间的通信划分。
所有非首进程只与首进程通信,然后消息由首进程转发到远程结点上的远程首进程。
对于多级的算法的一个主要挑战是围绕公共资源的使用进行竞争。
这个负载是双折叠:
在一侧的发送/接收通过网络的数据转换成从内存总线通过PCI总线到数据移动,另一侧,移动数据的节点内产生的存储器总线的流量,因此碰撞的网络迁移。
(2)三种集合算法
①一对多
假设节点内通信的每个计算节点是lcomm命令,节点间通信的首进程是llcomm和处理进程排名P。
假设一个两级的广播算法,采用了基于生成树的方法进行跨结点等级和用于该节点内的水平线性逼近。
提出的HierKNEM广播算法足够的自适应处理特殊情况,如当所有的进程都分配在一个单一的节点上,我们的广播转化为一个线性算法与KNEM相同的,当每个结点都有一个进程在通信,我们的HierKNEM广播自动演变成一个生成树广播与跨节点的级数相同。
具体的算法流程如右图所示:
②多对一
与广播算法相似,该减少算法使用一个跨节点通信和内节点通信。
除了这两个传播者,HierKNEM减少创建另一个本地通信,lcomm命令的一个子集,组织所有的非首进程在同一个节点(新通讯)上,这个新的通信用于从内部分离过程的首进程节点的减少。
该HierKNEM减少实际上是一个双重首进程的算法:
第一首进程参与上层(节点间)减少,而第二首进程将是根上的每个新的通讯传播者和负责任的节点内减少与上一级别降低当地的贡献,更新第一的首进程。
算法2描述了HierKNEM减少了一般情况下:
每个节点都具有两个以上的进程在参与还原操作:
一个首进程节点间减少和另一个首进程为节点内减少。
为了节省空间,我们减持的特殊情况处理的算法,内部管理和KNEM注册的分布。
具体算法如下图所示:
③多对多
该HierKNEM提供了两种算法Allgather:
一个首进程为基础的算法簇小节点(每个节点2-6芯)和环算法对于大结点。
领先的算法有三个步骤:
1)收集到的信息为首进程流程2)首进程之间的数据交换,以及3)从首进程广播
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 分布式 作业
![提示](https://static.bdocx.com/images/bang_tan.gif)