Flink的Akka分布式通信实现(谷歌翻译)

 

本页讨论了Flink的Akka分布式通信的实现,该版本已在0.9版中采用。使用Akka,所有远程过程调用现在都实现为异步消息。这主要影响的组件JobManagerTaskManager 和JobClient 将来,甚至有可能将更多的组件转换为参与者,从而使它们能够发送和处理异步消息。

Akka和Actor

Akka  是用于开发并发,容错和可伸缩应用程序的框架。它是参与者模型的实现, 因此类似于Erlang的并发模型。在参与者模型的上下文中,所有代理实体都被视为独立的参与者。角色通过彼此发送异步消息与其他角色进行通信。参与者模型的优势在于这种异步性。也可以显式等待响应,以便您执行同步操作。但是,强烈建议不要使用同步消息,因为它们会限制系统的可伸缩性。每个参与者都有一个邮箱,其中存储了收到的消息。此外,每个参与者都保持自己的孤立状态。下面是几个参与者的示例网络。

 

角色具有单个处理线程,该线程轮询角色的邮箱并连续处理接收到的消息。作为已处理消息的结果,参与者可以更改其内部状态,发送新消息或生成新参与者。如果一个actor的内部状态是从其处理线程内部专门操纵的,则无需使actor的状态线程安全。即使单个参与者本质上是顺序的,由多个参与者组成的系统也是高度并发且可伸缩的,因为处理线程在所有参与者之间共享。这种共享也是为什么从不应该从参与者线程内部调用阻塞调用的原因。这样的调用将阻止该线程被其他参与者用来处理自己的消息。

Actor系统

actor系统是所有actor的容器。它提供共享服务,例如计划,配置和日志记录。参与者系统还包含线程池,所有参与者线程都从该线程池中募集。
多角色系统可以共存于一台机器上。如果actor系统以开头RemoteActorRefProvider,则可以从可能位于远程计算机上的另一个actor系统进行访问。actor系统自动识别actor消息是发给居住在同一actor系统还是远程actor系统中的actor的。在本地通信的情况下,可以使用共享内存有效地传输消息。在远程通信的情况下,消息是通过网络堆栈发送的。

所有参与者都按层次结构组织。每个新创建的actor都会将其创建actor作为父级分配。该层次结构用于监督。每个父母都有对其子女的监护权。如果其中一个子项发生错误,则会通知他。如果actor可以解决问题,那么他可以继续或重新开始孩子。如果问题超出了他的处理范围,他可以将错误上报给自己的父母。逐步升级错误仅表示当前层之上的层次结构层现在负责解决问题。有关Akka监督和监控的详细信息,请参见  此处

系统创建的第一个参与者由系统/user 提供的监护者监督。actor层次在这里进行了深入的说明。有关一般Actor系统的更多信息,请参见此处

actor本身就是状态和行为的容器。它是actor线程顺序处理传入的消息。因为一个actor一次仅活动一个线程,所以它使用户摆脱了易于出错的锁定和线程管理任务。但是,必须确保仅从此参与者线程访问参与者的内部状态。actor的行为由接收函数定义,该函数为每个消息包含在接收到此消息时执行的某些逻辑。

Flink系统由必须进行通信的三个分布式组件组成:JobClient,,JobManager 和TaskManager。在JobClient 从用户需要弗林克作业,并将其提交给JobManager。的JobManager 然后负责协调作业执行。首先,它分配所需的资源量。这主要包括上的执行插槽TaskManagers

在分配资源之后,JobManager 部署人员将作业的各个任务部署到各自的任务。TaskManagers 接收到任务后,将TaskManager 产生一个执行任务的线程。状态更改(例如开始计算或完成计算)将发送回JobManager。根据这些状态更新,JobManager 将引导作业执行直到完成。作业完成后,其结果将发送回给,JobClient 以告知用户有关情况。下图描述了作业执行过程。

JobManager和TaskManager

JobManager是中央控制单元,负责执行Flink作业。因此,它控制着资源分配,任务调度和状态报告。

必须先启动一个JobManager和一个或多个TaskManager,然后才能执行任何Flink作业。然后,TaskManager通过向JobManager发送RegisterTaskManager 消息来在JobManager上注册。JobManager通过AcknowledgeRegistration 消息确认注册成功  。如果TaskManager已经在JobManager上注册,则由于RegisterTaskManager 发送了多条消息,AlreadyRegistered JobManager将返回一条消息。如果注册被拒绝,则JobManager将以一条RefuseRegistration 消息进行响应。

