文章目录
1 SCALA基础
1.1 变量
var和val的区别??
scala中的返回值是执行代码块的最后一行代码,不使用return语句返回结果;如果在for或者while等循环语句中,可以使用return返回结果
if(condition){
}else{
}
1.2 下滑线的作用
- var变量初始化的时候给定默认值
- 在函数赋值给一个变量的时候,使用下滑线表示参数的占位
- 高阶函数中下滑线表示参数的占位
- 在模式匹配中,下划线表示匹配所有
- 在import导入包的时候,下划线表示导入所有子包或者包中的类,类似java的*
1.3 scala中有一个非常特殊的数字 ==> 22
- 匿名函数中最多支持22个输入参数
- case class中最多支持22个属性(在主构造函数中定义)
- Tuple最多支持22元组
1.4 函数
1. 4.1 定义:
f: T => U 表示一个函数f,输入参数列表是T,返回值类型为U
def max(x:Int, y:Int):Int = if (x > y) x else y
1.4.2 函数的调用
val maxResult = max(5, 10)
函数赋值给一个变量
val max2 = max _
max2: (Int, Int) => Int
val a = (x:Int, y:Int) => if (x > y) x else y
1.4.3匿名函数
(x:Int, y:Int) => if (x > y) x else y
这个就叫做匿名函数,匿名函数一般赋值给一个变量然后再使用
val max3 = (x:Int, y:Int) => if (x > y) x else y
max3(1,3)
1.4.4高阶函数
如果一个函数f接收其它函数g作为输入参数,那么函数f就叫做高阶函数
eg:
def f(g: Int => Int) {println(g(10))}
def g1(a:Int) = a * 2
def g2(a:Int) = a * 3
高阶函数调用省略过程
-
可以省略输入参数的类型
f((a:Int) => a * 2)
-
如果输入参数列表中只有一个参数的话,那么可以省略输入参数的小括号
f(a => a * 2)
-
如果左侧的参数列表中的参数在右侧的函数体中有且仅使用一次,并且使用的顺序和参数列表中的参数属性一致,那么可以使用下划线来代替参数(前提:使用下划线代替后,可以推断出数据类型)
f(_ * 2)
map 和 flatMap 的区别
相同点:
都是对原始集合中的数据进行处理,然后返回一个新的集合,新集合中的元素和调用map/flatMap API的时候给定的参数函数有关;都对原始集合中的所有原始进行给定函数的处理
不同点:
map api返回的新集合中的元素就是给定参数函数的返回值
flatMap API要求给定的参数函数f必须返回一个集合,最终形成的新集合中的元素是函数f返回集合中的元素;实质是在map的基础上做了一个扁平化操作
Option
Scala中表示有值无值的一个class
Some表示有值 Some()
None表示无值
val c = Map("a"->16,"v"->89)
c("b")
c.getOrElse("b",-1)
c.get("b") = None
c.get("a") = Some(16).get
1.5 Try
scala中表示代码块执行是否有异常的一个class
Success表示执行成功,可以获取执行成功的结果
Failure表示有异常
1.6 隐式转换
val str:String = 123
//定义一个隐式转换函数即可
implicit def int2String(i:Int) = {
println("int 2 string")
i.toString
}
1.7 常见的符号
- : =》 数据类型 或者函数的返回类型 在IDEA使用 alt+Enter
- <- =》 for (i <- 0 until 9)
- -> =》 val a = Map(“key” -> value)
- :: =》 val a = 1::2::Nil
- => =》 匿名函数 (a:Int) => a+2
- +/+= ++/++= =》在变长数组ArrayBuffer ListBuffer使用 += 和++=添加元素
2、大数据的起源及发展
大数据改变世界,Spark改变大数据 大数据 大数据技术,HADOOP 2.x为主生态系统框架
*大数据起源于搜索,发展于电商/社交
数博会 人在干,数在转,云在算
腾讯 对几百台服务日志进行处理分析的技术选型的一个过程。 服务器的日志文件几百台机器,TB级别数据 分为三阶段:
第一阶段: MySQL + Python(数据清洗和ETL)
第二阶段: HADOOP + Hive 分区 涉及到一些负责业务:迭代计算,机器学习
第三阶段: HADOOP + Spark HDFS/Hive: 数据存储 YARN: Spark程序运行在YARN上
3、MapReduce的缺点
3.1 分布式计算框架,是Hadoop中的一个组件
InputFormat -> Mapper -> Shuffle -> Reducer -> OutputFormat
缺点:
1. 执行速度慢
内存利用率不高, shuffle的时候会将大量的数据溢出到磁盘
如果是一个多Job组成的MR任务的,前一个Job会将数据写出到HDFS上 ==> 有很大的网络IO、磁盘IO开销
Task启动比较慢,Task以进程的方式进行启动
2. 框架只提供map和reduce两个算子/API
只提供了map->reducer或者map [->map]* -> reducer [->map]*】
3.2 Spark
类比MapReduce框架,都是处理数据,分析数据
并行计算框架
Spark 优化的快读内存迭代框架
批处理(batch procssing) | 交互式处理 | 流处理 |
---|---|---|
MapReduce\Hive | Impala\Kylin | Storm\JStorm |
SparkCore | SparkSQL | SparkStreaming |
RDD | SQL\DSL |
Spark 核心编程
Spark Core
Spark 开发核心
Spark SQL
Spark Streaming
Spark 高级分析
Spark MLlib
Spark GraphX
4、Spark 发展
加州大学 伯克利 分校 AMPLab 实验室
AMP(机器学习,人工智能)
- A:算法
- M:机器
- P:人
Databrick金砖
5、Spark相关文档
基于内存迭代的分布式计算框架
文档:http://spark.apache.org/docs/2.2.1/
官方博客:https://databricks.com/blog
Apache Spark 2.2.0 中文文档
http://spark.apachecn.org/docs/cn/2.2.0/
6、Spark编译
官方的编译文档
http://spark.apache.org/docs/2.2.1/building-spark.html
- 下载
http://archive.apache.org/dist/spark/spark-2.2.1/
http://archive.apache.org/dist/spark spark-2.2.1/spark-2.2.1.tgz
- 将所需要的所有文件上传linux
- 开始编译(需要进行的信息参考ppt)
- apache hadoop依赖编译
./make-distribution.sh --tgz \
-Phadoop-2.6 \
-Dhadoop.version=2.6.0 \
-Pyarn \
-Phive -Phive-thriftserver
- cdh hadoop版本编译
./make-distribution.sh --tgz \
-Phadoop-2.6 \
-Dhadoop.version=2.6.0-cdh5.14.2 \
-Pyarn \
-Phive -Phive-thriftserver
7、将SPARK源码导入IDEA中
过程见ppt或者笔记中的图片
备注:所有的源码(包括不限于需要运行的代码)所放到的文件夹路径中不允许存在空格和中文。
备注:导入之前可以考虑将repository(Windows Linux开发环境依赖maven本地仓库).zip的内容解压到本地的maven仓库中
IDEA默认快捷键:
CTRL+N => 查找类,按两次表示查找依赖的类
CTRL+F12 => 在当前类中查找方法,按两次表示查找父类中的方法
ALT + ENTER => 万能的快捷键,主要用于异常提示、导包、类型给定等(鼠标放到异常位置或者需要给定类型的变量后面)
基本步骤:
1. 解压源码(11m的那个文件)到一个非中文的目录
2. 启动IDEA,在loading Project弹窗中点击canceling或者进入当前的工程界面 file -> close project
3. 替换saprk2.2.1源码项目所依赖的maven的本地仓库(先删除原有的,再解压进去)
8、Spark应用的四种运行环境
bin/spark-submit
本地模式
1、local => 主要用于开发(IDEA中运行)和开发的测试(spark-shell运行)
集群模式
2、standalone => 将spark应用运行在spark自带的资源管理器上
3、yarn => 将spark应用运行在yarn上
80%的公司选择将程序运行在yarn上
4、mesos => 将spark应用运行在mesos上
standalone、yarn、mesos均为集群资源管理器;mesos、standalone都是类似yarn的一种资源管理器
Spark on Local
环境搭建
-
先安装Scala
# 1.解压安装包 $ tar -zxf scala-2.11.8.tgz -C /opt/modules # 2.配置环境变量 $ sudo vi /etc/profile #SCALA_HOME export SCALA_HOME=/opt/modules/scala-2.11.8 export PATH=$PATH:$JAVA_HOME/bin:$SCALA_HOME/bin # 3.测试 $ source /etc/profile $ scala -version
-
解压编译好的压缩包或者软件工具文件夹中的压缩包
$ tar -zxf spark-2.2.1-bin-2.6.0-cdh5.14.2.tgz -C /opt/modules/cdh/
-
进入spark的根目录(解压目录)
$ cd /opt/modules/cdh $ ln -s spark-2.2.1-bin-2.6.0-cdh5.14.2/ spark2.2.1 $ cd spark2.2.1
-
修改配置信息(conf/spark-env.sh)
$ mv conf/spark-env.sh.template conf/spark-env.sh
JAVA_HOME=/opt/modules/java
SCALA_HOME=/opt/modules/scala
HADOOP_CONF_DIR=/opt/modules/cdh/hadoop-2.6.0-cdh5.14.2/etc/hadoop
SPARK_LOCAL_IP=[hostname]
注意:HADOOP_CONF_DIR参数的含义是指定spark连接的hadoop的相关配置信息所在的文件夹路径,当spark应用程序连接hadoop的时候,从会该路径下加载相关的配置信息 ===> 实质上就是将hdfs-site.xml、core-site.xml、yarn-site.xml配置文件添加到spark应用程序的classpath环境变量中 ===> 可以考虑不配置该参数,直接将配置文件放到${SPARK_HOME}/conf文件夹中
linux本地环境测试
-
- 启动hdfs的服务
-
- 运行run-example
$ bin/run-example SparkPi
$ bin/run-example SparkPi 100
-
- 官方案例测试
$ bin/spark-shell
17/10/17 11:56:09 INFO ui.SparkUI: Started SparkUI at http://192.168.187.146:4040
17/10/17 11:56:10 INFO repl.SparkILoop: Created spark context…
Spark context available as sc.
/beifeng/bc3108de-6f74-468d-b5e3-a8392e287103/_tmp_space.db
17/10/17 11:56:50 INFO repl.SparkILoop: Created sql context (with Hive support)…
SQL context available as sqlContext.
scala> val textFile = sc.textFile("README.md")
使用fs.defaultFS指定的文件系统进行RDD数据读取
底层的原理:
如何读取HDFS数据呢???
按照MapReduce读取文件的方式进行的
默认情况下MapReduce读取HDFS
一行一行的读取,将每一行的数据变为Key,Value对的形式
Key:
每行数据的所在文件的偏移量
Value:
每一行的值
//明确指定读取本地磁盘的文件数据(本地磁盘该文件存在)
val textFile = sc.textFile("file:///opt/modules/cdh/spark2.2.1/spark/README.md")
textFile.count()
textFile.first()
val linesWithSpark = textFile.filter(line => line.contains("Spark"))
textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
textFile: 默认形成RDD数据格式是:文件中的一行数据就是RDD中的一个元素
备注:
textFile给定的文件路径,如果没有给定schema信息的情况下,默认使用fs.defaultFS作为默认的schema;当配置好HADOOP_CONF_DIR,默认的文件系统为HDFS文件系统; 也就是说如果没有配置HADOOP_CONF_DIR配置信息,那么使用本地磁盘作为默认的文件系统
9、数据分析统计:
- 1,清洗过滤
- 2,分组 word count
- 3,统计
- 4,排序 top
- 5,Top
row_number over(partition by col1 sort by col2 asc/dec) rank
10、WordCount
编程结构:
Step 1:
读取要处理要分析的数据 -> 内存
封装
集合(RDD : Resilient Distributed Dataset) 数据结构
分区的 - hdfs block
每个分区进行数据处理,函数 - RDD
Step 2:
分析处理数据
RDD#transformation
Step 3:
将分析数据分结果进行存储
RDD#action
RDD的算子
算子/函数(方法)
-
- 处理数据 函数
Transformation 转换
-
- 存储或者返回
Action
count\take(5)\saveAsTextFile(“”)\foreach(item => { })
Wordcount案例详解
- 将word.txt上传到hdfs上
- WordCount案例实现
// 修改当前应用的日志级别
sc.setLogLevel("ERROR")
- 编码
- 3.1 读取文件形成RDD
//基于输入数据构建RDD; textFile API是读取HDFS上的文件形成RDD,其中第一个参数给定HDFS上的文件路径,第二个参数给定形成RDD的最少分区数量;默认分区数为2
val rdd = sc.textFile("/beifeng/spark/data/word.txt")
// rdd: org.apache.spark.rdd.RDD[String] = /beifeng/spark/data/word.txt MapPartitionsRDD[9] at textFile at <console>:27
- 3.2 调用Transformation算子,实现业务功能
val rdd0 = rdd.flatMap(line => line.split(" "))
val rdd1 = rdd0.filter(word => word.nonEmpty)
val rdd2 = rdd1.map(word => (word,1))
val rdd3 = rdd2.groupBy(t => t._1)
val resultRDD1 = rdd3.map(t => {
// rdd3中的数据类型是一个二元组,第一个元素是进行分组的数据, 也就是单词,第二个数据,分组后,相同数据的value形成的一个迭代器; value本身的数据类型是一个(String,Int)的二元组
(hive,iter((hive,1),(hive,1),(hive,1))
val word = t._1
val iter = t._2
val sum = iter.map(tt => tt._2).sum
(word, sum)
})
val rdd4 = rdd2.groupByKey()
val resultRDD2 = rdd4.map(t => {
// rdd4中的数据类型是一个二元组,第一个元素是进行分组的数据, 也就是单词,第二个数据,分组后,相同数据的value形成的一个迭代器;value的原始数据类型是Int
ive,iter(1,1,1))
val word = t._1
val iter = t._2
val sum = iter.sum
(word, sum)
})
// aggregateByKey和reduceByKey的性能比groupByKey的性能高,在实际的工作中,优先考虑前两个API;性能高的原因是:前两个API在进行shuffle之前会对每个分区的数据进行聚会的聚合操作,可以降低shuffle传输量 ==> 类似MapReduce的combiner的作用
val resultRDD3 = rdd2.reduceByKey((a,b) => a + b)
- 3.3将结果数据输
// 输出到控制台
resultRDD3.collect.foreach(i => println(i))
resultRDD3.first
resultRDD3.take(10)
// 输出到HDFS文件中
resultRDD3.saveAsTextFile("/beifeng/spark/core/wc")
11 、TopN的程序
含义:获取出现次数最多的前N个元素的值 (对于wrodcount而言)
resultRDD3.map(t => (t._2, t._1)).sortByKey(ascending = false).take(5).map(t => t.swap)
// 默认的排序器对于元组的数据来讲,是先对第一个元素进行比较,如果第一个相同,再比较第二个、第三个....
resultRDD3.map(_.swap).top(5).map(_.swap)
resultRDD3.top(5)(ord = new scala.math.Ordering[(String,Int)](){
override def compare(x: (String,Int), y: (String,Int)): Int = {
// 返回0表示相等,-1表示x<y(负数),1表示x>y(正数)
val tmp = x._2.compare(y._2)
if (tmp != 0) {
tmp
} else {
x._1.compare(y._1)
}
}
})
12、Spark Standalone(独立运行)
Spark的运行架构
Standalone属于Spark自身自带的分布式资源管理和任务调度框架(Spark Application), 是一种类似Yarn的spark自带的资源管理框架
主节点 YARN
Master ResourceManager
从节点
Works NodeManagers
Yarn架构
ResourceManager
负责集群资源的管理
NodeManager
负责当前节点上的资源管理
Standalone架构
Master
负责管理集群的所有资源
Worker
负责当前进程的所有资源
资源:CPU和内存
资源:CPU Cores + 内存
假设单个节点的为2颗CPU,每颗12核,内存128G
CPU指的是逻辑CPU、内存也是逻辑内存CPU是参数yarn.nodemanager.resource.cpu-vcores(默认为8) 控制,默认情况下表示一个NodeManager管理8核的CPU //18核
内存是参数yarn.nodemanager.resource.memory-mb(默认8192)控制,
默认情况下表示一个NodeManger管理8g的内存 //100G
默认情况下,一个MapReduce的task(map task\reduce task)需要1核cpu+1g内存
Standalone的环境配置:
- 前提:spark的本地执行环境已经搭建好了
- 修改conf/spark-env.sh文件内容
SPARK_MASTER_IP=[hostname]
SPARK_MASTER_PORT=7070
SPARK_MASTER_WEBUI_PORT=8080
# 给定当前的机器上的一个worker进程允许分配/管理的cpu核数
SPARK_WORKER_CORES=2
# 给定当前机器上的一个worker进程允许分配/管理的内存大小
SPARK_WORKER_MEMORY=2g
SPARK_WORKER_PORT=7071
SPARK_WORKER_WEBUI_PORT=8081
## 给定当前机器上允许存在多少个worker进程(spark1.6),当前版本中不要配置
SPARK_WORKER_INSTANCES=2
- 配置worker机器列表(slave列表)
$ mv conf/slaves.template conf/slaves
- 启动standalone的服务
sbin/start-master.sh
sbin/start-slaves.sh
sbin/start-slave.sh spark://[hostname]:7070
#关闭所有
sbin/stop-all.sh
# 开启所有
sbin/start-all.sh
Standalone的测试
–master MASTER_URL spark://host:port, mesos://host:port, yarn, or local. ==> 指定spark应用的运行环境
$ bin/spark-shell --master spark://[hostname]:7070
val rdd = sc.textFile("/beifeng/spark/data/word.txt")
val rdd0 = rdd.flatMap(line => line.split(" "))
val rdd1 = rdd0.filter(word => word.nonEmpty)
val rdd2 = rdd1.map(word => (word,1))
val resultRDD3 = rdd2.reduceByKey((a,b) => a + b)
resultRDD3.collect.foreach(println)
问题:
- bin/spark-shell --master local[2] bin/spark-shell --master spark://bigdata.server1:7070 不要两个同时起
- 不相关的进程最好不要启动, 目前仅需要启动 hdfs相关的进程
- 配置文件要生效,master 和 worker进程必须先停止,再启动
- 在standalone模式下,提交应用程序或者运行spark-shell,必须使用 --master spark://bigdata.server1:7070 表式应用程序运行所需的资源需要通过master节点来分配
历史日志聚合
- 生成历史日志聚合配置文件
$ cp conf/spark-defaults.conf.template conf/spark-defaults.conf
- 在conf/spark-defaluts.conf中拷贝以下两个参数并修改
注意:spark.eventLog.dir在hdfs对应的目录需要手动创建
spark.eventLog.enabled true
spark.eventLog.dir hdfs://linux01:8020/spark/history
- 在conf/spark-env. sh中配置中已有的参数下方增加以下参数
注意:1.“=”左右两侧不能有空格;2.右侧的配置信息是一行内容,并且 –D后面也没有空格
SPARK_HISTORY_OPTS="-Dspark.history.fs.logDirectory=hdfs://linux01:8020/spark/history -Dspark.history.ui.port=18080"
13、Standalone分布式配置
1.完全分布式(没有HA)
- 所有机器之间的免密码登录完全做好了
- 选取一台配置进行配置spark,修改spark-env.sh中对应的IP地址信息以及路径信息(eg: JAVA_HOME\SCALA_HOME…)
- 在master机器上修改slaves文件内容,将所有的worker机器ip地址添加到文件中,一行一个
- 将一台配置好的机器上的spark的目录ssh-copy到其它机器上
2.Standalone Master HA配置
http://spark.apache.org/docs/2.2.1/spark-standalone.html#high-availability
1. Single-Node Recovery with Local File System
基于文件的单节点master恢复机制
修改conf/spark-env.sh文件内容添加一个环境变量
SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=FILESYSTEM -Dspark.deploy.recoveryDirectory=/tmp"
2. Standby Masters with ZooKeeper
基于zk的active、standby模式的HA热备机制
修改conf/spark-env.sh文件内容添加一个环境变量
SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=hadoop01:2181,hadoop02:2181,hadoop03:2181 -Dspark.deploy.zookeeper.dir=/spark"
3.(基于zookeeper的多节点HA)在spark-env.sh文件中将之前的关于master配置信息全注释掉
#SPARK_MASTER_IP
#SPARK_MASTER_PORT
#SPARK_MASTER_WEBUI_PORT