Spark入门之——运行环境、核心组件、分布式计算简介

Spark运行环境

Spark最常见的运行环境是Yarn,但也有本地模式、独立部署模式等运行环境。本地环境不是通常想的那样:本地IDEA运行一个Scala程序,本地运行环境指的是一直在本地存在的,想什么时候用就什么时候用,而不是运行一个程序之后就没了。本地环境如下图所示:

可以将上文中的案例​​​​​​​用一行语句在本地环境运行:

sc.textFile("data/word.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_ + _).collect()

本地环境提交应用程序(使用apache提供的已有例子):

bin/spark-submit --class org.apache.spark.examples.SparkPi --master local[2] ./examples/jars/spark-examples_2.12-3.0.0.jar 10
// 参数10表示10个任务

独立部署模式是使用spark节点自身的集群模式,是一种经典的master-slave模式,集群模式除了高可用之外,还可以配置历史服务。集群部署好之后,也可以像上面那样提交应用程序,命令类似,各参数含义如下:

 独立部署模式由Spark自身提供计算资源,无需其他框架提供资源。但为了将资源调度跟计算本身分离开来,让Spark更好的承担计算,需要引入资源调度框架,国内最常用的就是Yarn。

Spark核心组件

Spark结构中提现了master-slave的模式,图中的Driver就是master,负责管理作业调度,Executor就是slave,负责执行任务。Driver主要职责:

1. 将用户程序转换为作业(job)

2. 在Executor直接调度任务(task)

3. 跟踪Executor的执行情况

4. 通过UI展示允许情况

Executor是工作节点(Worker Node)中的一个JVM进程,负责运行具体的任务,任务彼此之间相互独立。如果Executor节点发生了故障,Spark会将出错节点上的任务调度到其他Executor节点上运行。 前面所述的资源就是Executor的内存大小和使用的虚拟CPU核数。

Yarn的部署模式:Client或者Cluster模式,如果Driver在集群里就是Cluster模式,如果不在就是Client模式。

分布式计算

先简单看一个客户端向服务端发送任务的例子。先写一个任务类Task:

class Task extends Serializable {
    val datas = List(1,2,3,4)

    val logic : (Int) => Int = _ * 2

    def comput() = {
        datas.map(logic);
    }
}

再写客户端(Driver)类的main方法:

val client = new Socket("localhost", 9999)

val out : OutputStream = client.getOutputStream

val objOut = new ObjectOutputStream(out)

val task = new Task()

// 将任务对象传给服务端Executor
objOut.writeObject(task)

objOut.flush()
objOut.close()
out.close()

最后是服务端(Executor)的main方法:

val server = new ServerSocket(9999)

val client : Socket = server.accept()

val in : InputStream = client.getInputStream

val objIn = new ObjectInputStream(in)

val task : Task = objIn.readObject().asInstanceOf[Task]

val results : List[Int] = task.compute()


in.close()
objIn.close()
server.close()

上述的计算只有一个节点来完成,我们可以把任务分解,让多个节点进行并行计算,这就是分布式计算,引入SubTask类:

class SubTask {
    var datas : List[Int] = _
    var logic : (Int) => Int = _
    
    def compute() = {
        datas.map(logic)
    }
}

客户端此时应该发送两个任务给服务端:

val client1 = new Socket("localhost", 9999)
val client2 = new Socket("localhost", 8888)

val out1 : OutputStream = client1.getOutputStream
val out2 : OutputStream = client2.getOutputStream

val objOut1 = new ObjectOutputStream(out1)
val objOut2 = new ObjectOutputStream(out2)

val task = new Task()

val subTask1 = new SubTask()
subTask1.logic = task.logic
subTask1.datas = task.datas.take(2)

val subTask2 = new SubTask()
subTask2.logic = task.logic
subTask2.datas = task.datas.takeRight(2)

// 将任务对象传给服务端Executor
objOut.writeObject(subTask1)
objOut.writeObject(subTask2)

objOut1.flush()
objOut1.close()
out1.close()

objOut2.flush()
objOut2.close()
out2.close()

服务端的代码不需要修改,需要拷贝一份,改个端口号即可,意味着两台服务器。这样一个简单的分布式计算的例子就类似于Spark的工作流程,我们不需要写单独的Task/SubTask,因为Spark已经封装了几个数据结构供我们使用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值