spark学习小结

本地模式
         -standalone
集群模式--yarn        ---(client、cluster),区别在于Driver程序在哪里创建
         -mesos(了解)
         
         
1.mr不擅长迭代式计算(多个mr连续使用,下一个mr基于上一个mr的"落盘"的结果),spark基于内存指的是迭代式计算的中间结果不落盘,shuffle过程还是会落盘
2.RDD->弹性分布式数据集  (是一个数据抽象,底层存储的是逻辑,而非数据,但通过执行代码可以得到数据),通过最后的collect方法可以触发执行
  弹性指的是(存储弹性、计算和容错、分区弹性)
  分布式:不同分区中的数据会分配给集群中不同的服务器节点计算
  每个创建RDD的方法都需源代码中都需要new一个RDD的子类(例如HadoopRDD、parallelizeRDD,同时有RDD的五个特性(getPartitions获取分区
  ,compute计算每个分区的函数,dependency RDD之间的相互依赖关系,partitionner RDD的分片函数,getPreferredLocations(一个列表,存储存取每个Partition的优先位置)
  
3.spark 有独立调度器(master-worker...),但主流仍是应用yarn来进行资源调度
4.hadoop里的maptask和reducetask都是进程,而spark改成了线程,所以速度会相对快一些
5.spark/bin 的spark-shell 和 spark-submit比较常用
6.一般mr是需要现在开发工具中写代码->打包->上传服务器->调用jar包,
  spark执行有两种方法,1)spark-submit提交jar 2)通过交互式窗口spark-shell,(应用较少,多用于测试)
7.yarn中的nodemanager中的executor是真正干活的线程
8.解决standalone集群执行spark/sbin/start-all.sh时显示java_HOME not set问题:在sbin/spark-config.sh中配置java_home
9. 4040 spark-shell 端口, 18080 spark-jobhistory 端口 ,8080 spark-master端口 (如果zookeeper版本高于3.5,且配置高可用的话,需要将8080修改,一般改为8989)
10.三高特性:高可用,高并发,高流量
11.standalone集群模式有两种运行模式(client、cluster),区别在于Driver程序在哪里创建,若是client
   模式,运算结果会显示在提交任务的客户端(worker的executor反向注册),若是cluster模式,需要在服务器上查看结果
12.上传jar包提交spark submit任务时报spark Exception in thread "main" java.lang.RuntimeException: Error in configuring
    解决办法:在spark-env.sh中配置如下 export SPARK_DIST_CLASSPATH=$(${HADOOP_HOME}/bin/hadoop classpath)
    原因在于Spark编译时都没有将hadoop的classpath编译进去,所以必须在spark-env.sh中指定hadoop中的所有jar包。
