spark 2.4.0源码分析--(三)Spark Netty通信传输层架构

本文深入探讨Spark的Netty通信基础,涵盖TransportContext、TransportServer、TransportClientFactory的创建以及NettyRpcHandler在消息处理中的角色。分析了NettyRpcHandler的dispatcher消息分发、文件下载流程,以及TransportChannelHandler的响应消息处理机制。通过实例展示了如何在项目中应用Spark的Netty RPC通信技术。
摘要由CSDN通过智能技术生成

Netty 是一个基于NIO的客户、服务器端编程框架,Netty 是一个基于NIO的客户、服务器端编程框架。
Spark Netty RPC通信可分为两大部分:

  • 首先,是Spark 对Netty通信基础Api的封装,实现Server和Client,这部分代码主要以java实现,在network-common 子项目中,分别实现了TransportServer、TransportClientFactory(连接池)、TransportClient(客户端)等功能
  • 后续,在下一篇文章,我们会分析Rpc消息如何在应用层创建、发送、分发(dispatcher)、处理(Endpoint)及回调,这一完整流程
    在本文,我们主要介绍Spark对Netty通信层的封装,以及在参考Spark Netty实现原理的基础上,在项目中的应用。

Netty通信基础框架中,NettyRpcEnv初始化创建TransportContext,其具有createServer()、createClientFactory()核心功能,是创建服务端和客户端连接池的起点。
以下TransportContex概要图在查看过程中,注意有①~④子模块,需各自对应起来分析。

在这里插入图片描述
在这里插入图片描述

一、创建TransportContext及其内部成员分析

在NettyRpcEnv中创建TransportContext:

private[netty] class NettyRpcEnv(
    val conf: SparkConf,
    javaSerializerInstance: JavaSerializerInstance,
    host: String,
    ...) extends RpcEnv(conf) with Logging {
    ...
    
    val transportConf = SparkTransportConf.fromSparkConf(
    conf.clone.set("spark.rpc.io.numConnectionsPerPeer", "1"),
    "rpc",
    conf.getInt("spark.rpc.io.threads", numUsableCores))
    
    val streamManager = new NettyStreamManager(this)
    
    // 创建TransportContext上下文
    private val transportContext = new TransportContext(transportConf,
    new NettyRpcHandler(dispatcher, this, streamManager))
    ...
}

1、TransportContext内部成员分析:TransportConf上下文配置

从NettyRpcEnv中创建transportConf可知,其数据源是SparkConf全局配单的一份拷贝,同时提供了netty相关配置的get()方法,包括io mode、timeout、buffer size、threads等netty配置:

public class TransportConf {
	private final ConfigProvider conf;
	...
  	public int numConnectionsPerPeer() {
    	return conf.getInt(SPARK_NETWORK_IO_NUMCONNECTIONSPERPEER_KEY, 1);
 	 }
 	 
  	public int backLog() { return conf.getInt(SPARK_NETWORK_IO_BACKLOG_KEY, -1); }

  	public int serverThreads() { return conf.getInt(SPARK_NETWORK_IO_SERVERTHREADS_KEY, 0); }
  	
  	public int clientThreads() { return conf.getInt(SPARK_NETWORK_IO_CLIENTTHREADS_KEY, 0); }
 	
 	public int receiveBuf() { return conf.getInt(SPARK_NETWORK_IO_RECEIVEBUFFER_KEY, -1); }
}

2、TransportContext内部成员分析:NettyRpcHandler

由TransportContext的创建可知,RpcHandler的实现为: new NettyRpcHandler(dispatcher, this, streamManager)
NettyRpcHandler内部具有dispatcher和streamManager两个重要成员,这里分别介绍:

I、NettyRpcHandler:dispatcher消息分发

