经过4个RC版本,Spark 1.4最终还是赶在Spark Summit前发布了,本文简单谈下本版本中那些非常重要的新feature和improvement.

正式引入SparkR

  Spark 1.4正式引入了SparkR(可以参见本博客的《Spark官方正式宣布支持SparkR(R on Spark)》介绍),它是一个R API,SparkR是基于Spark的DataFrame抽象。用户可以通过local R data frames或者来自Spark各种外部数据源(比如Hie表)来创建SparkR DataFrame,SparkR DataFrame支持所有Spark DataFrame所支持的操作,包括聚合、过滤、分组、汇总统计以及其他的分析函数。同时它也支持混入SQL查询,而且支持将查询结果保存成DataFrame或者从DataFrame中获取数据。因为SparkR使用的是Spark的并行计算引擎,所以它的操作将可以使用多个Core和机器,而且可以在集群中分析大规模的数据,来看下下面的例子:

people <- read.df(sqlContext, "./examples/src/main/resources/people.json", "json")
 
 head(people)
  
 ##  age    name
  
 ##1  NA Michael
  
 ##2  30    Andy
  
 ##3  19  Justin
  
 # SparkR automatically infers the schema from the JSON file
  
 printSchema(people)
  
 
  
 # root
  
 #  |-- age: integer (nullable = true)
  
 #  |-- name: string (nullable = true)


  关于SparkR的编程指南,可以看这里《SparkR(R on Spark)编程指南》

Spark Core:

  现在大家最关心什么?性能和运维呀! 什么最影响性能?必须shuffle呀!什么是运维第一要务?必须是监控呀(就先不扯alert了)!1.4在这两点都做足了功夫。 1.4中,Spark为应用提供了REST API来获取各种信息(jobs / stages / tasks / storage info),使用这个API搭建个自己的监控简直是分分钟的事情,不止于此,DAG现在也能可视化了,不清楚Spark的DAGScheduler怎么运作的同学,现在也能非常轻易地知道DAG细节了。再来说说shuffle, 大家都知道,从1.2开始sort-based shuffle已经成为默认的shuffe策略了,基于sort的shuffle不需要同时打开很多文件,并且也能减少中间文件的生成,但是带来的问题是在JVM的heap中留了大量的java对象,1.4开始,shuffle的map阶段的输出会被序列化,这会带来两个好处:1、spill到磁盘上的文件变小了 2、GC效率大增 ,有人又会说,序列化反序列化会产生额外的cpu开销啊,事实上,shuffle过程往往都是IO密集型的操作,带来的这点cpu开销,是可以接受。

  大家期待的钨丝计划(Project Tungsten)也在1.4初露锋芒,引入了新的shuffle manager “UnsafeShuffleManager”, 来提供缓存友好的排序算法,及其它一些改进,目的是降低shuffle过程中的内存使用量,并且加速排序过程。 钨丝计划必定会成为接下来两个版本(1.5,1.6)重点关注的地方。

Spark Streaming:

  Streaming在这个版本中增加了新的UI, 简直是Streaming用户的福音啊,各种详细信息尽收眼底。话说Spark中国峰会,TD当时坐我旁边review这部分的code,悄悄对说我”this is awesome”。对了,这部分主要是由朱诗雄做的,虽然诗雄在峰会上放了我鸽子,但必须感谢他给我们带来了这么好的特性!另外此版本也支持了0.8.2.x的Kafka版本。


窗口函数和DataFrame的其他提升

Spark SQL(DataFrame)

  支持老牌的ORCFile了,虽然比Parquet年轻,但是人家bug少啊 : ) 1.4提供了类似于Hive中的window function,还是比较实用的。本次对于join的优化还是比较给力的,特别是针对那种比较大的join,大家可以体会下。JDBC Server的用户肯定非常开心了,因为终于有UI可以看了呀。

 这个版本的Spark SQL和Spark的DataFrame库引入了窗口函数,窗口函数是流行的数据分析函数,它运行用户统计窗口范围内的数据。

val w = Window.partitionBy("name").orderBy("id")
df.select(
 sum("price").over(w.rangeBetween(Long.MinValue, 2)),
  
 avg("price").over(w.rowsBetween(0, 4))
  
 )



  除此之外,社区为DataFrame带来了大量的提升,包括支持丰富的统计和数学函数

Spark ML/MLlib

  ML pipelines从alpha毕业了,大家对于ML pipelines的热情还真的蛮高的啊。我对Personalized PageRank with GraphX倒是蛮感兴趣的,与之相关的是recommendAll in matrix factorization model。 事实上大多数公司还是会在Spark上实现自己的算法。

可视化和监控工具

  生成环境下的Spark程序一般都很复杂,而且包含了很多的stages,Spark 1.4.0加入了可视化和监控工具,使得我们在spark作业运行的时候理解Spark的运行,这些都是非常棒的功能!


SparkSession设置最大 spark1.4最大变化_SparkSession设置最大



RestAPI

Spark 1.4中引入了REST API,这样我们可以像Hadoop中REST API一样,很方便地获取一些信息。这个ISSUE在https://issues.apache.org/jira/browse/SPARK-3644里面首先被提出,已经在Spark/api/v1。比如,对于历史服务器来说,我们可以通过http://:18080/api/v1来获取一些信息;对于正在运行的Spark应用程序,我们可以通过http://localhost:4040/api/v1来获取一些信息。

下面是目前Spark支持的所有REST API:


/applications:这个将显示所有的应用程序;
/applications/[app-id]/jobs:获取给定应用程序的所有Jobs;
/applications/[app-id]/jobs/[job-id]:获取给定Job的信息
/applications/[app-id]/stages:获取给定应用程序的所有stages;
/applications/[app-id]/stages/[stage-id]:获取给定stages的所有attempts ;
/applications/[app-id]/stages/[stage-id]/[stage-attempt-id]:获取给定stages attempts 的信息
/applications/[app-id]/stages/[stage-id]/[stage-attempt-id]/taskSummary:获取给定stage attempt中所有tasks的metrics信息
/applications/[app-id]/stages/[stage-id]/[stage-attempt-id]/taskList:获取给定stage attempt的所有tasks;
/applications/[app-id]/executors:获取给定应用程序的所有executors;
/applications/[app-id]/storage/rdd:获取给定应用程序的所有缓存的RDDs ;
/applications/[app-id]/storage/rdd/[rdd-id]:获取给定RDD的存储状态详情。


[app-id]改成[app-id]/[attempt-id]。上面所有的URL都是有版本的,这样将使得开发者们很容易在上面开发应用程序。此外,Spark还提供以下保证:

  1、任何一个版本的Endpoints都不会被移除;

  2、单个字段将永远不会从任何的Endpoints中移除;

  3、新的Endpoints可能被加入;

  4、新的字段可能会被加入到某个Endpoints中;

  5、新的版本可能会在未来加入到单独的Endpoint中(比如api/v2),而且新版本不要求向后兼容;

  6、API的版本可能会被删除,但至少存在一个新的API版本。applications/[app-id]部分,即使是存在一个应用程序。比如如果你想获取所有正在运行的应用程序的作业列表,你可以通过http://localhost:4040/api/v1/applications/[app-id]/jobs获取,这样做是为了在两种模式中保存一致的路径。查看:http://www.iteblog.com/archives/1386