背景介绍:
对flink整个流程进行分析,首先第一步需要了解每个组件之前的通讯方式,以及调用的流程,这样就可以对后面研究的代码,主要分析flink1.14.2比较新的版本。
主要分析大体如以下的内容:
1、 Flink RPC 网络通信框架。
2、 Flink RPC 案例。
3、 Flink基础组件的RPC实现。
一、 Flink RPC 网络通信框架。
flink的rpc主要组件如下图:
从上面可以看出来Flink PRC是基于Akka实现的。那么Akka的工作机制又是什么呢?
关于akka的工作机制原理如下:
1、ActorSystem 是管理 Actor 生命周期的组件,Actor 是负责进行通信的组件
2、每个 Actor 都有一个 MailBox,别的 Actor 发送给它的消息都首先储存在 MailBox 中,通过这种方式可以实现异步通信。
3、每个 Actor 是单线程的处理方式,不断的从 MailBox 拉取消息执行处理,所以对于 Actor 的消息处理,不适合调用会阻塞的处理方法。
4、Actor 可以改变他自身的状态,可以接收消息,也可以发送消息,还可以生成新的 Actor(谁生的谁养)
5、每一个 ActorSystem 和 Actor 都在启动的时候会给定一个 name,如果要从 ActorSystem 中,获取一个 Actor,则通过以下的方式来进行 Actor 的获取:akka.tcp://actorsystem_name@bigdata02:9527/user/actor_name 来进行定位
6、如果一个 Actor 要和另外一个 Actor 进行通信,则必须先获取对方 Actor 的 ActorRef 对象,然后通过该对象发送消息即可。actorRef = actorSystem.actorOf("akka.tcp://actorsystem_name@bigdata02:9527/user/actor_name")// 获取和对方 actor 进行通信的一个 actorRef 对象,类似于一个本地调用,但事实上,actorRef 和 对方actor 的通信细节被封装了。actorRef = actorSystem.actorOf("schema://actorsystem_name@hostname:port/user/actor_name")actorRef.getNow()
7、通过 tell 发送异步消息,不接收响应,通过 ask 发送异步消息,得到 Future 返回,通过异步回到返回处理结果
简单总结:
1、RpcGateway 路由,RPC 的老祖宗,各种其他 RPC 服务组件,都是 RpcGateWay 的子类,类似于 Hadoop 中的通信协议 Protocol
2、RpcEndpoint 业务逻辑载体,对应的 Actor 的封装
3、RpcService 对应 ActorSystem 的封装,类似于 Spark 中的 RpcEnv
4、RpcServer RpcService(ActorSystem)和 RpcEndpoint(Actor)之间的粘合层
最后总结:RpcEndpoint 下面有四个比较重要的子类
1、TaskExecutor 集群中从节点中最重要的角色,负责资源管理
2、Dispatcher 主节点中的一个工作角色,负责 job 调度执行
3、JobMaster 应用程序中的主控程序,类似于 Spark 中的 Driver 的作用,或者 MapReduce 中的 MRAppMaster
4、ResourceManager 集群中的主节点 JobManager 中的负责资源管理的角色,和 TaskExecutor 一起构成资源管理的主从架构
二、RPC案例demo
pom.xml 添加如下几个依赖:
org.apache.flink flink-core ${flink.version} org.apache.flink flink-runtime_2.12 ${flink.version}
java code如下:
package com.mazh.flink.rpc.service; import akka.actor.ActorSystem; import com.mazh.flink.rpc.demo01.HelloRpcEndpoint; import org.apache.flink.configuration.Configuration; import org.apache.flink.runtime.akka.AkkaUtils; import org.apache.flink.runtime.rpc.RpcService; import org.apache.flink.runtime.rpc.akka.AkkaRpcService; import org.apache.flink.runtime.rpc.akka.AkkaRpcServiceConfiguration; public class MyService { public static void main(String[] args) { // ActorSystem actorSystem = AkkaUtils.createDefaultActorSystem(); Configuration configuration = new Configuration(); ActorSystem actorSystem = AkkaUtils.createActorSystem(configuration, "localhoust", 9999); // 创建 RpcService, 基于 AKKA 的实现 RpcService rpcService = new AkkaRpcService(actorSystem, AkkaRpcServiceConfiguration.defaultConfiguration()); HelloRpcEndpoint helloRpcEndpoint = new HelloRpcEndpoint(rpcService); String address = helloRpcEndpoint.getAddress(); System.out.println(address); helloRpcEndpoint.start(); } }
import org.apache.flink.runtime.rpc.RpcEndpoint; import org.apache.flink.runtime.rpc.RpcService; /** * Author: * Description: */ public class HelloRpcEndpoint extends RpcEndpoint implements HelloGateway { public HelloRpcEndpoint(RpcService rpcService) { super(rpcService); } @Override public String hello() { return "Hello Flink RPC"; } }
package com.mazh.flink.rpc.service; import akka.actor.ActorSystem; import com.mazh.flink.rpc.demo01.HelloGateway; import org.apache.flink.runtime.akka.AkkaUtils; import org.apache.flink.runtime.rpc.RpcService; import org.apache.flink.runtime.rpc.akka.AkkaRpcService; import org.apache.flink.runtime.rpc.akka.AkkaRpcServiceConfiguration; import java.util.concurrent.ExecutionException; public class MyClient { public static void main(String[] args) throws ExecutionException, InterruptedException { ActorSystem actorSystem = AkkaUtils.createDefaultActorSystem(); RpcService akkaRpcService = new AkkaRpcService(actorSystem, AkkaRpcServiceConfiguration.defaultConfiguration()); HelloGateway getNowGateway = akkaRpcService.connect("akka.tcp://flink@localhoust:9999/user/rpc/e18c9493-e5bc-4e9f-a6df-ccb71d7c755b", HelloGateway.class).get(); System.out.println(getNowGateway.hello()) }
}
结果如下: