Akka在Flink中的使用剖析

Akka与Actor 模型

Akka是一个用来开发支持并发容错扩展性的应用程序框架。它是actor model的实现,因此跟Erlang的并发模型很像。在actor模型的上下文中,所有的活动实体都被认为是互不依赖的actor。actor之间的互相通信是通过彼此之间发送异步消息来实现的。每个actor都有一个邮箱来存储接收到的消息。因此每个actor都维护着自己独立的状态。

每个actor是一个单一的线程,它不断地从其邮箱中poll(拉取)消息,并且连续不断地处理。对于已经处理过的消息的结果,actor可以改变它自身的内部状态或者发送一个新消息或者孵化一个新的actor。尽管单个的actor是自然有序的,但一个包含若干个actor的系统却是高度并发的并且极具扩展性的。因为那些处理线程是所有actor之间共享的。这也是我们为什么不该在actor线程里调用可能导致阻塞的“调用”。因为这样的调用可能会阻塞该线程使得他们无法替其他actor处理消息。

Actor系统

一个actor系统是所有actor存活的容器。它也提供一些共享的服务,比如调度配置日志记录等。一个actor系统也同时维护着一个为所有actor服务的线程池。多个actor系统可以在一台主机上共存。如果一个actor系统以RemoteActorRefProvider的身份启动,那么它可以被某个远程主机上的另一个actor系统访问。actor系统会自动得识别actor消息被路由到处于同一个actor系统内的某个actor还是处于一个远程actor系统内的actor。如果是本地通信的情况(同一个actor系统),那么消息的传输可以有效得利用共享内存的方式;如果是远程通信,那么消息将通过网络栈来传输。

actor基于层次化的组织形式(也就是说它基于树形结构)。每个新创建的actor都将以创建它的actor作为父节点。层次结构有利于监督、管理(父actor管理其子actor)。如果某个actor的子actor产生错误,该actor将会得到通知,如果它有能力处理这个错误,那么它会尝试处理否则它会负责重启该子actor。系统创建的首个actor将托管于系统提供的guardian actor/user

Flink为什么要用Akka来代替RPC

原先的RPC服务存在的问题:

  • 没有带回调的异步调用功能,这也是为什么Flink的多个运行时组件需要poll状态的原因,这导致了不必要的延时。
  • 没有exception forwarding,产生的异常都只能简单地吞噬掉,这使得在运行时产生一些非常难调试的古怪问题
  • 处理器的线程数受到限制,RPC只能处理一定量的并发请求,这迫使你不得不隔离线程池
  • 参数不支持原始数据类型(或者原始数据类型的装箱类型),所有的一切都必须有一个特殊的序列化类
  • 棘手的线程模型,RPC会持续的产生或终止线程

采用Akka的actor模型带来的好处:

  • Akka解决上述的所有问题,并对外透明
  • supervisor模型允许你对actor做失效检测,它提供一个统一的方式来检测与处理失败(比如心跳丢失、调用失败…)
  • Akka有工具来持久化有状态的actor,一旦失败可以在其他机器上重启他们。这个机制在master fail-over的场景下将会变得非常有用并且很重要。
  • 你可以定义许多call target(actor),在TaskManager上的任务可以直接在JobManager上调用它们的ExecutionVertex,而不是调用JobManager,让其产生一个线程来查看执行状态。
  • actor模型接近于在actor上采用队列模型一个接一个的运行,这使得状态机的并发模型变得简单而又健壮

Akka在Flink中的使用

Akka在Flink中用于三个分布式技术组件之间的通信,他们是JobClientJobManagerTaskManager。Akka在Flink中主要的作用是用来充当一个coordinator的角色。