通过发送一条SubmitJob 消息以及与之对应的作业将作业提交给JobManager JobGraph 。一旦接收到JobGraph,则JobManager创建ExecutionGraph 出的JobGraph 作为分布式执行的逻辑表示。该ExecutionGraph 包含哪些有才能被部署到任务管理器将要执行的任务的信息。

JobManager的调度程序负责在可用TaskManager上分配执行插槽。在TaskManager上分配执行插槽后,SubmitTask 带有执行任务所需的所有必要信息的消息将发送到相应的TaskManager。确认成功部署任务TaskOperationResult。一旦部署并运行了提交作业的源,作业提交也被认为是成功的。JobManager通过发送Success 带有相应作业ID 的消息来通知JobClient有关此状态的信息。

TaskManager上运行的各个任务的状态更新通过UpdateTaskExecutionState 消息发送回JobManager 。使用这些更新消息,  ExecutionGraph 可以更新,以反映执行的当前状态。

JobManager还充当数据源的输入拆分分配器。它负责在所有TaskManager之间分配工作,以便在可能的情况下保留数据局部性。为了动态平衡负载,Tasks请在完成对旧输入的处理后再请求一个新的输入拆分。该请求是通过向RequestNextInputSplitJobManager 发送来实现的。JobManager会显示一条NextInputSplit消息。如果没有更多输入拆分,则消息中包含的输入拆分为null

Tasks懒惰地部署到任务管理器。这意味着消耗数据的任务仅在其生产者之一完成生产某些数据之后才部署。生产者执行此操作后,就会向ScheduleOrUpdateConsumersJobManager 发送一条消息。此消息表明,消费者现在可以读取新生成的数据。如果使用任务尚未运行,它将被部署到TaskManager。

JobClient

JobClient代表分布式系统的面向用户的组件。它用于与JobManager进行通信,因此它负责提交Flink作业,查询已提交作业的状态并接收当前正在运行的作业的状态消息。

JobClient还是您通过消息与之通信的参与者。存在与提交工作有关的两条消息:SubmitJobDetached 和SubmitJobWait。第一条消息提交作业,并从接收任何状态消息和最终作业结果中注销。如果您想以丢脸的方式将作业提交到Flink群集,则分离模式非常有用。

SubmitJobWait 消息将作业提交给JobManager并注册以接收该作业的状态消息。在内部,这是通过生成辅助角色来完成的,该辅助角色用作状态消息的接收者。作业终止后,JobResultSuccess 带有持续时间和累加器结果的a将由JobManager发送到生成的助手角色。收到此消息后,辅助角色会将消息转发给SubmitJobWait 最初发出消息的客户端,然后终止。

异步消息与同步消息

Flink尽可能尝试使用异步消息并将响应作为将来处理。期货和少数现有的阻塞调用都有一个超时,在此之后该操作将被视为失败。这样可以防止消息丢失或分布式组件崩溃时系统陷入僵局。但是,如果您碰巧拥有非常大的群集或较慢的网络,则可能会错误地触发超时。因此,可以通过配置中的“ akka.ask.timeout”指定这些操作的超时时间。

actor可以与其他actor交谈之前,必须为其检索ActorRef。此操作的查找也需要超时。为了在没有启动actor的情况下使系统快速故障,将查找超时设置为比常规超时更小的值。如果遇到查找超时,可以通过配置中的“ akka.lookup.timeout”来增加查找时间。

Akka的另一个特点是它设置了可以发送的最大邮件大小的限制。原因是它保留了相同大小的序列化缓冲区,并且不想浪费内存。如果由于消息超出最大大小而遇到传输错误,则可以"akka.framesize" 在配置中通过增加帧大小。

故障检测

分布式系统中的故障检测对其鲁棒性至关重要。在商品集群上运行时,总是会发生某些组件发生故障或无法再访问的情况。此类故障的原因是多态的,从硬件故障到网络中断都可能造成故障。一个强大的分布式系统应该能够检测出故障的组件并从中恢复。

Flink通过使用Akka的DeathWatch机制来检测故障组件。即使没有受到该actor的监督,甚至不在另一个actor系统中,DeathWatch也可以让actor观看其他actor。一旦被观看的actor去世或不再可及,终止消息就会发送给观看的actor。因此,在接收到这样的消息时,系统可以针对它采取步骤。在内部,DeathWatch被实现为心跳和故障检测器,该故障检测器基于心跳间隔,听音暂停和故障阈值来估计actor何时可能死亡。心跳间隔可以通过"akka.watch.heartbeat.interval" 在配置中设置值来控制。可以通过以下方式指定可接受的心跳暂停"akka.watch.heartbeat.pause"。心跳暂停应该是心跳间隔的倍数,否则丢失的心跳将直接触发DeathWatch。可以通过指定故障阈值"akka.watch.threshold" ,它可以有效控制故障检测器的灵敏度。有关DeathWatch机制和故障检测器的更多详细信息,请参见  此处

