文章目录
我们从整体的角度看一下Flink RPC通信框架的设计与实现,了解其底层Akka通信框架的基础概念及二者之间的关系。
1. Akka基本概念与Actor模型
Akka是使用Scala语言编写的库,用于在JVM上简化编写具有可容错、高可伸缩性的Java或Scala的Actor模型。Akka基于Actor模型,提供了一个用于构建可扩展、弹性、快速响应的应用程序的平台。
Actor 模型是一种并发计算模型,Actor 模型的核心思想是将计算单元抽象为独立的并发实体,称为 “actors”,这些 actors 之间通过消息传递进行通信。
以下是 Actor 模型的一些关键概念:
Actor由状态(State)、行为(Behavior)和邮箱(Mailbox)三部分组成。
actor系统
2. Akka相关demo
2.1. 创建Akka系统
Akka系统的核心组件包括ActorSystem和Actor,构建一个Akka系统,首先需要创建ActorSystem,然后通过ActorSystem创建Actor。
如代码所示,Akka系统中包含了创建ActorSystem以及Actor的基本实例。
// 1. 构建ActorSystem
// 使用缺省配置
ActorSystem system = ActorSystem.create("sys");
// 也可显示指定appsys配置
// ActorSystem system1 = ActorSystem.create("helloakka", ConfigFactory.load("appsys"));
// 2. 构建Actor,获取该Actor的引用,即ActorRef
ActorRef helloActor = system.actorOf(Props.create(HelloActor.class), "helloActor");
// 3. 给helloActor发送消息
helloActor.tell("hello helloActor", ActorRef.noSender());
// 4. 关闭ActorSystem
system.terminate();
在Akka中,创建的每个Actor都有自己的路径,该路径遵循 ActorSystem 的层级结构,大致如下:
本地:akka://sys/user/helloActor
远程:akka.tcp://sys@l27.0.0.1:2020/user/remoteActor
- sys,创建的ActorSystem的名字;
- user,通过ActorSystem#actorOf和ActorContext#actorOf 方法创建的 Actor 都属于/user下,其是系统层面创建的,与系统整体行为有关,在开发阶段并不需要对其过多关注;
- helloActor,我们创建的HelloActor。
其中远程部分路径含义如下:
- akka.tcp,远程通信方式为tcp;
- sys@127.0.0.1:2020,ActorSystem名字及远程主机ip和端口号。
2.2. 根据path获取Actor并与之通讯
若提供了Actor的路径,可以通过路径获取到ActorRef,然后与之通信,代码如下所示:
ActorSystem system = ActorSystem.create("sys");
ActorSelection as = system.actorSelection("/path/to/actor");
Timeout timeout = new Timeout(Duration.create(2, "seconds"));
Future<ActorRef> fu = as.resolveOne(timeout);
fu.onSuccess(new OnSuccess<ActorRef>() {
@Override
public void onSuccess(ActorRef actor) {
System.out.println("actor:" + actor);
actor.tell("hello actor", ActorRef.noSender());
}
}, system.dispatcher());
fu.onFailure(new OnFailure() {
@Override
public void onFailure(Throwable failure) {
System.out.println("failure:" + failure);
}
}, system.dispatcher());
3. Flink RPC框架与Akka的关系
Flink进行RPC通信的组件
通过AkkaRpcService实现远程通讯能力
4.运行时RPC整体架构设计
Flink的RPC框架设计非常复杂,除了基于Akka构建了底层通信系统之外,还会使用JDK动态代理构建RpcGateway接口的代理类。
Flink RPC UML关系图
这里我们简单梳理一下RPC架构涉及的组件以及每种组件的作用。
- 基本实现类与FencedToken对比
- RpcEndpoint的实现类有TaskExecutor组件,FencedRpcEndpoint的实现类有Dispatcher、JobMaster以及ResourceManager等组件。这些组件可以获取RpcService中ActorSystem的dispatcher服务,并直接通过
dispatcher创建Task线程实例
。 - RpcService提供了创建和启动RpcServer的方法。
- RpcServer接口通过AkkaInvocationHandler动态代理类实现,所有远程或本地的执行请求最终都会转换到AkkaInvocationHandler代理类中执行。
5. RpcEndpoint的设计与实现
RpcEndpoint是集群中RPC组件的端点,每个RpcEndpoint都对应一个由endpointId和actorSystem确定的路径,且该路径对应同一个Akka Actor。
如图,所有需要实现RPC通信的集群组件都会继承RpcEndpoint抽象类,例如TaskExecutor、Dispatcher以及ResourceManager组件服务,还包括根据JobGraph动态创建和启动的JobMaster服务。
从图中我们可以看出,RpcEndpoint实现了RpcGateway和AutoCloseableAsync两个接口,其中 RpcGateway
提供了动态获取RpcEndpoint中Akka地址和HostName的方法。
RpcEndpoint中包含RpcService、RpcServer以及MainThreadExecutor三个重要的成员变量,其中