昨天在群里一个同学问了这样一个问题,Flink怎么根据数据里面的某个字段动态把数据写入多个kafka的topic.
其实这个问题非常简单,你肯定会想到说写多个sink就可以了,Flink确实也是支持多个sink的,但是他的需求是可能会写入上千个topic(我们这里不去讨论这个需求是否合理或者是否有这样的场景),我们肯定不可能会复制上千遍的代码.
那其实Flink提供了高阶的序列化模式,与FlinkKafkaConsumer类似,FlinkKafkaProducer提供了一个叫KeyedSerializationSchema的高级序列化模式的接口,这个模式允许分开地序列化key和value。同时允许重写目标topic,因此一个FlinkKafkaProducer可以发送数据到多个topic。
下面来看下KeyedSerializationSchema接口的源码
/** @deprecated */@Deprecated@PublicEvolvingpublic interface KeyedSerializationSchema<T> extends Serializable {
byte[] serializeKey(T var1); byte[] serializeValue(T var1); String getTargetTopic(T var1);}
可以看到这个接口里面有3个方法,可以分别对key,value进行序列化,还可以设置一个topic,但是你会发现这个接口已经被标记为Deprecated.我们先来用这个接口实现一下,虽然被标记为Deprecated,但是还是可以用的.
/** * 自定义序列化 根据数据里面的topic写入到不同的kafka的topic */class MyKeyedSerialization extends KeyedSerializationSchema[Person] {
private lazy val CHARSET = Charset.forName("UTF-8") // key的序列化 override def serializeKey(t: Person): Array[Byte] = t.age.toString.getBytes(CHARSET) // value的序列化 override def serializeValue(t: Person): Array[Byte] = t.toString.getBytes(CHARSET) // 从数据里面获取topic名称 override def getTargetTopic(t: Person): String = t.topic}
既然Flink官方不推荐使用这个接口了,那肯定有相应的替换接口,我们稍微找一下Flink的源码,就会发现有一个KafkaSerializationSchema新的接口.