当您在云中运行时,利用现场实例可能是大幅降低Spark基础设施计算成本的最快和最简单的方法之一。在本文中,我们将讨论两种特定于Spark在Kubernetes上的技术,Enhanced Spot Instance Selection和Executor Decommissioning,它们既可以消除Spot实例的一些缺陷,又可以提高计算的可靠性——从而实现更快、更便宜的应用程序。
什么是现货实例?
大多数云提供商将其计算产品分为两类,按需和现货实例。按需实例有效地工作,就像拥有实例一样;只要您正在付款,您就可以独占该计算,并且实例不能被收回,直到您选择关闭它。现货实例更类似于租赁;您可以在一段不确定的时间内保持对计算实例的完全控制,但是云提供商可以随时将这些计算实例召回,并将其返回市场并分配给另一个帐户。我们称这个召回过程为a点杀.当一个点杀发生时,云提供商将向实例发送消息(通常在删除之前60-120秒),以通知机器上运行的任何应用程序或处理,以便它们能够正确地关闭或将任何相关数据移出本地存储。
在AWS上,现货价格演变缓慢(自2017年底发布新的现货定价算法以来),通常比按需定价的价格便宜60-90%。
您可能会想,“如果现场实例可以随时被回忆起来,我为什么要选择使用它们呢?”答案很简单——成本。现货实例比按需实例便宜得多。有许多因素决定现货实例的价格,例如实例类型、大小、区域、可用性区域,甚至是一天中的时间,但平均而言,现货实例可以满足您的需求与按需实例相比,可以节省60-90%的成本.
Apache Spark如何处理现货实例?
虽然从成本的角度来看,合并现货实例肯定是有优势的,但它也需要额外的工作。利用现场实例需要对应用程序处理存储在设备本地存储中的状态或中间计算的方式进行稍微不同的设计。还必须考虑到数据恢复和持久性,以便在发生spot kill时,应用程序可以快速地从中断的地方恢复,而不会在此过程中丢失任何工作或数据。
一个Apache Spark应用程序由以下组成:
- Spark Driver,它是应用程序的大脑。该驱动程序对发现kill没有弹性,因此在按需实例上运行它非常关键。
- 一个(通常是大量的)Spark执行器,Spark任务在其上并行执行(分布式编程)。
Spark被设计为对丢失的执行程序具有弹性,这使得它们适合在现场实例上运行。当Spark收到来自云提供商的即时终止通知时,它会快速阻止即将离开的Executor完成任何未来的任务,并更新事件日志,以便其他Executor可以继续上一个Executor停止的工作,而不会重复任何先前完成的工作。实际上,在重新组织丢失的执行程序计划任务时,应用程序将继续异步工作。
虽然Spark可以有效地重新分配执行器任务,但对于存储在磁盘上的数据或中间结果却不是这样。如果Spark在应用程序的未来任务或阶段中需要中间的dataframe或缓存结果,Spark将不得不重新执行先前完成的工作,以便重新计算必要的数据。根据需要计算的任务的复杂性,这个过程会显著增加应用程序的运行时。
所以我们认为点击杀是不好的,应该尽量避免,以充分意识到点实例的价值。我们该怎么做呢?
增强的点实例选择
dota2雷竞技规则 是一个完全托管、持续优化的Spark-on-Kubernetes服务,可以部署在您的云帐户中。Ocean for Apache Spark构建于海洋Spot的无服务器容器引擎。io,它优化了Kubernetes集群的自动伸缩,并帮助现货实例选择。
一个特别有用的功能是现货市场评分。使用现货市场评分,Ocean使用各种数据点,如可用性、价格和现货杀伤可能性,在不同实例类型和可用性区域之间创建一系列评分。然后,Spot根据从Ocean请求的资源(通常是内存和cpu)为应用程序的工作负载选择最佳实例类型。雷竞技rabet官网
Ocean for Apache Spark将这种Spot选择灵活性直接集成到我们的平台中。
下面的示例Spark应用程序请求:
- 一个具有2个CPU内核的驱动程序,运行在一个按需实例上。
- 10个executor,每个executor有4个CPU内核,运行在r5、r5d、r4或i3实例家族中的一个实例上。
应用规范{
"司机":{
“核”:1、
“点”:假的
},
"执行者":{
" instanceAllowList ": [" r5 ", " r5d ", " r4 ", " i3 "]
“核心”:4
“实例”:10
“点”:真的
}}
这种配置为Ocean提供了一定的自由度,可以选择最佳可用性区域和最佳实例类型,以满足您的工作负载需求,并具有最高的可用性、最便宜的价格和最低的现货销毁可能性——这要归功于Ocean的预测性现货市场评分算法。
例如,上面的配置-总共需要40个现场实例,可以通过以下方式满足:
- 1个i3.4x大实例(16核)
- 1个r5.2xlarge实例(8核)
- 2 r5。Xlarge实例(每个实例2个核或总共8个核)
- 2 r4。Xlarge(每个2核或总共8核)
混合多个实例类型还有一个额外的好处:它遵循了“不要把所有的鸡蛋放在一个篮子里”的原则。即使在一个特定的现货市场上发生了现货杀死,使用这种配置,您也不太可能同时失去许多执行者。
为了测试这个功能,我们运行了一个实验来测试Spot实例选择的有效性。我们在两个单独的配置下运行了一个批处理ETL应用程序,大约每小时运行1个小时,持续两周:一个静态配置,其中唯一允许的实例类型是m5。xlarge和一个优化的配置,其中instanceAllowList接受整个m5家族。两个应用程序都有以下配置:
- 1个驱动程序(1核,按需),10个执行程序(每个4核,现货)
- Spark executor任务由睡眠55分钟组成,如果没有现场中断,应用程序将在大约1小时内运行。
结果如下:
配置为使用实例族选择器的应用程序比硬编码特定实例类型少获得79%的点击杀。这一发现证实了使用多种实例类型和可用性区域可以显著提高现场实例的可靠性。此外,由于减少了spot kill,我们还观察到重复Spark任务和阶段、S3调用、应用程序运行时和整体应用程序成本的减少。
优雅的执行程序退役
正如前面所提到的,当执行程序由于spot kill而被召回时,任务日志将从离开的执行程序传输到剩余的执行程序,但是在本地存储中持久化的任何数据(例如shuffle数据或持久化dataframe)将丢失,如果下游任务需要这些数据,则将导致重新执行任务。这种数据丢失将导致更长的实例恢复时间和更慢的应用程序性能。
感谢优雅的执行者退役,发布仅适用于Spark-on-Kubernetes2021年的Spark 3.1版本,我们现在有了更好的解决方案。通过启用退役,当Spark从云提供商接收到spot kill通知时,它将尝试移动存储在被召回节点上或持久化的任何数据,并将其分发给应用程序中的另一个执行程序。一旦执行程序和节点被正式移除,Spark将确定从退役过程中传输的数据是否足够或继续,或者它将重新处理无法传输的任何数据。
为了更好地理解Graceful Executor Decommissioning的功能,我们运行了一系列实验来负载测试传输过程。我们使用4个核心执行程序运行了几个应用程序,测试了不同的实例类型、内存比率和执行程序数量。接下来的过程如下:
- 我们创建了一个生成大量shuffle文件的Spark应用程序
- 我们通过从集群中分离包含执行器荚的节点来模拟接收点击杀的过程,宽限期为120秒(与AWS相同)。
- 使用Spark UI中的Storage选项卡并解析来自驱动程序和执行器日志的信息,我们可以进行测量
- 分离之前存储在执行器上的数据
- 在退役期间,数据从一个执行程序移动到另一个执行程序
- Spark移动文件所花费的时间
平均而言,Graceful Executor Decommissioning在常规实例上移动了~15GB/分钟的shuffle数据,在ssd备份实例上移动了35-40GB /分钟的数据.
结论
Ocean for Apache Spark使Spark-on-k8s以3种方式可靠地运行在现场实例上:
- 在按需节点上运行Spark驱动,现场运行执行器。这可以通过在每个应用程序上设置一个布尔标志来控制。
- 根据对现货市场评分的预测算法,优化运行Spark工作负载的可用分区和实例类型。我们的实验证明,用这种方法可以避免79%的斑杀。
- 为Spark 3.1+启用Executor Decommissioning功能,通过主动保存shuffle文件和缓存数据来减轻spot kill的影响,在spot kill发生之前的2分钟内通知。
要了解有关Apache Spark的Ocean的更多信息,请安排一个时间与我们的Spark-on-Kubernetes专家团队会面-我们期待了解更多关于您的用例和需求,并构建解决方案来共同解决这些问题。雷电竞官网进入