Spark 整体感知

余生长醉 提交于 2019-11-28 15:08:38

原文引用 大专栏  https://www.dazhuanlan.com/2019/08/26/5d634faceb33c/

为了能够深入使用 Spark ,那么必须对 Spark 有更为深入的理解。整体的结构的把握会显得非常重要。整体结构在脑海中成型后,别如同脑海中有了一个 Spark 的地图,后续深入了解的每个模块都能在整体上找到对应的位置,开发对应功能也会更加了然于胸。 网上的结构图非常丰富,但是我觉得都太过抽象,缺少一些细节。我这里尝试做的就是帮助 Spark 新手读者能构建一个 Spark 的直观感受,同时也是我自己知识的一个整理。

小Demo

下面是一段简单的 demo 进程。首先从数据源中取数,这里是从文本中读取数据。然后进行一系列的转换,最终得到自己想要的结果。

public static void main(String[] args) {
    SparkConf conf = new SparkConf().setAppName("Spark WordCount").setMaster("local");
    JavaSparkContext sc = new JavaSparkContext(conf);
    JavaRDD<String> lines = sc.textFile("your/file/path");
    lines.flatMap((String s) -> Arrays.asList(s.split(" ")).iterator())
            .mapToPair((String word) -> new Tuple2<>(word, 1))
            .reduceByKey((Integer v1, Integer v2) -> v1 + v2)
            .foreach((Tuple2<String, Integer> p) -> System.out.println(p._1 + " : " + p._2));
    sc.close();
}

这里代码内部有一个函数式计算 中非常重要的内容,流计算。曾经看过一个对流计算的形容,大意为流计算如同一个高高挂起的一桶水。每当增加一个计算,就如同在下方放置了个工具(比如滤网 filter),水桶依然高高挂起没有任何动作,直到触发一个按钮,那桶水倾倒处理,经过一个个计算节点,最后达到终点。 在下面的代码中,这里我们进入到最后的 foreache 方法,发现了触发倒水的按钮runJob。

 def foreach(f: T => Unit): Unit = withScope {
  val cleanF = sc.clean(f)
  sc.runJob(this, (iter: Iterator[T]) => iter.foreach(cleanF))
}

重要概念

  • RDD 全称是Resilient Distributed Datasets。RDD 中包含由 N 个 partition
  • partition是计算的最小单元。每个 partition 都是相互独立的。
  • 一个 RDD 和另外一个 RDD 的依赖关系分为宽依赖和窄依赖
  • 宽依赖。一个 RDD_a给一个计算得到 RDD_b。如果b 中的一块 partition 数据时计算a 中 N 块 partition 得出的。那么就是 RDD_b宽依赖 RDD_a
  • 窄依赖。如果b 中的一块 partition 数据时计算a 中 1 块 partition 得出的。那么就是 RDD_b窄依赖 RDD_a
  • 窄依赖可以在同一台机器上完成。
  • 宽依赖必须进行 shuffle,将计算需要的数据放到一起计算才行。

执行你的进程

首先,记住经过你的一系列计算后,你拿到的是包含了一系列的计算过程的RDD。当把这个RDD提交给 spark 后,spark 会做一下操作来得到最终结果。

  1. 解析出 RDD 中每一步的依赖关系。却别出子 RDD 对于父RDD 是,同一个partition 依赖(窄依赖)还是跨多个 partition(宽依赖)
  2. 按照宽依赖来切割 stage。需要进行shuffle 将不同机器不同partition的数据进行整理,以便同一key的数据发到同一台机器进行计算。
  3. 创建 Task。Task 只有两种,一种是 ShuffleMapTask,就是做 shuffle 的。另外一种是 ResultTask,就是计算最终结果的 Task。同样可以知道一个 Task 的数据来源也有两个,一个是文本,数据库之类的数据源。还有一个就是 上一个ShuffleMapTask 的结果。
  4. 以上操作都是在 Driver 端完成,下面Driver需要将安排好的 Task 提交到 Executor上执行。 当然,在提交之前首先要Master申请executor资源,获得资源后才能提交。
  5. Executor拿到 Task 后,便开始计算。这里就是上面水桶比喻中的倒水操作。executor 计算好之后,告知 Driver 计算结束。Driver 会将余下的 Task 依次提交,直到得出最终结果。至此你的计算就在 Spark 的帮助下完成了。
  6. 需要注意的是,Executor 返回个 Driver 的计算成功与否的结果,并非数据的计算结果。每一个 ShuffleMapTask的计算结果都是由 Spark 管理的,下一个 Task 需要上一个 Task 的结果时候,只需找 Spark 获取即可。

后面的话

从宏观上看大数据本质上还是非常朴素的,但是由于实现细节比较复杂,导致了很多门槛从而难以下手。当有了一个全局的感受后就会容易很多。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!