Flink类型管理与序列化
Flink作为一个强大的实时计算引擎,底层大部分源码都是Java编写的,所以flink对pojo有着很好的支持,类似于Spark中DataFrame引入的schema,Flink也能够很好的infer推断数据类型的schema,可以将推断出的schema当作一个database,所以TypeInformation中包含了一个类的很多基本信息。TypeInformation决定了序列化方式与比较器。
1、 flink的数据处理
POJO(Plain Ordinary Java Object):简单的Java对象
Flink尝试推断很多有关在分布式计算过程中交换和存储的数据类型的信息。可以像一个推断表架构的数据库那样思考它。在大多数情况下,Flink会自行无缝地推断所有必要的信息。具有类型信息使Flink可以做一些很酷的事情:
- 使用POJO类型进行keyby(“username”)进行groupby、aggregating等操作,username是类型的属性
- flink对数据类型了解的越多,序列化和布局方案(layout schema)就越好,这对flink的内存使用优化非常重要
- 大多数情况下,开发者不需要担心序列化框架与必须注册类型
2、常见的问题
用户需要与flink的数据类型交互的最常见问题
- 注册子类型
- 如果函数签名仅描述superclass,如class A extends B ; def a(b: B) ,那么我们可以通过
env.registerType(classOf[A])
来注册subclass进行优化
- 如果函数签名仅描述superclass,如class A extends B ; def a(b: B) ,那么我们可以通过
- 注册自定义序列化程序
- 如果flink不能推断出该类型是否为POJO,那么就会回退到以Kryo进行序列化,但是并非所有的类型都按照kryo进行无缝处理,所以有些类型我们需要手动指明该序列化器
env.getConfig().addDefaultKryoSerializer(class,serializer)
- 如果flink不能推断出该类型是否为POJO,那么就会回退到以Kryo进行序列化,但是并非所有的类型都按照kryo进行无缝处理,所以有些类型我们需要手动指明该序列化器
- 手动创建typeInformation
- 如何创建一个TypeInformation:
import org.apache.flink.streaming.api.scala._ //must import
- TypeInformation所有类型描述符的基类,它揭示了所有类的基本属性,并可以生成序列化器!~
1)TypeInformation.of(classOf[SensorReading])
2)createTypeInformation[SensorReading]
3)BasicTypeInfo.STRING_TYPE_INFO
- 如何创建一个TypeInformation:
3、Flink的TypeInformation
3.1 flink对类型的区分
在Flink中对类型作了区分:
- 基本类型
- 所有的Java基本数据类型及其包装类 如:int Integer
- 基本数据、对象数据 如Array[Int] \ Array[Object]
- 复合类型
- Java TupleX【元组类型】
- Scala中的case class【样例类】
- Row (类似Spark中的DataFrame抽象中的类型就是【Row类型】,能推断schema)
- POJO 没有逻辑的遵循plain ordinary java object 的规则
- 辅助类型
- 范型类型
其中POJO耐人寻味,功能强大
Flink自动识别为POJO的要求
//Flink自动识别为POJO的要求
/** ***********************************************************************
* 1、必须是public的独立类(没有非静态内部类)
* 2、必须有公共的无参构造器
* 3、类中的所有非静态,非瞬态成员都是公共的,不能是最终的final,必须有对应的getter\setter方法
* ************************************************************************/
3.2 如何创建typeInformation及其Serializer
//在Flink程序中,有3种方式获取ExecutionConfig
//1、env.getConfig
//2、datastream|dataset.getExecutionConfig
//3、在RichFunction中通过getRuntimeContext.getExecutionConfig
//4、还可以通过工厂的方式创建typeinformation信息
val sensorInformation: TypeInformation[SensorReading] = createTypeInformation[SensorReading]
sensorInformation.createSerializer(env.getConfig)
4、自定义Kryo序列化方式
如果在Flink程序中无法通过Flink类型序列化器进行序列化,那么Flink将退回到使用Kryo序列化器的角度,我们可以在Kryo中注册自己的序列化程序或者序列化系统,常用的序列化系统有 Google Protobuf & Apache Thrift
具体操作可以如下:
//给一个类型添加默认的Kryo序列化方式
env.getConfig.registerTypeWithKryoSerializer(classOf[SensorReading],classOf[KryoSerializableSerializer])
如何使用外部系统的序列化方式:
- 首先引入相关的依赖
<!--Thrift依赖-->
<dependency>
<groupId>com.twitter</groupId>
<artifactId>chill-thrift</artifactId>
<version>0.7.6</version>
<!-- exclusions for dependency conversion -->
<exclusions>
<exclusion>
<groupId>com.esotericsoftware.kryo</groupId>
<artifactId>kryo</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- libthrift is required by chill-thrift -->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.11.0</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Protobuf依赖-->
<dependency>
<groupId>com.twitter</groupId>
<artifactId>chill-protobuf</artifactId>
<version>0.7.6</version>
<!-- exclusions for dependency conversion -->
<exclusions>
<exclusion>
<groupId>com.esotericsoftware.kryo</groupId>
<artifactId>kryo</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- We need protobuf for chill-protobuf -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.7.0</version>
</dependency>
2)然后注册序列化方式
// register the Google Protobuf serializer with Kryo
env.getConfig().registerTypeWithKryoSerializer(MyCustomType.class, ProtobufSerializer.class);
// register the serializer included with Apache Thrift as the standard serializer
// TBaseSerializer states it should be initialized as a default Kryo serializer
env.getConfig().addDefaultKryoSerializer(MyCustomType.class, TBaseSerializer.class);