dispatcher作用是在server端分发各rpc消息至inbox和应用级Endpoint,具体分发流程在下一篇文章介绍,这里只做简单介绍,NettyRpcHandler中,涉及dispatcher有两类用法:
A、接收数据:
** receive(client, messages, callback)【server TransportRequestHandler#processRpcRequest()处理Rpc消息】、
** receive(client, messages)【server TransportRequestHandler#processOneWayMessage()处理单向消息】、
** internalReceive()【直接数据包装为RequestMessage】
B、代理TransportRequestHandler的channelActive()、channelInactive()、exceptionCaught()方法,在channel通道连接、失去连接、捕获异常时,使用postToAll()给dispatcher发送对应远端client状态消息

II、NettyRpcHandler:streamManager文件下载消息流程示例

  • NettystreamManager作用是文件传输,我们通过SparkContex调用addJar()增加依赖jar包,会调用env.rpcEnv.fileServer.addJar(file),将文件添加到NettyStreamManager中
  • OneForOneStreamManger用于点对点chunk传输,核心方法是getChunk(),其创建流程是NettyBlockTransferService–>NettyBlockRpcServer–>OneForOneStreamManager,最后nettyBlockTransferService在SparkEnv中由BlockManager持有,提供块传输服务(文章篇幅限制,这个分支感兴趣的读者可以深入研究)。

以NettystreamManager为例,介绍下载文件的整体流程:

A、遍历需要下载的文件url,发起StreamRequest请求

NettyStreamManager的核心方法是openStream(streamId),将文件打开为输出流。
由Executor发起请求文件的StreamRequest消息,并最终返回文件流及StreamResponse:
在这里插入图片描述

上图需要注意的点:

  • TransportRequestHandler是在Server(即spark driver)中,进行文件的打开、返回消息的封装,并通过channel写出。
  • 其余模块均在Executor中,属于Client端功能。
B、StreamResponse在TransportResponseHandler和Executor端处理

以TransportResponseHandler中handler(responseMessage)为起点,Executor中处理StreamResponse消息的流程如下图
分为查找callback、设置拦截器、在TransportFrameDecoder的channelRead()中调用拦截器的handler()方法处理数据。

在这里插入图片描述

二、使用TransportConxt创建TransportServer

TransportServer是一个逻辑上的服务端概念,init()方法内部调用contex.initializePipleline()时,创建了TransportChannelHandler、TransportRequestHandler,与指定的channel绑定,用于channelRead()时消息读取,最后将消息交给其内部nettyRpcHandler的dispatcher进行消息分发,最后,各应用Endpoint会接收和最终响应消息。

