spark的第二种共享变量是广播变量,它可以让程序高效地向所有工作节点发送一个较大的只读值。

1、广播变量的使用

应用场景:

 想向所有工作节点发送机器学习训练的模型参数,e.g.命名实体识别、分词的模型参数。

在spark2.0中,官方推荐Spark中所有功能的入口点都是SparkSession类,网上很多代码是基于老版本的,新老写法总结见如下代码。

spark2.X的java代码如下:

//spark2.0之前写法
SparkConf conf = new SparkConf().setAppName("RealNameDS").setMaster("local");
JavaSparkContext jsc = new JavaSparkContext(conf);

//spark2.0之后写法
SparkSession session = SparkSession.builder().master("local").appName("RealNameDS").getOrCreate();
session.sparkContext().setLogLevel("WARN");
...
// 从文件读取模型参数,并广播该变量,每个节点只会被发送一次
ArrayList<String> paramList = FileUtils.readFileAsList(modelPath);
...
//spark2.0之后从sparkContext中得到JavaSparkContext 
JavaSparkContext jsc = javaSparkContext.fromSparkContext(session.sparkContext());
final Broadcast<ArrayList<String>> paramListBroad = jsc.broadcast(paramList);
...
JavaPairRDD<String, Integer> phoneNamePairs = myRDD.mapPartitionsToPair(new PairFlatMapFunction<Iterator<Row>, String, Integer>() {
    @Override
	public Iterator<Tuple2<String, Integer>> call(Iterator<Row> rowIter) throws Exception {
        ArrayList<String> stayMapBroad = paramListBroad.value();
        ...
    }
});
...

(1)通过JavaSparkContext的broadcast()方法创建一个广播对象,任何可序列化的类型都可以这么实现。

(2)通过value()方法访问广播对象的值。

(3)广播变量只会被发到各个节点一次,应作为只读值处理,例如定义为final类型。

2、广播的序列化优化

当广播一个比较大的值时,选择既快又好的序列化格式可以显著提升性能。spark的Java API中默认使用的序列化库为Java序列化库,因此它对于除了基本类型的数组以外的任何对象都比较低效。spark支持使用第三方序列化库Kryo,它可以提供比Java的序列化工具更短的序列化时间和更高压缩比的二进制表示,但不能直接序列化全部类型的对象。

代码如下:

SparkConf conf = new SparkConf().setAppName("RealNameDS")setMaster("local");

conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
//严格要求注册类
conf.set("spark.kryo.registrationRequired", "true");
conf.registerKryoClasses(Array(classOf[MyClass]), classOf[MyOtherClass]);

首先,设置spark.serializer为org.apache.spark.serializer.KryoSerializer。为了获得最佳性能,向Kryo注册你想要序列化的类。注册类可以让Kryo避免把每个对象的完整类名写下来,成千上万条记录累计节省的空间相当可观。如果想强制要求这种注册,可以把spark.kryo.registrationRequired设置为true,这样Kryo会在遇到未注册的类时抛出错误。

如果抛出了NotSerializableException,要查出引发问题的类是比较困难的,可以通过设置spark-submit的--driver-java-options和--executor-java-options标记来打开“-Dsun.io.serialization.extened DebugInfo=true”选项。