V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wellwell
V2EX  ›  程序员

第一篇技术博客:函数式编程和 Spark

  •  
  •   wellwell · 249 天前 · 1185 次点击
    这是一个创建于 249 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    最近工作中开始用 Spark 了,完全是赶鸭子上架 0 基础。想着把自己的学习经历记录下,而且写点博客也对求职有帮助,就试着写了一篇,发现写这玩意确实很难啊,写了半天写得一塌糊涂。一方面是自己才疏学浅,刚毕业大学学的的东西也忘得差不多了;一方面是不太会写,写文章没有条理。

    希望大家读完给点建议,挑挑错~ 面向的读者大概是 Spark 的使用者吧。

    开篇

    第一篇先讲讲函数式编程在 Spark 中的应用,因为理解函数式编程对理解 Spark 的一些原理还是很有帮助的。

    函数式编程简介

    函数式编程有两个比较重要的点,一个是无副作用,一个是 immutable 变量。

    1. 无副作用: f(x)=x + 1,对于这个函数,只要它的入参是 n,它的输出值永远都是 n+1 。因为这个函数不依赖任何外部的状态,只依赖入参。这一特性是 Spark 的 RDD 懒加载的理论基础。
    2. immutable 变量: 这个特性指的是,所有变量都应该是不可变的,在 Spark 中,RDD 就是不可变的。它和无副作用是 Spark 容错机制 lineage 的理论基础。

    Transform,action 和懒加载( Lazy Loading )

    编写过一些 Spark 程序的人,应该了解 Spark 有两种对 RDD/dataset 的操作。一种是 Transform 类型,包括 map,mapPartition 等;一种是 action 类型,包括 count,reduce 等。

    看下这个例子:

    val sampleRdd = sc.makeRDD(Array(1, 2, 3, 4), 2)
    val rdd2 = sampleRdd.filter((str) => str >= 2)
    val count = rdd2.count()
    

    spark 会等到调用 count()的时候才执行 filter(),这就是懒加载,只有用户真正需要结果的时候才执行全过程。所有 transform 类型的操作都是懒加载的,而 action 类型会触发 rdd 上的所有 transform 。懒加载可以让程序集中运行,节约资源,而且在 Spark 这样的分布式程序里可以节约大量的通信调度时间。

    为什么函数式编程的无副作用的对懒加载相当重要呢,我们来看下面这个例子。

    val xMinBefore = (x : Int) => {
        System.currentTimeMillis / 1000 - 60 * x;
    }
    

    看到这个函数,它就是有副作用的,它的运行结果不仅依赖入参,还依赖于这个世界的时间,所以你在不同时间去执行这个函数,返回的值是不同的。对于这种有副作用的函数,我们自然不能使用懒加载,我们需要在调用的时候就得到结果,才能保证结果是我们需要的。而没有副作用的函数,我们可以在任何时候执行都得到一致的结果,自然可以在任何时候调用,也就保证了在最后加载的时候,输出的数据是不会有问题的。

    RDD 的 Lineage

    保证了无副作用,Spark 的容错机制 lineage 才能起作用。回到上面那个例子

    val sampleRdd = sc.makeRDD(Array(1, 2, 3, 4), 2)
    val rdd2 = sampleRdd.filter((str) => str >= 2)
    val count = rdd2.count()
    

    rdd2 是在 sampleRdd 的基础上进行了 filter 操作,rdd2 实际上就是保留了一个对 sampleRdd 的引用,并记录了 filter 操作。rdd2 这样就有了和 samleRdd 的 lineage 。

    lineage 的应用: 在执行第三行 count()时,rdd2 就会在 sampleRdd 的基础上执行 filter 操作。当执行 filter 的时候失败了,spark 就会往上追溯到上一个成功的 rdd,也就是 sampleRdd,再执行一把。可以使用这种方式容错的前提,就是 RDD 的 immutable 特性以及无副作用,它们保证在任何时候对一个 RDD 执行相同操作时,输出的结果永远是一样的。

    5 条回复    2021-09-13 18:13:59 +08:00
    KAQQAK
        1
    KAQQAK  
       249 天前
    楼主有个人博客吗 可以发到个人博客上整理合集更方便把
    levelworm
        2
    levelworm  
       249 天前 via Android
    求问 java 新手如何进化到读懂 spark 源码? java 水准大致上就是可以写基础数据结构的水平,感觉离读懂 scala 写的源码还很远。
    Xhack
        3
    Xhack  
       249 天前
    这千万不要发展成 csdn
    DeleteZN
        4
    DeleteZN  
       249 天前   ❤️ 2
    @levelworm 前大数据从业者回答一下,
    先学好一些基本的数据结构,链表、Map 等等,至少要把 java 写熟悉了,了解 JVM 是什么,干了什么事情。然后就可以去看看 scala 了,推荐本书《快学 scala 》
    同时要去看大数据发展历史的组件,顺序大约是 HDFS->MapReduce->Yarn->Hive->Spark 等等。
    学 Spark 的时候,要先学 Spark 的架构和原理,然后自己亲手去写一下试一试,不管是 spark 任务还是 streamming,还是 sparksql,还是 ml 。
    然后就可以开始简单的看点源码了,从简单的 spark 任务开始。
    levelworm
        5
    levelworm  
       248 天前 via Android
    @DeleteZN 多谢大佬,看来路漫漫兮其修远兮。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3291 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 05:21 · PVG 13:21 · LAX 22:21 · JFK 01:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.