public class TransportContext {
  public TransportServer createServer(int port, List<TransportServerBootstrap> bootstraps) {
    return new TransportServer(this, null, port, rpcHandler, bootstraps);
 
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spark submit任务提交是指将用户编写的Spark应用程序提交到集群中运行的过程。在Spark中,用户可以通过命令行工具或API方式提交任务。 Spark submit命令的基本语法如下: ``` ./bin/spark-submit \ --class <main-class> \ --master <master-url> \ --deploy-mode <deploy-mode> \ --conf <key>=<value> \ <application-jar> \ [application-arguments] ``` 其中,`--class`指定应用程序的主类,`--master`指定集群的URL,`--deploy-mode`指定应用程序的部署模式,`--conf`指定应用程序的配置参数,`<application-jar>`指定应用程序的jar包路径,`[application-arguments]`指定应用程序的命令行参数。 在Spark中,任务提交的过程主要包括以下几个步骤: 1. 创建SparkConf对象,设置应用程序的配置参数; 2. 创建SparkContext对象,连接到集群; 3. 加载应用程序的主类; 4. 运行应用程序的main方法; 5. 关闭SparkContext对象,释放资源。 在任务提交的过程中,Spark会自动将应用程序的jar包和依赖的库文件上传到集群中,并在集群中启动Executor进程来执行任务。任务执行完成后,Spark会将结果返回给Driver进程,并将Executor进程关闭。 总之,Spark submit任务提交是Spark应用程序运行的关键步骤,掌握任务提交的原理和方法对于开发和调试Spark应用程序非常重要。 ### 回答2: Spark 作为一款强大的分布式计算框架,提供了很多提交任务的方式,其中最常用的方法就是通过 spark-submit 命令来提交任务。spark-submit 是 Spark 提供的一个命令行工具,用于在集群上提交 Spark 应用程序,并在集群上运行。 spark-submit 命令的语法如下: ``` ./bin/spark-submit [options] <app jar | python file> [app arguments] ``` 其中,[options] 为可选的参数,包括了执行模式、执行资源等等,<app jar | python file> 为提交的应用程序的文件路径,[app arguments] 为应用程序运行时的参数。 spark-submit 命令会将应用程序的 jar 文件以及所有的依赖打包成一个 zip 文件,然后将 zip 文件提交到集群上运行。在运行时,Spark 会根据指定的主类(或者 Python 脚本文件)启动应用程序。 在提交任务时,可以通过设置一些参数来控制提交任务的方式。例如: ``` --master:指定该任务运行的模式,默认为 local 模式,可设置为 Spark Standalone、YARN、Mesos、Kubernetes 等模式。 --deploy-mode:指定该任务的部署模式,默认为 client,表示该应用程序会在提交任务的机器上运行,可设置为 cluster,表示该应用程序会在集群中一台节点上运行。 --num-executors:指定该任务需要的 executor 数量,每个 executor 会占用一个计算节点,因此需要根据集群配置与任务要求确定该参数的值。 --executor-memory:指定每个 executor 可用的内存量,默认为 1g,可以适当调整该值以达到更好的任务运行效果。 ``` 此外,还有一些参数可以用来指定应用程序运行时需要传递的参数: ``` --conf:指定应用程序运行时需要的一些配置参数,比如 input 文件路径等。 --class:指定要运行的类名或 Python 脚本文件名。 --jars:指定需要使用的 Jar 包文件路径。 --py-files:指定要打包的 python 脚本,通常用于将依赖的 python 包打包成 zip 文件上传。 ``` 总之,spark-submit 是 Spark 提交任务最常用的方法之一,通过该命令能够方便地将应用程序提交到集群上运行。在提交任务时,需要根据实际场景调整一些参数,以达到更好的任务运行效果。 ### 回答3: Spark是一个高效的分布式计算框架,其中比较重要的组成部分就是任务提交。在Spark中,任务提交主要通过spark-submit来实现。本文将从两方面,即任务提交之前的准备工作和任务提交过程中的细节进行探讨。 一、任务提交之前的准备工作 1.环境配置 在执行任务提交前,需要确保所在的计算机环境已经配置好了SparkSpark的环境配置主要包括JAVA环境、Spark的二进制包、PATH路径配置、SPARK_HOME环境变量配置等。 2.编写代码 Spark的任务提交是基于代码的,因此在任务提交前,需要编写好自己的代码,并上传到集群中的某个路径下,以便后续提交任务时调用。 3.参数设置 在任务提交时,需要对一些关键的参数进行设置。例如,任务名、任务对应的代码路径、任务需要的资源、任务需要的worker节点等。 二、任务提交过程中的细节 1.启动Driver 当使用spark-submit命令提交任务时,Spark会启动一个Driver来运行用户的代码。这个Driver通常需要连接到Spark集群来执行任务。 2.上传文件 Spark支持在任务提交时上传所需的文件。这些文件可以用于设置Spark的环境变量、为任务提供数据源等。 3.资源需求 Spark的任务执行依赖于一定的资源。每个任务可以指定自己的资源需求,例如需要多少内存、需要多少CPU等。这些资源需求通常与提交任务时需要的worker节点数量有关系。 4.监控和日志 在任务执行的过程中,Spark会收集任务的监控数据和日志信息。这些数据可用于后续的调试和性能优化。 总之,在Spark任务提交过程中,需要充分考虑任务的资源需求和监控日志信息的收集,以便更好地完成任务和优化Spark运行效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值