Flink实战:写入Kafka自定义序列化类和自定义分区器

落花浮王杯 提交于 2021-02-04 07:35:25

概述:

    flink kafka实时流计算时都是用默认的序列化和分区器,这篇文章主要介绍如何向Kafka发送消息,并自定义消息的key,value,自定义消息分区类,这里选择最新的Flink1.9.1进行讲解。


自定义序列化类KeyedSerializationSchema:   


    通常我们都是用默认的序列化类来发送一条消息,有时候我们需要执行发送消息的key,value值,或者解析消息体后,在消息的key或者value加一个固定的前缀,这时候我们就需要自定义他的序列化类,Flink提供了可自定的的序列化基类KeyedSerializationSchema,这里先看下他的源码,:

package org.apache.flink.streaming.util.serialization;import java.io.Serializable;import org.apache.flink.annotation.PublicEvolving;/** @deprecated */@Deprecated@PublicEvolvingpublic interface KeyedSerializationSchema<T> extends Serializable {    byte[] serializeKey(T var1);
byte[] serializeValue(T var1);
String getTargetTopic(T var1);}

    是不是很简单 ,子类只需要自定义以上三个函数即可,这里我自定义序列化类CustomKeyedSerializationSchema,这里实现比较简单,只是将消息体进行拆分,分别在消息的键值加了前缀,代码如下:

package com.hadoop.ljs.flink.utils;import org.apache.flink.streaming.util.serialization.KeyedSerializationSchema;import java.util.Map;/** * @author: Created By lujisen * @company ChinaUnicom Software JiNan * @date: 2020-02-24 20:57 * @version: v1.0 * @description: com.hadoop.ljs.flink.utils */public class CustomKeyedSerializationSchema  implements KeyedSerializationSchema<String{    @Override    public byte[] serializeKey(String s) {        /*根据传过来的消息,自定义key*/        String[] line=s.split(",");        System.out.println("key::::"+line[0]);        return ("key--"+line[0]).getBytes();    }    @Override    public byte[] serializeValue(String s) {        /*根据传过来的消息,自定义value*/        String[] line=s.split(",");        System.out.println("value::::"+line[1]);        return ("value--"+line[1]).getBytes();    }    @Override    public String getTargetTopic(String topic) {        /*这里是目标topic,一般不需要操作*/        System.out.println("topic::::"+topic);        return null;    }}


自定义分区类FlinkKafkaPartitioner


    自定义分区类需要继承他的基类,只需要实现他的抽象函数partition()即可,源码如下:

package org.apache.flink.streaming.connectors.kafka.partitioner;import java.io.Serializable;import org.apache.flink.annotation.PublicEvolving;@PublicEvolvingpublic abstract class FlinkKafkaPartitioner<T> implements Serializable {    private static final long serialVersionUID = -9086719227828020494L;    public FlinkKafkaPartitioner() {    }    public void open(int parallelInstanceId, int parallelInstances) {    }    public abstract int partition(T var1, byte[] var2, byte[] var3, String var4, int[] var5);}

    自定义分区类CustomFlinkKafkaPartitioner,我这里只是简单的实现,你可根据自己的业务需求,自定义:

package com.hadoop.ljs.flink.utils;import org.apache.flink.streaming.connectors.kafka.partitioner.FlinkKafkaPartitioner;/** * @author: Created By lujisen * @company ChinaUnicom Software JiNan * @date: 2020-02-24 21:00 * @version: v1.0 * @description: com.hadoop.ljs.flink.utils */public class CustomFlinkKafkaPartitioner extends FlinkKafkaPartitioner {    /**     * @param record      正常的记录     * @param key         KeyedSerializationSchema中配置的key     * @param value       KeyedSerializationSchema中配置的value     * @param targetTopic targetTopic     * @param partitions  partition列表[0, 1, 2, 3, 4]     * @return partition     */    @Override    public int partition(Object record, byte[] key, byte[] value, String targetTopic, int[] partitions) {        //这里接收到的key是上面CustomKeyedSerializationSchema()中序列化后的key,需要转成string,然后取key的hash值`%`上kafka分区数量        System.out.println("分区的数据量:"+partitions.length);        int partion=Math.abs(new String(key).hashCode() % partitions.length);        /*System.out.println("发送分区:"+partion);*/        return partion;    }}


主函数: 


    我的主函数是从Socket端接收消息,写入Kafka集群,这里只是个例子实现比较简单,代码如下:

package com.hadoop.ljs.flink.streaming;import com.hadoop.ljs.flink.utils.CustomFlinkKafkaPartitioner;import com.hadoop.ljs.flink.utils.CustomKeyedSerializationSchema;import org.apache.flink.streaming.api.datastream.DataStream;import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer010;import java.util.Properties;/** * @author: Created By lujisen * @company ChinaUnicom Software JiNan * @date: 2020-02-24 21:27 * @version: v1.0 * @description: com.hadoop.ljs.flink.utils */public class FlinkKafkaProducer {
public static final String topic="topic2402";    public static final String bootstrap_server="10.124.165.31:6667,10.124.165.32:6667";    public static void main(String[] args) throws Exception { final String hostname="localhost"; final int port=9000; /*获取flink流式计算执行环境*/        final StreamExecutionEnvironment senv = StreamExecutionEnvironment.getExecutionEnvironment(); /*从Socket端接收数据*/ DataStream<String> dataSource = senv.socketTextStream(hostname, port, "\n"); /*下面可以根据自己的需求进行自动的转换*/ /* SingleOutputStreamOperator<Map<String, String>> messageStream = dataSource.map(new MapFunction<String, Map<String, String>>() { @Override public Map<String, String> map(String value) throws Exception { System.out.println("接收到的数据:"+value); Map<String, String> message = new HashMap<>(); String[] line = value.split(","); message.put(line[0], line[1]); return message; } });*/ /*接收的数据,中间可经过复杂的处理,最后发送到kafka端*/        dataSource.addSink(new FlinkKafkaProducer010<String>(topic, new CustomKeyedSerializationSchema(), getProducerProperties(),new CustomFlinkKafkaPartitioner())); /*启动*/ senv.execute("FlinkKafkaProducer");    } /*获取Kafka配置*/ public static Properties getProducerProperties(){ Properties props = new Properties(); props.put("bootstrap.servers",bootstrap_server);//kafka的节点的IP或者hostName,多个使用逗号分隔 props.put("acks", "1"); props.put("retries", 3); props.put("batch.size", 16384); props.put("linger.ms", 1); props.put("buffer.memory", 33554432); props.put("key.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer"); return props; }}


测试验证:


    从window命令行,通过socket端9000端口发送数据,主函数接收消息进行处理,然后发送kafka:


kafka接收消息,持久化到log中,如图:

     这里FLink的默认序列化和分区的知识我之后会写一篇文章详细讲解,在一个kafka没有经过SSL加密认证,加密后的Kafka集群如何与Flink进行集成,后面我都会统一进行讲解,敬请关注!!!!


本文分享自微信公众号 - 大数据开发运维架构(JasonLu1986)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!