JobClient获取用户提交的job,然后将其提交给JobManagerJobManager随后对提交的job进行执行的环境准备。首先,它会分配job的执行需要的大量资源,这些资源主要是在TaskManager上的execution slots。在资源分配完成之后,JobManager会部署不同的task到特定的TaskManager上。在接收到task之后,TaskManager会创建线程来执行。所有的状态改变,比如开始计算或者完成计算都将给发回给JobManager。基于这些状态的改变,JobManager将引导task的执行直到其完成。一旦job完成执行,其执行结果将会返回给JobClient,进而告知用户

它们之间的一些通信流程如下图所示:

上图中三个使用Akka通信的分布式组件都具有自己的actor系统。

代码分析

当前关于Akka相关的代码,都在runtimemodule下,但实现的代码是JavaScala混合的(也许这块的逻辑Flink正在过渡阶段,后续会有更多的逻辑改为用Scala实现)。

其中,只有JobClient的Akka代码是用Java实现的。JobManager以及TaskManager跟Akka相关的逻辑以Scala实现。

消息定义

  • Messages : 三个分布式组件都会用到的消息定义
  • JobClientMessages : JobClient相关的message,将会被org.apache.flink.runtime.client.JobClientActor使用
  • JobManagerMessages : JobManager相关的message
  • TaskManagerMessages : TaskManager相关的message定义

当然不止这么多消息,还有垂直划分的几种定义,比如:RegistrationMessages用于定义TaskManagerJobManager相关的register消息。

下面我们看看在Java和Scala中,Flink实现的actor的基类。

基类FlinkUntypedActor

在Akka提供的Java lib中,实现一个actor通常是靠继承UntypedActor来实现。FlinkUntypedActor也不例外。继承自UntypedActor的类,通常要覆盖onReceive方法,该方法的完整签名如下:

    public final void onReceive(Object message) throws Exception {}
  • 1

然后,通常在这个方法里会判断具体的消息类型,根据不同的消息类型来实现不同的处理逻辑。而在FlinkUntypedActor类中,它先对消息进行一轮验证,过滤掉非法的消息后,再处理各种消息的类型。验证主要是比对sessionID是否合法(即是否等同于leader session id),然后才会调用核心处理逻辑方法handleMessage。该方法是抽象方法,有待子类具体实现,目前只有涉及到JobClient处理的JobClientActor类继承了该类。

由scala实现的FlinkActor几乎具有相同的语义,这里不再啰嗦。

总结

本篇主要介绍了Akka,并对Akka在Flink中的使用进行了大致的介绍。其实,就源码而言倒没有太多值得关注的地方,主要还是三个分布式组件之间的通信/协同逻辑,下篇我们会谈这方面的话题。

原文发布时间为:2016-04-14

本文作者:vinoYang

本文来自合作伙伴CSDN博客,了解相关信息可以关注CSDN博客。

时间: 2025-01-01 16:04:58

Akka在Flink中的使用剖析的相关文章

Flink中task之间的数据交换机制

Flink中的数据交换构建在如下两条设计原则之上: 数据交换的控制流(例如,为实例化交换而进行的消息传输)是接收端初始化的,这非常像最初的MapReduce. 数据交换的数据流(例如,在网络上最终传输的数据)被抽象成一个叫做IntermediateResult的概念,它是可插拔的.这意味着系统基于相同的实现逻辑可以既支持流数据,又支持批处理数据的传输. 数据传输包含多个对象,它们是: JobManager master节点,用于响应任务调度.恢复.协作,以及通过ExecutionGraph数据结

Flink原理与实现:详解Flink中的状态管理

Flink原理与实现系列文章 : Flink 原理与实现:架构和拓扑概览Flink 原理与实现:如何生成 StreamGraphFlink 原理与实现:如何生成 JobGraphFlink原理与实现:如何生成ExecutionGraph及物理执行图Flink原理与实现:Operator Chain原理 上面Flink原理与实现的文章中,有引用word count的例子,但是都没有包含状态管理.也就是说,如果一个task在处理过程中挂掉了,那么它在内存中的状态都会丢失,所有的数据都需要重新计算.从

Flink 原理与实现:理解 Flink 中的计算资源