13.RDD算子相关的代码在Executor执行,RDD算子外的代码在Driver执行 (包括定义bean对象)
14.RDD算子分为两类,一类是转换算子,转换算子后会创建新的RDD,不会马上执行计算(transformations),另一类是行动算子(actions,例如collect返回结果)
14.获取RDD的方法,  1.from memory    sc.parallelize / sc.makeRDD(list)  默认分区数取决于分配给应用的cpu核数 local[] *表示cpu的核数 或者自定义数字
                   2.from exterior  sc.textFile(本地路径/hdfs://IP:端口号/)  默认分区数:math.min(分配给应用的cpu核数,2),或者指定最小分区数
                     指定分区  >FileInputFormat  getSplits 切片  >LineRecordReader next方法 读取
15.     
    15.1内存创建rdd获取分区内容(可以自定义获取分区数)
    def positions(length: Long, numSlices: Int): Iterator[(Int, Int)] = {
      (0 until numSlices).iterator.map { i =>
        val start = ((i * length) / numSlices).toInt
        val end = (((i + 1) * length) / numSlices).toInt
        (start, end)
      }
    }
    
    15.2文件创建RDD
    
    原始数据(22字节) 
    0 1 2 3 4 5 6 7 8 
    a b c d e f g X X
    9 10 11 12 13 14
    h i  j  k  X  X
    15 16 17 18 19
    l  m  n  X  X
    20 21
    o  p
    
    切片规划 FileInputFormat ->getSplits
    文件创建RDD获取切片大小
    return Math.max(minSize, Math.min(goalSize, blockSize));  ->splits.size = 7
    
    //获取分区数
    3 = {FileSplit@5245} "file:/I:/IDEAworkspace/spark-demo/input/test.txt:21+1"
    2 = {FileSplit@5193} "file:/I:/IDEAworkspace/spark-demo/input/test.txt:14+7"
    1 = {FileSplit@5153} "file:/I:/IDEAworkspace/spark-demo/input/test.txt:7+7"
    0 = {FileSplit@5125} "file:/I:/IDEAworkspace/spark-demo/input/test.txt:0+7"
    
    最终分区数据
    0:abcdefg
    1: hijk
    2 lmn X X op
    3
分区练习1.
原始数据如下,最小分区数为5
0 1 2 3 4
abc
5 6 7 8
ef
9 10 11
g
12 13 14 15
hj
16 17 18
klm

分区数及对应数据(goalsize=3
0: 0~3  abc
1: 3~6  ef
2: 6~9  g
3: 9~12 hj
4: 12~15
5: 15~18 klm
6: 18~19

    
17.转换算子(Transformation)
   单Value
    >map :对集合中的元素一个一个算,
    >mapPartition是按分区批量计算,
    >mappartitionwithindex是将index和分区映射成二元组(index,iter)来计算
    >flatMap 对RDD中的元素进行扁平化处理
    >glom 将RDD中每一个分区中的单个元素,转化为数组
    >groupBy 按照一定的规则,对RDD中的元素进行分组
    >filter 按照一定的规则,对RDD中的元素进行过滤
    >sample 
        -参数1:是否抽样放回 true 放回 false 不放回
        -参数2: 如果参数1是true,表示期望元素出现的次数  >0
                如果参数1是false,表示每一个元素出现的概率 [0,1]
        -参数3:随机算法的初始值(种子),一般不指定
        
        -takesample(行动算子)
        
    >distinct
        去重,底层是通过 map(key => (key,null)) + reducebykey((a,b) =>a ) 完成去重操作
    >改变分区
        -coalesce 一般用于缩减分区,默认不执行shuffle过程
        -repartition 一般用于扩大分区,默认有shuffle过程,底层调用的是coalesce
    
    >sortBy
        按照指定规则,对RDD中的元素进行排序,默认升序
    >对于RDD中的每一个分区,都会执行pipe算子中指定的脚本
   双Value
    >union  合集
    >intersection  交集
    >substract  差集
    >zip 拉链
    
   key-Value模式 :scala中也建议Key采用String或Integer类型
    >partitionBy
        自定义Partitioner,返回的分区数字不能大于创建RDD时的分区数(类比Mapreduce的numRuducetask与partitionner
            numRuducetask大于partition可运行,会导致输出的文件部分为空,
            numRuducetask小于partition不可以运行
    >reducebykey:按照Key进行聚合,在shuffle之前有combiner(预聚合)操作,返回结果是RDD[K,V]
    
    >groupBykey:按照Key进行分组,直接进行Shuffle
         在不影响业务逻辑的前提下,优先选用reduceByKey,求和操作不影响业务逻辑,但求平均值影响业务逻辑
      
    >aggregateByKey(zeroValue)(分区内计算规则,分区间计算规则)
                分区内计算参数是定义的初始值与各个key的value值
    >foldByKey(zeroValue)(分区内间计算规则)是agregateBykey的简化
    >combineByKey(对当前Key的value进行转换,分区内计算规则,分区间计算规则)

    *集中聚合算子对比
        -reducebykey     combineByKeyWithClassTag[V]((v: V) => v, func, func, partitioner)
        -aggregateByKey(zeroValue)(cleanedSeqOp,combOp)  combineByKeyWithClassTag[U]((v: V) => cleanedSeqOp(createZero(), v), cleanedSeqOp, combOp, partitioner)
        -foldByKey       combineByKeyWithClassTag[V]((v: V) => cleanedFunc(createZero(), v),cleanedFunc, cleanedFunc, partitioner)
        -combineByKey    combineByKeyWithClassTag(createCombiner, mergeValue, mergeCombiners)(null)
        
    >sortByKey  按照RDD中的key对元素进行排序
    >mapValues 只对RDD中的value进行操作
    >join&cogroup  cogroup类似全连接,而且在当前的RDD内先进行组合再连接
    
    行动算子(Action)
      -行动算子执行后,才会触发计算
     >reduce  对RDD中的元素进行聚合
     >collect.foreach和foreach
       -collect.foreach  将每一个excutor中的数据收集到Driver,行成一个新的数组
                         .foreach不是一个算子,是集合的方法,是对数组中的元素进行遍历
       -对RDD中的元素进行遍历
     >count  获取RDD中的个数
     >countByKey  获取RDD中每个key对应的元素个数
     >first
     >take
     >takeordered 获取排序后的RDD中的前几个元素
     >aggreagate&fold :主要针对单值类型,且初始值是参与分区间计算的
     >save相关的算子
        -saveAsTextFile
        -saveAsObjectFile
        -saveAsSequenceFile(只针对kv类型RDD)
    
18.Spark的Job调度
    -集群(Standalone|Yarn)
        *一个Spark集群可以同时运行多个Spark应用
    -应用(Application)
        *一个应用程序(app)可以提交多个job(触发行动算子)
    -Job
        *Job对应着我们应用中的行动算子,每次执行一个行动算子,都会提交一个Job
        *一个Job由多个Stage组成
    -Stage
        *一个宽依赖转换成一个Stage
        *阶段的个数 = 宽依赖个数 + 1
        *每个Stage由多个tasks来组成,这些tasks表示每个并行计算,并且会在多个执行器上执行
        
    -Task
    *每一个阶段最后一个RDD的分区数,就是当前阶段的Task个数
    当启动一个SparkContext的时候,就开启了一个Spark应用,一个驱动程序(driver)被启动了,多个执行器在集群中的工作节点
    也被启动了。一个执行器(excutor)就是一个JVM,一个执行器不能跨越多个节点,但是一个节点可以包括多个执行器 
19.spark中没有自己的序列化方法,基础数据类型默认是kyro序列化(效率高,但无法控制transit属性),其他类型使用java序列化方法,
    实际使用中可以考虑设置kyro序列化来进行优化,(需要重新设置)
       // 替换默认的序列化机制
      .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
                        // 注册需要使用 kryo 序列化的自定义类
                        .registerKryoClasses(Array(classOf[Searcher]))
20    * 序列化
      *   -为什么要序列化
      *       因为在Spark程序中,算子相关的操作在Excutor执行,算子之外的算法在Driver中执行,
      *     在执行有些算子的时候,需要使用到Driver端定义的数据,这就涉及到了跨进程或跨节点
      *     的通讯,所以要求传递给Excutor中的数据所属类型必须实现Serializable接口
      *   -如何判断是否实现了Serializable接口
      *       在作业Job提交之前,其中有一行代码val cleanF = sc.clean(f),用于进行闭包检查,
      *       之所以叫闭包检查,是因为在当前函数内部访问了外部函数的变量,属于闭包的形式,
      *       如果算子的参数是函数的形式,都会存在这种情况                    
21. 血缘关系:一般用于数据恢复(容错机制),存在DAG有向无环图
    窄依赖(NarrowDependency <- OneToOneDependency,RangeDpendency,PruneDependency)    父RDD中一个分区中的数据,最多交给子RDD一个分区来处理    
    宽依赖( ShuffleDependency)   父RDD中一个分区中的数据,交给子RDD多个分区来处理    ,往往伴随着shuffle,即会存在缓存,故实际运行中shuffle前的stage可能会跳过

22.JVM分配内存(1/4~1/64)
23.检查点应用场景,血缘关系过长,降低容错,另外为了数据安全,会存储在HDFS上会从血缘关系的最开始执行一遍
24.RDD的持久化
  -cache
      底层调用的就是persist,默认存储在内存中,应用程序结束后就会清除
  -persist
      可以通过参数指定存储级别,应用程序结束后就会清除
      
  -checkpoint
      *可以当做缓存来理解,存储在HDFS上,更稳定
      *为了避免容错执行时间过长,可以使用checkpoint
      
  -缓存不会切断血缘,但是检查点会切断血缘
 25.数据的读取和保存
    -textFile
    -sequenceFile
    -ObjectFile
    -Json(本质还是通过textFile读取文件,对读取到的内容进行json处理)
    -HDFS
    -Mysql(重点jdbc)
        以元素为单位--以分区为单位
        map    --- mappartition
        foreach ---foreachpartition
26.在Spark里,有三大数据结构
    -RDD  弹性分布式数据集
    -累加器  分布式共享只写变量
    -广播变量 分布式共享只读变量  (可以作为优化选项,减小excutor内存压力,将每个task的变量可以缩减到每个excutor中)
    
    driver="com.mysql.jdbc.Driver"
    url = "jdbc:mysql://hadoop102:3306/database"
----------------------------------------------------------------------------------------------------------------------
获取sparksession方式:val spark: SparkSession =  SparkSession.builder().config(conf).getOrCreate()
1.SparkSQL 和 Hive对比
        -hive --- 引擎 ---MR
        -SparkSQL ---引擎 ---spark
2.SparkSQL对数据集的抽象
    -DataFrame  增加了字段内容
        *spark.read.不同类型文件
        *通过SQL风格操作df  需要创建临时视图
        *通过DSL风格操作df,不需要创建临时视图,直接调用
    -DataSet  增加了强类型,将java中的类与字段做了映射

3.数据集转换(注意:在spark-shell窗口可以直接调用toDF方法,在IDEA接口中需要import spark.implicits._ )
    rdd => DF :var rdd = sc.textFile(path); rdd.map{str => {var fields = str.split(",");People(fields(0),fields(1).toInt)}}.toDF.show(需要提前定义样例类case class People(name:String,age:Int))
                                            rdd.map{str => {var fields = str.split(",");(fields(0),fields(1).toInt)}}.toDF("name","age").show
    DF => rdd :var df = spark.read.json(path); df.rdd   得到的RDD[org.apache.spark.sql.Row]
    rdd => DS :var rdd = sc.textFile(path); rdd.map{str => {var fields = str.split(",");People(fields(0),fields(1).toInt)}}.toDS.show  (需要提前定义样例类case class People(name:String,age:Int))
    DS => rdd : var ds = Seq(Person("banzhang",18)).toDS;  ds.rdd  得到的RDD[Person]
    DF => DS : var df = spark.read.json(path);定义样例类case class People(name:String,age:Int);  df.as[People]
    DS => DF :  var ds = Seq(Person("banzhang",18)).toDS; ds.toDF 
    Seq(Person("banzhang",18)).toDS.show(较少使用)

4.用户自定义函数
    -UDF
        一进一出
    -UDAF
        多进一出
        *继承UserDefinedAggreagatedFunction(弱类型)
        *继承org.apache.spark.sql.expressions.Aggregator[输入类型,缓存类型,输出类型] (强类型)
    -UDTF
        一进多出
5.文件加载与数据保存
    -spark.read.format("类型").load(path)
    -spark.read.json/csv(path)
    
    -df.write.format("类型").save(path)
    -df.write.save(path) 默认为snappy压缩,parquet格式
    -df.write.mode("append/overwrite/ignore").format("json/parquet..").save(path)
    
6.使用df创建的临时视图与spark内置的hive没有关系
7.外部hive配置
    -确保原有hive是正常工作的
    -把hive-site拷贝到spark的conf目录下
    -注释hive-site中原有的引擎(tez)
    -将mysql连接驱动拷贝到spark的jars目录下
 可以用bin/spark-shell页面通过spark.sql("sql") 查询hive表
 亦可以用bin/spark-sql页面启动,类似于hive客户端(应用较少)

8.代码中操作hive
    -添加依赖<dependency>
                <groupId>org.apache.spark</groupId>
                <artifactId>spark-hive_2.11</artifactId>
                <version>2.1.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hive</groupId>
                <artifactId>hive-exec</artifactId>
                <version>1.2.1</version>
            </dependency>
    -拷贝hive-site.xml到resource目录中(需注意target目录下必须也要生成相应文件,否则不能生效)
    -虚拟机需要启动hdfs
    -注意:创建sparkSession时需要引入该参数启动hive支持 .enableHiveSupport() 
9.sparkSQL项目
--1.通过SQL实现求出各个地区热门排名前三名
--1.1从用户行为表中,查询所有点击记录,并和city_info,product_info进行连接
select
   c.area,
   p.product_name
from
   user_visit_action a
left join city_info c on a.`city_id` = c.`city_id`
left join product_info p on a.`click_product_id` = p.`product_id`
where a.click_product_id != -1;
--1.2 按照地区和商品的名称进行分组,统计出每个地区每个商品的总点击量
select
   t1.area,
   t1.product_name,
   count(*) as product_click_count
from
   (select
       c.area,
       p.product_name
    from
        user_visit_action a
    left join city_info c on a.`city_id` = c.`city_id`
    left join product_info p on a.`click_product_id` = p.`product_id`
    where a.click_product_id != -1)t1
group by t1.area,t1.product_name
--1.3针对每个地区,对商品点击数进行降序排序
select
    t2.area,
    t2.product_name,
    t2.product_click_count,
    row_number() over(partition by t2.area order by t2.product_click_count desc) cn
from
    (
   select
   t1.area,
   t1.product_name,
   count(*) as product_click_count
   from
     (select
         c.area,
         p.product_name
      from
          user_visit_action a
      left join city_info c on a.`city_id` = c.`city_id`
      left join product_info p on a.`click_product_id` = p.`product_id`
      where a.click_product_id != -1)t1
      group by t1.area,t1.product_name
    )t2

--1.4对查询的结果取前三名
select
 *
from
(select
    t2.area,
    t2.product_name,
    t2.product_click_count,
    row_number() over(partition by t2.area order by t2.product_click_count desc) cn
from
    (
   select
   t1.area,
   t1.product_name,
   count(*) as product_click_count
   from
     (select
         c.area,
         p.product_name
      from
          user_visit_action a
      left join city_info c on a.`city_id` = c.`city_id`
      left join product_info p on a.`click_product_id` = p.`product_id`
      where a.click_product_id != -1)t1
      group by t1.area,t1.product_name
    )t2
    )t3
where t3.cn <= 3;

select name,count(*) 
from business 
where substring(orderdate,1,7) = '2017-04' 
group by name;


--2.通过代码实现

--3.城市备注实现(通过自定义UDAF函数)

-------------------------------------------------------------------------------------------
SparkStreaming 
    -Spark的内置模块,主要用于实时计算
    -微批次的流式实时计算框架
    -离线和实时
        数据处理的延迟
    
    -批和流式
获取StreamingContext方式:val ssc: StreamingContext = new StreamingContext(conf,Seconds(3))
                        
1.批处理间隔是Spark Streaming的核心概念和关键参数,它决定了Spark Streaming提交作业的频率和数据处理的延迟,同时也影响着数据处理的吞吐量和性能。
2.读取数据
    ssc.queueStream        从队列获取(一般不用,了解)
    ssc.socketTextStream  从端口号获取
    ssc.receiverStream  自定义Receiver读取指定数据源
    
    通过读取kafka数据源创建DS
      -spark-streaming-kafka-0-8(kafka 0.8 support is deprecated as of Spark 2.3.0)
        *receiver方式(过时,从zookeeper中获取offset)
            采集器(excutor)从kafka的partition中读取数据,然后分发给excutor进行处理
        *Direct方式(从checkpoint中维护offset,应用较少)
            Excutor可以直接从kafka的partition中读取数据
            >自动维护offset,需要改变Streamingcontext获取方式 StreamingContext.getActiveOrCreate
               1.自动维护偏移量,偏移量维护在checkpoint中
               2.指定检查点后,还需要设置从检查点中取offset,否则还是会出现丢失数据的情况。
               3.修改StreamingContext对象获取方式,先从检查点获取,如果检查点没有,通过函数创建,保证数据不丢失
               缺点:
                1.小文件过多
                2.在checkpoint中,只记录最后offset的时间戳,再次启动程序的时候,会从这个时间到当前时间的所有周期都执行一次
            >手动维护offset ,为保证数据的精准一致性,一般维护在有事务的存储上(mysql)
            
      -spark-streaming-kafka-0-10  (主流方式,消费的offset保存在kafka内置topic (consumer_offset)中)
        *Direct DStream
        *取到的是ConsumerRecords文件,获取值为ConsumerRecords.value
3.架构图
        采集线程(ssc.start) -> 
        Driver -> excutor(处理线程)
4.背压机制
    采集线程采集的速度大于excutor处理的速度,可以根据excutor的处理能力动态调节采集速率
    
5.DStream算子、
    -转换算子
        *无状态转换
            transform
            map/flatmap...
        *有状态转换
            updateStateByKey(Seq,Option) //Seq为相同key的value集合;Option为相同KEY的缓存数据  注:需要指定checkpoint
            window
    -输出算子
    
6.累加器和广播变量的使用与RDD相同,但需要注意使用sparkcontext调用累加器
7. sparkcore                  sparkSQL                  sparkStreaming
  sparkcontext(sc)    sparkSeesion(spark)  StreamingContext(ssc)  执行入口
  rdd                     dataframe/dataset          DStream             数据抽象
   
8.内核源码分析
    -第一部分:将App部署到Yarn服务器
    -第二部分:Job以及任务调度过程
        App->Job->Stage->Task
    -第三部分:提交Task到Executor
    -第四部分:Shuffle过程分析
    
    
spark优化
RDD中的样例类,可以自动实现序列化    
filter一般可以与colesce一起使用进行优化
    
    


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值