从社区的讨论看,目前的Shuffle架构(External Shuffle Service)主要存在以下几个问题。
当单台主机上运行较多的executor时,大量Shuffle File的并发读写速度将受制于单台主机磁盘和网络的速度,
Shuffle File存储在本地磁盘,没有备份。当所在主机故障时,所有Spark程序存储在该主机的Shuffle File都要重新计算。代价很高。
当Spark在容器化环境运行时,所有executor都需要挂载所在主机的External Shuffle Service容器的存储卷。而k8s集群的管理员出于各种考虑,也许并不允许这种部署方式。
存算分离是目前大规模分布式系统的一个架构演进趋势。但是当前的Shuffle Service架构无法将Shuffle File存储到高性价比的外部存储中。
针对以上问题,社区讨论了下一代Shuffle Service(RemoteShuffleService)要实现的几个目标:
目前实现以上目标的路线有两条:
已经有的一些实现。
Facebook的Cosco(未开源)将整个Shuffle的逻辑独立成了一个分布式的服务。
Uber的RemoteShuffleService也将ShuffleManager的实现分成了RSS Client和RSS Server两个部分。
MemVerge的SplashShuffleManager则是改写了SortShuffleManager。定义了一套插件接口,支持将Shuffle File写入外部存储。
路线1中的ShuffleManager实现大量复制了SortShuffleManager。且缺少与driver端配合,进行Shuffle File读取异常处理、Shuffle File地址管理等操作的接口。
所以社区提出了第二条路线:重构SortShuffleManager代码,将Shuffle File读写的逻辑抽象出一套新接口。
新接口将支持四种Shuffle File保存策略:
重构后,社区会优先完成将数据写入本地磁盘的实现。
如果要等社区版本的RemoteShuffleService,估计还需要一段时间。
实现中可能出现的性能问题
如果方案是通过RSS Client写入RSS Server,数据会增加2次额外的传输:RSS Client ——> RSS Server ——> Distributed File System。读取的时候同理。
每个Map Task输出的Shuffle数据都有两个文件:一个Shuffle File,包含若干个Shuffle Block;一个Shuffle Index File,包含每个Shuffle Block在Shuffle File的offset。
当前的ExternalShuffleService实现会将Shuffle Index File包含的信息缓存在内存中。
如果替代方案中没有Server端,每个Shuffle Reader都需要重新读取一边Shuffle Index File。
需要评估一下这一变化带来的性能损耗。
部分分布式文件系统(如单个HDFS集群)存储文件元数据的能力是无法进行水平扩展的。
Master节点的处理能力有可能成为性能瓶颈。