Flink1.19底层RPC通信原理详解

1.概要

Flink1.19RPC通信是基于Pekko+Netty实现的

这里主要讲解Flink各组件之间的是如何通信的,原理是Pekko+动态代理

以ResourceManager和TaskManager通信为例,底层TaskManager(实际上是TaskExecutor)要向ResourceMananger发送消息,首先要获取到rm的网关(动态代理对象),然后调用动态代理对象的invoke方法,将

消息发送到rm对应的Actor中(Actor就是pekko的一个类,实际接受处理rpc请求消息的),actor会处理该RPC请求

2.前置知识

抽象类RpcEndpoint

所有能进行RPC通信的组件都需要实现RpcEndpoint这个抽象类,才能实现通信

public abstract class RpcEndpoint implements RpcGateway, AutoCloseableAsync {
    //获取自身的网关对象(动态代理对象)
    public <C extends RpcGateway> C getSelfGateway(Class<C> selfGatewayType) {
        return rpcService.getSelfGateway(selfGatewayType, rpcServer);
    }
    //获取rpc服务
    public RpcService getRpcService() {
        return rpcService;
    }
}

RpcService接口

两个重要的方法:

1.connect()这个方法就是用来获取通信组件的动态代理对象,后续通过这个获取的代理对象进行rpc通信(自己和他人进行rpc通信)

2.startServer() 这个方法是创建一个自身的动态代理对象,并将该对象赋值给rpcserver(自己与自己进行rpc通信)

public interface RpcService extends AutoCloseableAsync {
    <F extends Serializable, C extends FencedRpcGateway<F>> CompletableFuture<C> connect(
            String address, F fencingToken, Class<C> clazz);

    <C extends RpcEndpoint & RpcGateway> RpcServer startServer(C rpcEndpoint);
}

 PekkoInvocationHandler

 动态代理类

class PekkoInvocationHandler implements InvocationHandler, PekkoBasedEndpoint, RpcServer {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Class<?> declaringClass = method.getDeclaringClass();

        Object result;

        if (declaringClass.equals(PekkoBasedEndpoint.class)
                || declaringClass.equals(Object.class)
                || declaringClass.equals(RpcGateway.class)
                || declaringClass.equals(StartStoppable.class)
                || declaringClass.equals(MainThreadExecutable.class)
                || declaringClass.equals(RpcServer.class)) {
            result = method.invoke(this, args);
        } else if (declaringClass.equals(FencedRpcGateway.class)) {
            throw new UnsupportedOperationException(
                    "InvocationHandler does not support the call FencedRpcGateway#"
                            + method.getName()
                            + ". This indicates that you retrieved a FencedRpcGateway without specifying a "
                            + "fencing token. Please use RpcService#connect(RpcService, F, Time) with F being the fencing token to "
                            + "retrieve a properly FencedRpcGateway.");
        } else {
            result = invokeRpc(method, args);
        }

        return result;
    }
}

 PekkoRpcActor

 最终rpc请求都会发送到这个actor中处理

class PekkoRpcActor<T extends RpcEndpoint & RpcGateway> extends AbstractActor {
    //接受消息,根据消息类型的不同走不同的方法
    @Override
    public Receive createReceive() {
        return ReceiveBuilder.create()
                .match(RemoteHandshakeMessage.class, this::handleHandshakeMessage)
                .match(ControlMessages.class, this::handleControlMessage)
                .matchAny(this::handleMessage)
                .build();
    }
    //处理rpc消息
    protected void handleRpcMessage(Object message) {
        if (message instanceof RunAsync) {
            handleRunAsync((RunAsync) message);
        } else if (message instanceof CallAsync) {
            handleCallAsync((CallAsync) message);
        } else if (message instanceof RpcInvocation) {
            handleRpcInvocation((RpcInvocation) message);
        } else {
            log.warn(
                    "Received message of unknown type {} with value {}. Dropping this message!",
                    message.getClass().getName(),
                    message);

            sendErrorIfSender(
                    new UnknownMessageException(
                            "Received unknown message "
                                    + message
                                    + " of type "
                                    + message.getClass().getSimpleName()
                                    + '.'));
        }
    }
}

3.整体架构流程

集群启动时,TaskManager(本质是TaskExecutor)向ResouceManager注册就用到了RPC通信,以此为例,讲解一下RPC通信的整体流程

1.通过rpcservice接口的connect方法获取rm的动态代理对象

2.这里的resoucemanager就是rm的代理对象(本质是FencedPekkoInvocationHandler),最终目的是为了调用到resourcemanager的registerTaskExecutor方法

3.接下来会调用到代理对象的invoke方法(动态代理相关的知识不多讲了),然后调用父类的invoke方法

4.判断是否为本地,这里不是本地,走invokePpc()方法

5.将数据封装,发送rpc消息

6.匹配消息类型,调用handlePpcMessage处理请求

7.继续匹配数据类型

8.从rpc请求中获取method和参数,调用method.invoke()方法

9.最终,流转到resourcemanager的registerTaskExecutor方法中,完成注册

小结

        Rpc通信是flink的重要机制之一,在底层很多地方都用到了上面的内容,例如RM和TM的通信,RM和JobMaster的通信,心跳机制,组件的启动等等

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值