一 Spark技术栈
Spark Core
Spark SQL
Spark Streaming
Spark GraphX
Spark MLlib
构建在Spark上的分布式机器学习库
二 Spark架构设计
运行架构
在驱动程序中,通过SparkContext主导应用的执行 SparkContext可以连接不同类型的Cluster Manager(Standalone、YARN、Mesos),连接后,获得集群节点上的Executor 一个Worker节点默认一个Executor,可通过SPARK_WORKER_INSTANCES调整 每个应用获取自己的Executor 每个Task处理一个RDD分区
核心组件
三 Spark API
SparkContext
连接Driver与Spark Cluster(Workers) Spark的主入口 每个JVM仅能有一个活跃的SparkContext SparkContext.getOrCreate
import org. apache. spark. { SparkConf, SparkContext}
val conf= new SparkConf( ) . setMaster( "local[2]" ) . setAppName( "HelloSpark" )
val sc= SparkContext. getOrCreate( conf)
SparkSession
Spark 2.0+应用程序的主入口:包含了SparkContext、SQLContext、HiveContext以及StreamingContext SparkSession.getOrCreate
import org. apache. spark. sql. SparkSession
val spark = SparkSession. builder. master( "local[2]" ) . appName( "appName" ) . getOrCreate( )
RDD&Dataset&DataFrame
RDD
Dataset
从Spark1.6开始引入的新的抽象,特定领域对象中的强类型集合,它可以使用函数或者相关操作并行地进行转换等操作 DataFrame
四 RDD
概念
简单的解释
RDD是将数据项拆分为多个分区的集合,存储在集群的工作节点上的内存中,并执行正确的操作 复杂的解释
RDD是用于数据转换的接口 RDD指向了存储在HDFS、Cassandra、HBase等、或缓存(内存、内存+磁盘、仅磁盘等),或在故障或缓存收回时重新计算其他RDD分区中的数据 RDD是弹性分布式数据集(Resilient Distributed Datasets)
分布式数据集
RDD是只读的、分区记录的集合,每个分区分布在集群的不同节点上 RDD并不存储真正的数据,只是对数据和操作的描述 弹性
RDD默认存放在内存中,当内存不足,Spark自动将RDD写入磁盘 容错性
RDD与DAG
两者是Spark提供的核心抽象 DAG(有向无环图)反映了RDD之间的依赖关系
特性
一系列的分区(分片)信息,每个任务处理一个分区 每个分区上都有compute函数,计算该分区中的数据 RDD之间有一系列的依赖 分区函数决定数据(key-value)分配至哪个分区 最佳位置列表,将计算任务分派到其所在处理数据块的存储位置
编程流程
RDD创建
import org. apache. spark. { SparkConf, SparkContext}
import org. apache. spark. rdd. RDD
object wordCount {
def main( args: Array[ String ] ) : Unit = {
println( "创建SparkContext" )
val conf: SparkConf = new SparkConf( ) . setMaster( "local[*]" ) . setAppName( "wordcount" )
val sc: SparkContext = SparkContext. getOrCreate( conf)
println( "---------parallelize方式创建RDD---------------" )
val rdd1: RDD[ Int ] = sc. parallelize( List( 1 , 2 , 3 , 4 , 5 , 6 ) , 2 )
rdd1. collect( ) . foreach( println)
println( rdd1. partitions. size)
println( rdd1. sum( ) )
println( "---------------makeRDD方式创建RDD-----------------" )
val rdd2: RDD[ Int ] = sc. makeRDD( List( 7 , 8 , 9 ) )
rdd2. collect( ) . foreach( println)
println( rdd2. partitions. size)
println( "--------通过键值对集合创建PairRDD--------------" )
val rdd3: RDD[ ( Int , Int ) ] = sc. parallelize( List( ( 1 , 2 ) , ( 3 , 4 ) ) )
rdd3. collect( ) . foreach( println)
println( "-------textFile加载本地相对路径-----------" )
val rdd4: RDD[ String ] = sc. textFile( "in/word.txt" )
rdd4. collect( ) . foreach( println)
rdd4. flatMap( _. split( " " ) ) . map( ( _, 1 ) ) . reduceByKey( _+ _) . collect( ) . foreach( println)
println( "------------textFile加载本地绝对路径-------------" )
val rdd5: RDD[ String ] = sc. textFile( "D:\\IDEA\\Data\\Spark\\mysparkdemo\\in\\word.txt" )
rdd5. collect( ) . foreach( println)
rdd5. flatMap( _. split( " " ) ) . map( ( _, 1 ) ) . groupBy( _. _1) . map( x => ( x. _1, x. _2. size) ) . collect( ) . foreach( println)
println( "-------textFile加载hdfs路径下文件/文件夹/正则匹配--------------" )
val rdd6: RDD[ String ] = sc. textFile( "hdfs://hadoopwei:9000/sparkWorkSpace/*2.txt" )
rdd6. collect( ) . foreach( println)
for ( elem <- rdd6. flatMap( _. split( " " ) ) . map( ( _, 1 ) ) . reduceByKey( ( x, y) => x + y) . collect( ) ) {
println( elem)
}
}
}
使用集合创建RDD
val rdd= sc. parallelize( List( 1 , 2 , 3 , 4 , 5 , 6 ) )
rdd. count
rdd. partitions. size
val rdd= sc. parallelize( List( 1 , 2 , 3 , 4 , 5 , 6 ) , 5 )
rdd. partitions. size
val rdd= sc. makeRDD( List( 1 , 2 , 3 , 4 , 5 , 6 ) )
Spark默认会根据集群的情况来设置分区的数量,也可以通过parallelize()第二参数来指定 Spark会为每一个分区运行一个任务进行处理
通过加载文件产生RDD
val distFile= sc. textFile( "file:///home/hadoop/data/hello.txt" )
distFile. count
val distHDFSFile= sc. textFile( "hdfs://hadoop000:8020/hello.txt" )
文件中的一行文本作为RDD的一个元素 加载“file://……”时,以local运行仅需一份windows本地文件,以Spark集群方式运行,应保证每个节点均有该文件的本地副本
支持目录、压缩文件以及通配符
sc. textFile( "/my/directory" )
sc. textFile( "/my/directory/*.txt" )
sc. textFile( "/my/directory/*.gz" )
Spark默认访问HDFS Spark默认为HDFS文件的每一个数据块创建一个分区,也可以通过textFile()第二个参数指定,但只能比数据块数量多
通过键值对集合创建PairRDD
sc. parallelize( List( ( 1 , 2 ) , ( 3 , 4 ) ) )