Spark
spark安装与部署
(1)配置文件:conf/spark-env.shn
export JAVA_HOME=/usr/local/jdk1.8.0n
export SPARK_MASTER_HOST=spark01n
export SPARK_MASTER_PORT=7077
(2) 配置文件:conf/slaven spark02n spark03
(3) 启动Spark集群:start-all.sh
Spark HA 实现
参考:
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=spark01:2181,spark02:2181,spark03:2181 -Dspark.deploy.zookeeper.dir=/spark"
每个节点上,需要将以下两行注释掉
export SPARK_MASTER_HOST=spark01n
export SPARK_MASTER_PORT=7077
执行Spark Demo程序
1、执行Spark Example程序Demo:
蒙特卡罗求PI(求π)命令:spark-submit --master spark://spark01:7077 --class org.apache.spark.examples.SparkPi examples/jars/spark-examples_2.11-2.1.0.jar 100
2、使用Spark Shellspark-shell是Spark自带的交互式Shell程序,方便用户进行交互式编程,用户可以在该命令行下用scala编写spark程序。
(*)启动Spark Shell:spark-shell也可以使用以下参数:
参数说明:–master spark://spark10:7077
指定Master的地址–executor-memory 2g
指定每个worker
可用内存为2G–total-executor-cores 2
指定整个集群使用的cup核数为2个
例:spark-shell --master spark://spark01:7077 --executor-memory 2g --total-executor-cores 2
如果启动spark shell时没有指定master地址,但是也可以正常启动spark shell和执行spark shell中的程序,其实是启动了spark的local模式,该模式仅在本机启动一个进程,没有与集群建立联系。
什么是RDD
(1)RDD是整个spark 的计算基石,是分布式数据的抽象,为用户屏蔽了底层复杂的计算和映射环境
(2)RDD是不可变的,如果需要在一个RDD上进行转换操作,则会生成一个新的RDD
(3)RDD是分区的,RDD里面的具体数据是分布式存在多台机器的executor里面的,堆内内存+堆外内存+磁盘
(4)RDD是弹性的
1.存储 :Spark会根据用户的配置获得当前Spark的应用运行情况去自动将RDD的数据缓存到内存或者磁盘。他是一个对用户不可见的,封装起来的功能
2.容错:当你的RDD数据被删除或者丢失的时候,可以通过血统或者检查点机制恢复数据,这个用户透明的
3.计算:计算是分层的,有应用->Job->Stage->TaskSet->Task每一层都有对应的计算的保障与重复机制,保障你的计算不会因为突发因素而终止
4.分片:可以根据业务需求或者一些算子来重新调整RDD中的数据分布
2.SparkCore(操作RDD)
RDD的创建-》RDD的转换-》RDD的缓存-》RDD的行动-》RDD的输出
创建RDD的方式有三种
1.从scala集合中创建RDD sc.parallelize(seq) 把seq这个数据并行化分片到节点sc.makeRDD(seq) 把seq这个数据并行化分片到节点,他的实现就是parallelizesc.makeRDD(seq[T,seq]) 这种方式可以指定seq的存放位置
2.从外部存储创建RDD比如 sc.textFile(“path”)
3.从其他RDD转换
transformations(转换) action(行动)的区别转换:
通过操作将一个RDD转换成另一个RDD(懒执行)行动:
将一个RDD进行求值或输出所有这些操作主要针对两种类型的RDD
(1)数值RDD
(2)键值对RDD
只有action的时候RDD才会真的去执行(优化)
算子
这里只列举了一些
object TestDemo {
def main(args: Array[String]): Unit = {
val conf=new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
val sc = new SparkContext(conf)
//transformation
//combineByKey
val array=Array(("java",98),("php",89),("hadoop",89),("java",88),("php",85),("hadoop",82))
val input: RDD[(String, Int)] = sc.parallelize(array)
val comp=input.combineByKey(
(v)=>(v,1),
(acc:(Int,Int),v)=>(acc._1+v,acc._2+1),
(acc1:(Int,Int),acc2:(Int,Int))=>(acc1._1+acc2._1,acc1._2+acc2._2) )
// comp.foreach(println(_))
//aggregateByKey 简化操作foldByKey
var rdd=sc.makeRDD(List((1,2),(1,3),(2,3),(3,8),(4,9),(3,5)),3)
rdd.aggregateByKey(0)(math.max(_,_),_+_)
rdd.foldByKey(0)(_+_)
//cogroup 在類型為(K,V)和(K,W)的RDD上調用,返回一個(K,(Iterable(v)),(Iterable(w)))類型的RDD
//笛卡爾積
var a=sc.makeRDD(1 to 3)
var b=sc.makeRDD(4 to 6)
a.cartesian(b)
//pipe 管道操作 類似mappartition (对于每个分区,都执行一个perl或shell脚本,返回输出的RDD),
//coalesce 缩减分区数,用于大数据集过滤后,提高小数据集的执行效率
//repartition 根据分区数重新通过网络分区所有数据(重型操作)
//glom 将每一个分区形成一个数组
//subtract 去除两个RDD 中相同的
//action
//reduce collect count first take takeSample(返回一个数组) takeOrdered(返回前几个的排序) fold
//saveAsTextFile 文本方式
val rdd2=sc.makeRDD(1 to 10,2)
rdd2.aggregate(1)(
{(x:Int,y:Int) =>x+y},
//得到第一个分区相加值
{(a:Int,b:Int)=> a+b}
//通过第一个分区相加值再去相加得到最终值
)
//当在RDD 中使用到了class的方法或者属性 ,该class需要继承java.io.Serializable接口,或者可以将属性赋值为本地变量来防止整个对象的传输
}
RDD依赖关系
1.RDD依赖关系分为宽依赖和窄依赖
2.窄依赖是说父RDD的每一个分区最多被一个子RDD的分区应用,也就是说它的出度为1
3.宽依赖是说父RDD的每一个分区被多个子RDD的分区应用,也就是说它的出度大于等于2
4.应用在整个过程中,RDD形成的产生关系,就叫做血统关系,RDD在没有持久化时默认是不保存的,如果需要,那么就要根据血统关系来重新计算
5.应用在执行过程中,是分为多个Stage来进行的,划分stage的关键,就是判断是不是存在宽依赖,从action往前去推整个Stage 的划分
RDD的持久化
1.RDD的持久化主要通过persist和cache操作来实现,cache操作就相当于StoageLevel为MEMORY_ONLY的persist操作
2.持久化它的存储等级可以分为:存储位置(磁盘,内存,非堆内存),是否序列化,存储的份数(1,2)
checkpoint用于hdfs(不存在血统关系) cache 用于内存上(存在血统关系)先cache 再checkpoint
RDD CheckPoint
1.创建一个RDD val check=sc.makeRDD(1 to 10)
2.设置SparkContext的checkpoint目录,如果你要用spark-shell,那么就是 sc.setCheckPointDir(“hdfs://hadoop01:9000/check”)
3.在RDD 上调用checkpoint方法 check.checkpoint
4.触发RDD的行动操作,让RDD的数据真实写入checkpoint目录
注意:整个checkpoint读取时用户透明
RDD DataSet DataFrame 之间的转换
RDD—>DataFrame :rdd.map(para=>(para(0).trim,para(1).trim.toInt)).toDF(“name”,“age”)
DataFrame—>RDD :dataframe.rdd
RDD—>DataSet :rdd.map(para=>Person(para(0).trim,para(1).trim.toInt)).toDS
DataSet—>RDD :DataSet.rdd
DataFrame—>DataSet :dataframe.to[Person]DataSet—>DataFrame :dataset.toDF
下面奉上从redis 以及mysql 传值与取值代码
1.redis
package day08
import org.apache.commons.pool2.impl.GenericObjectPoolConfig
import redis.clients.jedis.{Jedis, JedisPool}
object Jpools {
private val config = new GenericObjectPoolConfig()
private val pool = new JedisPool("192.168.198.110",6379)
def getJedis:Jedis={
val resource = pool.getResource
resource.select(1)
resource
}
}
package day08
import day04.MyUntil
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.broadcast.Broadcast
import org.apache.spark.rdd.RDD
object CoreToRedis {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
val sc = new SparkContext(conf)
//获取起始位置
val index: RDD[(Long, Long, String)] =sc.textFile("D:\\test\\ip.txt").map(tp=>{
val split=tp.split("[|]")
val start=split(2).toLong
val end=split(3).toLong
val provice=split(6)
(start,end,provice)
})
//array
val array: Array[(Long, Long, String)] = index.collect()
val arrays: Broadcast[Array[(Long, Long, String)]] = sc.broadcast(array)
//获取access 的ip地址
val ip: RDD[(String, Int)] = sc.textFile("D:/test/access.log").map(tp=>{
val split=tp.split("[|]")
val ip=split(1)
val ips=MyUntil.ip2Long(ip.toString())
val array2: Array[(Long, Long, String)] =arrays.value
val i: Int = MyUntil.find(array2,ips)
var pro=""
if(i != -1){
val value: (Long, Long, String) = array2(i)
pro=value._3
}
(pro,1)
})
val value: RDD[(String, Int)] = ip.reduceByKey(_+_)
//读出来
value.mapPartitions(filter=>{
val jedis = Jpools.getJedis
val aa: Iterator[String] =filter.map(tp=>{
val str = jedis.hget("aa","云南")
str
})
jedis.close()
aa
}).foreach(println(_))
//写进去
// value.foreachPartition(filter=>{
// val jedis = Jpools.getJedis
// filter.foreach(tp=>{
// jedis.hincrBy("aa",tp._1,tp._2)
// })
// jedis.close()
// })
}
}
2.mysql
package day08
import java.util.Properties
import day07.DataFrameToRedis.ip2Long
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.types.{LongType, StringType, StructField}
import org.apache.spark.sql.{Row, SaveMode, SparkSession, types}
object DataFrameToRedis {
def main(args: Array[String]): Unit = {
val session = SparkSession.builder().appName(this.getClass.getSimpleName).master("local[*]").getOrCreate()
import session.implicits._
val result1: RDD[Row] = session.sparkContext.textFile("D:\\test\\ip.txt").map(tp=>{
val split = tp.split("[|]")
Row(split(2).toLong,split(3).toLong,split(6))
})
val result2: RDD[Row] =session.sparkContext.textFile("D:\\test\\access.log").map(tp=>{
val split = tp.split("[|]")
Row(ip2Long(split(1)))
})
val schemaip=types.StructType{
List(
StructField("ip",LongType)
)
}
val schemaipresults=types.StructType{
List(
StructField("ipstart",LongType),
StructField("ipend",LongType),
StructField("provice",StringType)
)
}
val ipNum=session.createDataFrame(result2,schemaip)
val ipres=session.createDataFrame(result1,schemaipresults)
ipres.createTempView("result1")
ipNum.createTempView("iptable")
val result3 = session.sql(
"""
|select result1.provice,count(1) counts
|from result1
|join iptable
|on iptable.ip >=result1.ipstart and iptable.ip <= result1.ipend
|group by result1.provice order by counts
|desc limit 10
""".stripMargin)
val properties = new Properties()
// properties.setProperty("user","root")
// properties.setProperty("password","root")
// result3.write.mode(SaveMode.Append).jdbc("jdbc:mysql://localhost:3306/test1","ip",properties)
properties.setProperty("user","root")
properties.setProperty("password","root")
session.read.jdbc("jdbc:mysql://localhost:3306/test1","ip",properties).foreach(println(_))
}
}