在Flink中,JobManager监视所有已注册的TaskManager,而TaskManager监视JobManager。这样,两个组件都知道何时不再可访问另一个组件。JobManager的反应是将各个TaskManager标记为已死,以防止将来的任务部署到该TaskManager。此外,它将使当前正在此任务管理器上运行的所有任务失败,并重新安排它们在不同TaskManager上的执行。如果TaskManager仅因暂时的连接丢失而被标记为死,那么一旦重新建立连接,它就可以在JobManager中简单地重新注册自己。

TaskManager还监视JobManager。此监视使TaskManager在检测到JobManager失败时通过使所有当前正在运行的任务失败来进入清除状态。此外,如果触发的死亡仅由网络拥塞或连接丢失引起,TaskManager将尝试重新连接到JobManager。

未来发展

目前,只有三个组件JobClient,JobManager和TaskManager被实现为参与者。为了在提高可伸缩性的同时更好地利用并发性,可以想象将更多的组件实现为参与者。一个有前途的候选人可能是ExecutionGraph其个人ExecutionVertices甚至相关Execution对象可以被实现为actor的人。这种细粒度的参与者模型将具有以下优势:状态更新可以直接发送到相应的Execution 对象。这样,JobManager将从单一的通信点显着减轻。

组态

  • akka.ask.timeout: 用于所有期货并阻止Akka呼叫的超时。如果Flink由于超时而失败,则应尝试增加此值。超时可能是由于计算机运行缓慢或网络拥塞引起的。超时值需要一个时间单位说明符(ms / s / min / h / d)(默认值:  100 s)。
  • akka.lookup.timeout: 用于查找JobManager的超时。超时值必须包含一个时间单位说明符(ms / s / min / h / d)(默认值:  10 s)。
  • akka.framesize:在JobManager和TaskManager之间发送的消息的最大大小。如果Flink因消息超出此限制而失败,则应增加该限制。消息大小需要大小单位说明符(默认值:  10485760b)。
  • akka.watch.heartbeat.interval:Akka的DeathWatch机制的心跳间隔,以检测死的TaskManager。如果TaskManager由于心跳消息丢失或延迟而被错误地标记为已死,则应增加此值。可以在此处找到Akka的DeathWatch的完整描述   (默认值:  akka.ask.timeout / 10)。
  • akka.watch.heartbeat.pause:Akka的DeathWatch机制可以接受的心跳暂停。较低的值不允许不规则的心跳。可以在此处找到Akka的DeathWatch的完整描述   (默认值:  akka.ask.timeout)。
  • akka.watch.threshold:DeathWatch故障检测器的阈值。较低的值容易产生误报,而较高的值会增加检测到死机TaskManager的时间。可以在此处找到Akka的DeathWatch的完整描述   (默认值:  12)。
  • akka.transport.heartbeat.interval:Akka运输故障检测器的心跳间隔。由于Flink使用TCP,因此不需要检测器。因此,通过将间隔设置为非常高的值来禁用检测器。如果您需要运输故障检测器,请将间隔设置为合理的值。间隔值需要一个时间单位说明符(ms / s / min / h / d)(默认值:  1000 s)。
  • akka.transport.heartbeat.pause:Akka的运输故障检测器可接受的心跳暂停。由于Flink使用TCP,因此不需要检测器。因此,通过将暂停设置为很高的值来禁用检测器。如果您需要运输故障检测器,请将暂停设置为合理的值。暂停值需要一个时间单位说明符(ms / s / min / h / d)(默认值:  6000 s)。
  • akka.transport.threshold:运输故障检测器的阈值。由于Flink使用TCP,因此检测器不是必需的,因此将阈值设置为较高的值(DEFAULT:  300)。
  • akka.tcp.timeout:所有出站连接超时。如果由于网络速度慢而在连接TaskManager时遇到问题,则应增加此值(默认值:  akka.ask.timeout)。
  • akka.throughput:将线程返回到池之前,在批处理中处理的消息数。低值表示合理的调度,而高值则以不公平为代价提高性能(默认值:  15)。
  • akka.log.lifecycle.events:打开Akka的事件远程记录。调试时将此值设置为“ on”(默认值:  off)。
  • akka.startup-timeout:超时,之后远程组件启动失败(默认值:  akka.ask.timeout)。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值