本文所讨论的计算资源是指用来执行 Task 的资源,是一个逻辑概念.本文会介绍 Flink 计算资源相关的一些核心概念,如:Slot.SlotSharingGroup.CoLocationGroup.Chain等.并会着重讨论 Flink 如何对计算资源进行管理和隔离,如何将计算资源利用率最大化等等.理解 Flink 中的计算资源对于理解 Job 如何在集群中运行的有很大的帮助,也有利于我们更透彻地理解 Flink 原理,更快速地定位问题. Operator Chains 为了更高效地分布式执行

Flink中的一些核心概念

在源码解读前我们有必要先了解一下Flink的一些基本的但却很关键的概念.这有助于帮助我们理解整个架构.在翻译文档的同时,对于有争议的或者不是非常适合用中文表达的地方,我尽量保留原始英文单词. 程序和数据流 Flink程序的基本构建块是streams和transformations(注意,DataSet在内部也是一个stream).一个stream可以看成一个中间结果,而一个transformations是以一个或多个stream作为输入的某种operation,该operation利用这些str

Apache Flink流分区器剖析

这篇文章介绍Flink的分区器,在流进行转换操作后,Flink通过分区器来精确得控制数据流向. StreamPartitioner StreamPartitioner是Flink流分区器的基类,它只定义了一个抽象方法: public abstract StreamPartitioner<T> copy(); 但这个方法并不是各个分区器之间互相区别的地方,定义不同的分区器的核心在于--各个分区器需要实现channel选择的接口方法: int[] selectChannels(T record,

ASP.NET 2.0中发送电子邮件剖析之一

asp.net 一.简介 如今,电子邮件已经成为一种无所不在.异步通知和分布式的消息系统.存在许多web开发场所:其中,服务器端代码都需要生成一个电子邮件并且把它发送给指定的接收者.该电子邮件可以被发送给网点中的一些用户,通知他们有关于他们的新建用户帐户,提醒他们忘记的口令,或以邮件形式提交给他们一个清单.当然,这也可以是针对web开发者或站点管理员,提供给他们有关一个刚刚公开的未处理的异常或用户回馈的消息. 幸好,ASP.NET使得发送电子邮件非常轻松..NET框架版本1.x在System.W

Apache Flink fault tolerance源码剖析(二)

继续Flink Fault Tolerance机制剖析.上一篇文章我们结合代码讲解了Flink中检查点是如何应用的(如何根据快照做失败恢复,以及检查点被应用的场景),这篇我们来谈谈检查点的触发机制以及基于Actor的消息驱动的协同机制.这篇涉及到一个非常关键的类--CheckpointCoordinator. org.apache.flink.runtime.checkpoint.CheckpointCoordinator 该类可以理解为检查点的协调器,用来协调operator和state的分布

Apache Flink fault tolerance源码剖析(六)

上篇文章我们分析了基于检查点的用户状态的保存机制--状态终端.这篇文章我们来分析barrier(中文常译为栅栏或者屏障,为了避免引入名称争议,此处仍用英文表示).检查点的barrier是提供exactly once一致性保证的主要保证机制.这篇文章我们会就此展开分析. 这篇文章我们侧重于核心代码分析,原理我们在这个系列的第一篇文章<Flink数据流的Fault Tolerance机制> 一致性保证 Flink的一致性保证也依赖于检查点机制.在利用检查点进行恢复时,数据流会进行重放(replay

Apache Flink fault tolerance源码剖析完结篇

这篇文章是对Flinkfault tolerance的一个总结.虽然还有些细节没有涉及到,但是基本的实现要点在这个系列中都已提及. 回顾这个系列,每篇文章都至少涉及一个知识点.我们来挨个总结一下. 恢复机制实现 Flink中通常需要进行状态恢复的对象是operator以及function.它们通过不同的方式来达到状态快照以及状态恢复的能力.其中function通过实现Checkpointed的接口,而operator通过实现StreamOpeator接口.这两个接口的行为是类似的. 当然对于数据