退出安全模式
[hadoop@hadoop000 sbin]$ hadoop dfsadmin -safemode leave
读取sequencefile
import org.apache.hadoop.io.BytesWritable
import org.apache.spark.{SparkConf, SparkContext}
class xxx
object scfileApp {
def main(args: Array[String]): Unit = {
val sparkConf=new SparkConf()
//在spark-shell运行的时候再指定,这里的优先级要比在shell里更高,appname
//shell里有内置
.setMaster("local[2]").setAppName("Spark05")
//定义序列化方式
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
//要序列化注册的类
.registerKryoClasses(Array(classOf[xxx]))
val sc =new SparkContext(sparkConf)
//读sequenceFile,参数,路径,key(字节的形式,因为seq底层key是二进制的)和value的类型
//用textfile读,有部分数据会乱码
val file = sc.sequenceFile[BytesWritable,String]("/user/hive/warehouse/page_views_sequencefile/000000_0")
//直接查,数不对
//file.foreach(println)
//会把进制码打出来,这些数据不想要
//file.map(x=>(x._1.copyBytes(),x._2)).foreach(println)
//x._1进制码去掉
file.map(x=>x._2.split("\t")).map(x=>(x(0),x(1))).foreach(println)
sc.stop()
}
}
序列化
由于大部分Spark计算都是在内存中完成的,所以Spark程序的瓶颈可能由集群中任意一种资源导致,如:CPU、网络带宽、或者内存等。最常见的情况是,数据能装进内存,而瓶颈是网络带宽;当然,有时候我们也需要做一些优化调整来减少内存占用,例如将RDD以序列化格式保存(storing RDDs in serialized form)。
所以序列化的作用
1.数据序列化(这对于优化网络性能极为重要)
2.减少内存占用以及内存调优。
序列化在任何一种分布式应用性能优化时都扮演几位重要的角色。如果序列化格式序列化过程缓慢,或者需要占用字节很多,都会大大拖慢整体的计算效率。
java序列化
默认情况,Spark使用Java自带的ObjectOutputStream 框架来序列化对象,这样任何实现了 java.io.Serializable 接口的对象,都能被序列化。同时,你还可以通过扩展 java.io.Externalizable 来控制序列化性能。Java序列化很灵活但性能较差,同时序列化后占用的字节数也较多。
kryo序列化
Spark还可以使用Kryo 库(version 4)提供更高效的序列化格式。Kryo的序列化速度和字节占用都比Java序列化好很多(通常是10倍左右),但Kryo不支持所有实现了Serializable 接口的类型,它需要你在程序中 register 需要序列化的类型,以得到最佳性能。
要切换到使用 Kryo,你可以在 SparkConf 初始化的时候调用 conf.set(“spark.serializer”,“org.apache.spark.serializer.KryoSerializer”)
。这个设置不仅控制各个worker节点之间shuffle数据,同时还控制RDD存到磁盘上的序列化格式。
要用到序列化的情况,涉及网络传输
算子里面使用到外部变量
cache
shuffle
程序模板
//定义序列化方式
conf.set(“spark.serializer”, “org.apache.spark.serializer.KryoSerializer”)
//要序列化注册的类
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
最后,如果你不注册需要序列化的自定义类型,Kryo也能工作,不过每一个对象实例的序列化结果都会包含一份完整的类名,这有点浪费空间。
测试
java序列化
32MB
kryo序列化,不带注册
57MB
kruo序列化,带注册
22MB
程序里的序列化方式定义写在shell里
$SPARK_HOME/bin/spark-submit \
--master local[2] \
--class com.ruozedata.bigdata.core05.serializeApp \
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \
--name serializeApp \
/home/hadoop/data/g5-spark-1.0.jar
注册留在程序里
import scala.collection.mutable.ListBuffer
case class Student(id:Int,name:String,age:Int)
object serializeApp {
def main(args: Array[String]): Unit = {
val sparkConf=new SparkConf()
//在spark-shell运行的时候再指定,这里的优先级要比在shell里更高,appname
//shell里有内置
// .setMaster("local[2]").setAppName("Spark05")
//定义序列化方式,写在shell里
// .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
// //要序列化注册的类
.registerKryoClasses(Array(classOf[Student]))
val sc =new SparkContext(sparkConf)
val students = ListBuffer[Student]()
for (i<- 0 to 1000000){
students.append(Student(i,"ruozedata_"+i,39))
}
val studentRDD = sc.parallelize(students)
//带序列化的cache
studentRDD.persist(StorageLevel.MEMORY_ONLY_SER)
studentRDD.count()
//跑完等会,看spark web,没开历史
Thread.sleep(1000*20)
sc.stop()
}
}
sparksubmit参数
源码:SparkSubmitArguments
spark-defaults.conf
式spark-shell的参数的配置文件,参数必须以spark.开头
得到设置的参数值
sc.getConf.get(" ")
参数优先级 spark-shell优先级大于代码和defaults.conf
SparkContext
1)SparkConf
2)创建SparkEnv
3) DAGScheduler 切分stage 并且提交stage
4) TaskScheduler task调度FIFO,提交作业到集群
5) UI
一个taskset就是stage
spark作业提交到yarn上执行,driver运行main方法,生成sparkcontext,根据一系列的算子生成DAG,传给DAGScheduler,DAGScheduler根据宽窄
依赖划分stage,根据划分好的stage,对应生成一组task set,将task set传给taskScheduler,taskScheduler启动exector进行任务执行
推测式执行
在shuffle中,假如某些key数据很多,运行的时间和资源要比其他的task多许多,称之为长尾作业,为了加快速度,启用推测式执行。
推测式执行原理
设个百分比,如果没跑完的作业占所有作业的百分比大于它,那么没跑完的作业同时会被其他节点运行。新节点的和原节点谁先执行完,用这个的结果,把另外一个杀掉。