spark
为什么需要spark
MapReduce的缺陷
- 最初设计用于高吞吐量的批处理,不擅长低延迟处理
- 需要将数据存储到HDFS,迭代计算中数据共享效率低
- 系统设计没有充分利用内存,很难实现高性能
- MapReduce不表达复杂的计算问题,如图形计算、迭代计算
Spark基于内存计算思想提高计算性能
- RDD:基于内存的弹性分布式数据集,通过对RDD的一系列操作完成计算任务可以大大提高性能
- 一组RDD形成可执行的有向无环图DAG
Spark 基本架构和组件
- Master node: 集群部署时的概念,是整个集群的控制器,负责整个集群的正常运行,管理Worker node
- Work node:是计算节点,接收主节点命令与进行状态汇报
- Executors:每个Worker上有一个Executor,负责完成Task程序的执行
Spark编程模型
- RDD 弹性分布式数据集: 一种分布式的内存抽象,允许大型集群上执行基于内存的计算
- RDD 还保持了容错特性
- RDD只读,可分区,这个数据机全部或部分可以缓存在内存中,在多次计算间重用。
RDD支持两种操作类型;
- 转换:惰性操作,使用这种方法时,只是定义了一个新的RDD,而并不是马上计算新的RDD内部的值
- 动作:立即计算这个RDD的值,并返回结果给程序,或者将结果写入到外存中
两种容错方式
-
Lineage(世系系统、依赖系统):RDD提供一种基于粗粒度变换的接口,这使得RDD可以通过记录RDD之间的变换,而不需要存储实际的数据,就可以完成数据的恢复,使得Spark具有高效的容错性
-
检查点:对于很长Lineage的RDD,通过lineage 来恢复耗时长,在对包含宽依赖的长世系的RDD设置检查点操作非常有必要
RDD之间的依赖关系
- 窄依赖: 父RDD中的一个Partition最多被子RDD中的一个Partition所依赖
- 宽依赖: 父RDD中的一个Partition被子RDD中的多个Partition所依赖。
RDD持久化
- 未序列化的Java对象,存在内存中:可直接在JVM机内存中的RDD对象
- 序列化的数据,存于内存中:使用时需要反序列化
- 磁盘存储:RDD太大
基于MapReduce的K-means 聚类算法
Map阶段
- 初始化方法setup中读取全局的聚类中心数据
- Map方法收到一个数据点p,计算p与所有聚类中心间的距离,并选择一个距离最小的中心作为p所属的聚类, 输出<ClusterID,(p,1)> 键值对
- 使用combiner 优化,合并相同ClusterID的数据点,求均值并记录数据点的个数n
Reduce 阶段
- 接收中间结果<ClusterID,[(pm1,n1),(pm2,n2)…]>计算新的均值 输出<ClusterID,(pm,n)>
- 输出所有的<ClusterID,(pm,n)>形成新的聚类中心,供下一次迭代计算
PageRank
使用MapReduce实现PageRank
1:GraphBuilder:建立网页之间的超链接图
- map:输出<URL,(PR_init, link_list)> , PR_init 是 PageRank初始值 ,再加上网页的出度链表
- Reduce:输出 <URL,(PR_init,link_list)> 不做别的处理
2:RageRankIter
- Map :对上一个阶段的 <URL,(cur_rank,link_list)>,产生两种 <key,value>
- Map: for u in link_ist , 输出 <u,cur_rank / | link_list |>
- Map: <URL, link_list>, 保留网页链出信息,维护图结构
- Reduce : 计算 new_rank, 输出<URL, (new_rank,url_list)>
3:Rankviewer
- PageRankViewer:将最终结果排序输出,以rank 为 key,以url为value进行排序