转至元数据结尾 转至元数据起始
Spark 任务开发:
开发语言:Spark 支持 Java、Scala、Python等多张语言,Spark 任务编写上,Scala 是最推荐使用的语言。
步骤:
- 本地开发,以local模式跑通。
- 提交到公司 yarn 集群,以 yarn-cluster 模式运行。(yarn-cluster模式适合production环境, yarn-client模式适合debug环境. 如果采用Yarn-Client请记住保留本地的Driver日志)
Spark 任务提交到yarn步骤:
- 本地生成jar包
- 拷贝到线上机器 lg09
- 在线上机器 lg09 上提交任务
Spark 任务-- WordCount (从编写到运行)
- clone 项目:git clone http://git.xiaomi.com:8088/miuicloud/sec/miui-sec/miui-sec-hadoop && scp -p -P 29418 liujianquan@git.xiaomi.com:hooks/commit-msg miui-sec-hadoop/.git/hooks/
- 导入 IDEA,IDEA 安装 Scala 插件 creating-and-running-your-scala-application
-
新建 Scala 文件 WordCount.scala, 编辑 pom.xml 文件,添加依赖(已添加)。
package
com.xiaomi.miui.sec.example
import
java.net.URI
import
org.apache.hadoop.conf.Configuration
import
org.apache.hadoop.fs.{FileSystem, Path}
import
org.apache.spark.{SparkConf, SparkContext}
/**
* 统计文件中单词出现的个数
* Created by Liu on 16/5/3.
*/
object
WordCount {
def
main(args
:
Array[String]) {
if
(args.length !
=
2
) {
System.err.println(
"Usage: WordCount <input> <output>"
)
System.exit(
1
)
}
// 传入命令行参数, input 输入文件地址, output 输出文件地址
val
Array(input, output)
=
args
// 创建 Spark 配置并设置 AppName 为 WordCount
val
sparkConf
=
new
SparkConf().setAppName(
"WordCount"
)
sparkConf.setIfMissing(
"spark.master"
,
"local[2]"
)
// 创建 SparkContext
val
sc
=
new
SparkContext(sparkConf)
// 如果输出文件存在, 则先删除
val
fs
=
FileSystem.get(
new
URI(output),
new
Configuration())
fs.delete(
new
Path(output),
true
)
// Split each line into words and flatten the result.
val
lines
=
sc.textFile(input)
val
words
=
lines.flatMap(
_
.split(
" "
))
// Map each word into a pair and count them by word (key).
val
wc
=
words.map(w
=
> (w,
1
)).reduceByKey(
_
+
_
)
// Save the result into text files - one per partition.
wc.saveAsTextFile(output)
sc.stop()
}
}
- 打包 jar 。
mvn package -P wordCount
target 目录下生成 miui-sec-spark-wordCount-1.1.12-pom-SNAPSHOT.jar - 复制 jar 到 线上机器 lg09。
scp liu@10.235.134.9:/Users/Liu/Projects/Xiaomi/src/miui-sec-hadoop/miui-sec-spark/target/miui-sec-spark-wordCount-1.1.12-pom-SNAPSHOT.jar /home/work/dev/jars/ - 在 lg09 上运行 WordCount 任务
local 模式
输入文件 input.txt
local 模式运行任务,$INFRA_CLIENT/bin/spark-submit --class com.xiaomi.miui.sec.example.WordCount --master local /home/work/dev/jars/miui-sec-spark-wordCount-1.1.12-pom-SNAPSHOT.jar file:///$PWD/input.txtfile:///$PWD/output
其中,spark-submit 参数请查阅 submitting-applications ,infra client 使用参考infra-client使用
输出结果 output
yarn-cluster 模式
把 WordCount 提交到公司的 yarn 集群(由于lg机房逐步淘汰,现在都提交到 c3 机房的集群 c3prc-hadoop,办公网访问C3集群需要设置代理,方法见 办公网访问IDC代理指南)
输入文件是 HDFS 上的 input.txt
提交任务到 yarn
查看 yarn 上的任务执行情况:http://c3-hadoop-prc-ct04.bj:22301/cluster/app/application_1447144693824_1536961
查看 SparkUI 上任务执行情况:http://c3hadoopproxy.d.xiaomi.net:18900/history/application_1447144693824_1536961/1/jobs/
(办公网需要设置代理访问)
查看 output 结果
Spark 读写 HBase
HBase 使用参考 Xiaomi HBase BookXiaomi(0.98)和 Xiaomi HBase Book(0.94)
Spark 支持从多种数据源读取数据,进行处理,并支持输出到多种数据源中。Spark 读写 HBase 的方法,在现有的项目中有,可以直接参考。
需要注意:
公司维护的HBase有两个版本,0.94 和 0.98 版,两个版本的依赖不一样。
spark-submit 提交时需要指定--hbase 参数
Spark 读取其他格式文件
读取 Paruqet 文件,有两种方法
- 使用数据工厂的包com.xiaomi.data:commons-spark:0.0.1-SNAPSHOT
具体参考 MapReduce/Spark读写Thrift+Paruqet/SequenceFile -
使用Spark SQL
添加spark-sql依赖<
dependency
>
<
groupId
>org.apache.spark</
groupId
>
<
artifactId
>spark-sql_2.10</
artifactId
>
<
version
>1.5.2</
version
>
<
scope
>provided</
scope
>
</
dependency
>
读parquet文件
val sqlContext =
new
org.apache.spark.sql.SQLContext(sc)
val parquetFile = sqlContext.read.parquet(srcFile)
val basicRDD = parquetFile.rdd.filter(row => {
if
(row.isNullAt(
1
) && row.isNullAt(
2
) && row.isNullAt(
3
))
false
else
true
}).mapPartitions(it => {
for
(row <- it) yield {
basicCounter +=
1
(row.getString(
0
), (row.getString(
1
), row.getString(
2
), row.getString(
3
)))
}
})
使用 Spark 过程中可能遇到的坑
- 强烈建议:首先阅读 小米 Spark用户 QA,可以避免很多坑,了解如何 kill 任务、查看日志等。
- 任务队列:提交任务要指定队列(–queue),不指定会分配到资源少的 default 队列。另外测试阶段可以提交到development 队列
我们组的队列是
Hadoop 任务:root.production.miui_group.miuisec
Spark 任务:root.service.miui_group.miuisec
一般情况,MR 任务提交到 Hadoop 队列,Spark 任务提交到 Service 队列,特殊情况也可变通。Spark 任务提交到 Hadoop 任务队列可能会被抢占。 - HBase:
HBase 作为输入时,region的数量就是任务的数量。当 Regin size 过大时,可以考虑 Split Region,使任务数增多,单个任务处理的数据量降下来。
Scan HBase 可能会遇到,内存泄漏的问题,可以加入配置 conf.set("hbase.ipc.client.connection.maxidletime", "3600000"),具体原因未知。。
任务只读取行一次的情况下,关闭 CacheBlocks scan.setCacheBlocks(false)
合理设置Scan参数可以提高性能,参考 http://stackoverflow.com/questions/22528859/hbase-scan-performance
需要全表scan之前,可以先指定 startRow 和 stopRow,小范围运行任务,验证结果。 - 使用 Accumulator :使用计数器,可以方便的记录次数,并在 Spark UI 上实时查看,比查看 log 文件方便。
-
脏数据
脏数据很难避免,代码要足够兼容。 - 数据倾斜
- 合理设置RDD的Cache