Flink开发-常用的Source数据源

Flink开发-常用的Source数据源

  • 1.基于集合的Source
    • 1.1 fromCollection
    • 1.2 fromElements
    • 1.3 fromParallelCollection
    • 1.4 generateSequence
  • 2.基于Socket的Source
  • 3.基于文件的Source
    • 3.1 readFile
    • 3.1 readTextFile
  • 4.Kafka Consumer
  • 5.自定义单并行度Source
  • 6.自定义多并行度Source
    • 6.1 实现ParallelSourceFunction
    • 6.2 实现RichParallelSourceFunction

1.基于集合的Source

基于集合的Source是将一个普通的Java集合、迭代器或者可变参数转换成一个分布式数据集DataStreamSource,它是DataStream的子类,所以也可以使用DataStream类型来引用。得到DataStream后就可以调用Transformation或Sink度数据进行处理了。

1.1 fromCollection

fromCollection(Collection) 方法是一个非并行的Source,可以将一个Collection类型的数据作为参数传入到该方法中,返回一个DataStreamSource。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Integer> fromCollection = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5, 6));
        System.out.println("fromCollection创建的DataStream并行度为:"+fromCollection.getParallelism());
        fromCollection.print();
        env.execute("");
    }

输出结果:

fromCollection创建的DataStream并行度为:1
8> 1
3> 4
1> 2
2> 3
4> 5
5> 6

1.2 fromElements

fromElements(T …) 方法是一个非并行的Source,可以将一到多个数据作为可变参数传入到该方法中,返回DataStreamSource。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Integer> fromElements = env.fromElements(1, 2, 3, 4, 5, 6);
        System.out.println("fromElements创建的DataStream并行度为:"+fromElements.getParallelism());
        fromElements.print();
        env.execute("");
    }

输出结果:

fromElements创建的DataStream并行度为:1
7> 2
6> 1
8> 3
2> 5
1> 4
3> 6

1.3 fromParallelCollection

fromParallelCollection(SplittableIterator, Class) 方法是一个并行的Source(并行度可以使用env的setParallelism来设置),该方法需要传入两个参数,第一个是继承SplittableIterator的实现类的迭代器,第二个是迭代器中数据的类型。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Long> fromParallelCollection = env.fromParallelCollection(new NumberSequenceIterator(1L,6L),Long.class);
        System.out.println("fromParallelCollection创建的DataStream并行度为:"+fromParallelCollection.getParallelism());
        fromParallelCollection.print();
        env.execute("");
    }

输出结果:

fromParallelCollection创建的DataStream并行度为:8
5> 5
4> 4
2> 2
6> 6
3> 3
1> 1

1.4 generateSequence

generateSequence(long from, long to) 方法是一个并行的Source(并行度也可以通过调用该方法后,再调用setParallelism来设置)该方法需要传入两个long类型的参数,第一个是起始值,第二个是结束值,返回一个DataStreamSource。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Long> generateSequence = env.generateSequence(1L, 6L);
        System.out.println("generateSequence创建的DataStream并行度为:"+generateSequence.getParallelism());
        generateSequence.print();
        env.execute("");
    }

输出结果:

generateSequence创建的DataStream并行度为:8
5> 5
1> 1
6> 6
3> 3
2> 2
4> 4

2.基于Socket的Source

socketTextStream(String hostname, int port) 方法是一个非并行的Source,该方法需要传入两个参数,第一个是指定的IP地址或主机名,第二个是端口号,即从指定的Socket读取数据创建DataStream。该方法还有多个重载的方法,其中一个是socketTextStream(String hostname, int port, String delimiter, long maxRetry),这个重载的方法可以指定行分隔符和最大重新连接次数。这两个参数,默认行分隔符是”\n”,最大重新连接次数为0。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> socketTextStream = env.socketTextStream("localhost",8888);
        System.out.println("socketTextStream创建的DataStream并行度为:"+socketTextStream.getParallelism());
        socketTextStream.print();
        env.execute("");
    }

输出结果:

socketTextStream创建的DataStream并行度为:1
5> 1
6> 2
7> 3
8> 4
1> 5
2> 6

提示:如果使用socketTextStream读取数据,在启动Flink程序之前,必须先启动一个Socket服务,为了方便,Mac或Linux用户可以在命令行终端输入nc -lk 8888启动一个Socket服务并在命令行中向该Socket服务发送数据。Windows用户可以在百度中搜索windows安装netcat命令。

3.基于文件的Source

基于文件的Source,本质上就是使用指定的FileInputFormat格式读取数据,可以指定TextInputFormat、CsvInputFormat、BinaryInputFormat等格式,基于文件的Source底层都是ContinuousFileMonitoringFunction,这个类继承了RichSourceFunction,它们都是非并行的Source。

3.1 readFile

readFile(FileInputFormat inputFormat, String filePath) 方法可以指定读取文件的FileInputFormat 格式,其中一个重载的方法readFile(FileInputFormat inputFormat, String filePath, FileProcessingMode watchType, long interval) 可以指定FileProcessingMode,它有两个枚举类型分别是PROCESS_ONCE和PROCESS_CONTINUOUSLY模式,PROCESS_ONCE模式Source只读取文件中的数据一次,读取完成后,程序退出。PROCESS_CONTINUOUSLY模式Source会一直监听指定的文件,如果使用该模式,需要指定检测该文件是否发生变化的时间间隔,但是使用这种模式,文件的内容发生变化后,会将以前的内容和新的内容全部都读取出来,进而造成数据重复读取。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        String path = "src/main/resources/test.txt";
        //PROCESS_CONTINUOUSLY模式是一直监听指定的文件或目录,2秒钟检测一次文件是否发生变化
        DataStreamSource<String> readFile = env.readFile(new TextInputFormat(null), path,
                FileProcessingMode.PROCESS_CONTINUOUSLY, 2000);
        System.out.println("readFile创建的DataStream并行度为:"+readFile.getParallelism());
        readFile.print();
        env.execute("");
    }

输入内容:

qwe,71,1
wer,62,2
ert,53,3
rty,44,4
tyu,35,5
yui,26,6   //程序运行后输入的一行

输出结果:

readFile创建的DataStream并行度为:8
7> rty,44,4
4> wer,62,2
8> tyu,35,5
3> qwe,71,1
5> ert,53,3
1> yui,26,6
5> ert,53,3
6> rty,44,4
3> qwe,71,1
7> tyu,35,5
4> wer,62,2

3.1 readTextFile

readTextFile(String filePath) 可以从指定的目录或文件读取数据,默认使用的是TextInputFormat格式读取数据,还有一个重载的方法readTextFile(String filePath, String charsetName)可以传入读取文件指定的字符集,默认是UTF-8编码。该方法是一个有限的数据源,数据读完后,程序就会退出,不能一直运行。该方法底层调用的是readFile方法,FileProcessingMode为PROCESS_ONCE。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        String path = "src/main/resources/test.txt";
        DataStreamSource<String> readTextFile = env.readTextFile(path);
        System.out.println("readTextFile创建的DataStream并行度为:"+readTextFile.getParallelism());
        readTextFile.print();
        env.execute("");
    }

输入内容:

qwe,71,1
wer,62,2
ert,53,3
rty,44,4
tyu,35,5
yui,26,6  

输出结果:

readTextFile创建的DataStream并行度为:8
2> wer,62,2
1> qwe,71,1
4> rty,44,4
3> ert,53,3
5> tyu,35,5
7> yui,26,6

4.Kafka Consumer

首先在maven项目的pom.xml文件中导入Flink跟Kafka整合的依赖:

    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-connector-kafka_${scala.binary.version}</artifactId>
      <version>${flink.version}</version>
    </dependency>

在代码中,创建一个Properties对象,然后设置Kafka的地址和端口、读取偏移量的策略、消费者组ID、并且设置Source读取完Kafka的数据后,定期更新偏移量。然后new FlinkKafkaConsumer,指定三个参数,第一个参数是topic名称;第二个参数是读取文件的反序列化Schema,SimpleStringSchema指的是读取Kafka中的数据反序列化成String格式;第三个参数是传入事先new 好的Properties实例。然后调用env的addSource方法将FlinkKafkaConsumer的实例传入,这样就创建好了一个DataSteamSource。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        //设置Kafka相关参数
        Properties properties = new Properties();
        //设置Kafka的地址和端口
        properties.setProperty("bootstrap.servers", "59.XXX.XXX.35:9092,59.XXX.XXX.36:9092,59.XXX.XXX.37:9092");
        //读取偏移量策略:如果没有记录偏移量,就从头读,如果记录过偏移量,就接着读
        properties.setProperty("auto.offset.reset", "earliest");
        //设置消费者组ID
        properties.setProperty("group.id", "group1");
        //没有开启checkpoint,让flink提交偏移量的消费者定期自动提交偏移量
        properties.setProperty("enable.auto.commit", "true");
        //创建FlinkKafkaConsumer并传入相关参数
        FlinkKafkaConsumer<String> kafkaConsumer = new FlinkKafkaConsumer<>(
                "mytest", //要读取数据的Topic名称
                new SimpleStringSchema(), //读取文件的反序列化Schema
                properties //传入Kafka的参数
        );
        //使用addSource添加kafkaConsumer
        DataStreamSource<String> kafkaStream = env.addSource(kafkaConsumer);
        System.out.println("kafkaStream创建的DataStream并行度为:"+kafkaStream.getParallelism());
        kafkaStream.print();
        env.execute("");
    }

输入内容:

{"table":"11ttt","item_id":"111","pkey":["COMPID","ID"],"sub":{"k":"k1"},"subr":{"s":"s1","k":"k1"}}

输出结果:

kafkaStream创建的DataStream并行度为:8
3> {"table":"11ttt","item_id":"111","pkey":["COMPID","ID"],"sub":{"k":"k1"},"subr":{"s":"s1","k":"k1"}}

注意:目前这种方式无法保证Exactly Once,Flink的Source消费完数据后,将偏移量定期的写入到Kafka的一个特殊的topic中,这个topic就是__consumer_offset,这种方式虽然可以记录偏移量,但是无法保证Exactly Once。

5.自定义单并行度Source

Flink的DataStream API可以让开发者根据实际需要,灵活的自定义Source,本质上就是定义一个类,实现SourceFunction这个接口,实现run方法和cancel方法。run方法中实现的就是获取数据的逻辑,然后调用SourceContext的collect方法,将获取的数据收集起来,这样就返回了一个新的DataStreamSource,但是如果只实现这个接口,该Source只能是一个非并行的Source。

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> mySource = env.addSource(new MySource1());
        System.out.println("MySource1创建的DataStream并行度为:"+mySource.getParallelism());
        mySource.print();
        env.execute("");
    }
    public static class MySource1 implements SourceFunction<String> {
        @Override
        public void run(SourceContext<String> sourceContext) throws Exception {
            List<String> strs = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
            for (String str:strs){
                //将Source的数据输出
                sourceContext.collect(str);
            }
        }
        @Override
        public void cancel() {}
    }

输出结果:

MySource1创建的DataStream并行度为:1
8> aaa
4> eee
3> ddd
1> bbb
2> ccc

6.自定义多并行度Source

在生产环境,通常是希望Source可以并行的读取数据,这样读取数据的速度才更快,所以最好的方式是实现ParallelSourceFunction接口或继承RichParallelSourceFunction这个抽象类,同样实现实现run方法和cancel方法,这样该Source就是一个可以并行的Source了。其实所有的Source底层都是调用该的方法。

6.1 实现ParallelSourceFunction

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> mySource = env.addSource(new MySource2());
        System.out.println("MySource2创建的DataStream并行度为:"+mySource.getParallelism());
        mySource.print();
        env.execute("");
    }
    public static class MySource2 implements ParallelSourceFunction<String>{
        @Override
        public void run(SourceContext<String> sourceContext) throws Exception {
            sourceContext.collect("MySource");
        }
        @Override
        public void cancel() {}
    }

输出结果;

MySource2创建的DataStream并行度为:8
1> MySource
3> MySource
8> MySource
6> MySource
2> MySource
5> MySource
4> MySource
7> MySource

6.2 实现RichParallelSourceFunction

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port",8082);
        StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        DataStreamSource<String> mySource = env.addSource(new MySource3());
        System.out.println("MySource3创建的DataStream并行度为:"+mySource.getParallelism());
        mySource.print();
        env.execute("");
    }
    //Rich系列方法执行顺序:
    //1.调用MySource的构造方法
    //2.调用open方法仅调用一次
    //3.调用run方法开始产生数据
    //4.调用cancel方法停止run方法
    //5.调用close方法释放资源
    public static class MySource3 extends RichParallelSourceFunction<String> {
        private boolean flag = true;
        @Override
        public void open(Configuration parameters) throws Exception {
            super.open(parameters);
            System.out.println("SubTask:"+getRuntimeContext().getIndexOfThisSubtask()+" Open MySource!");
        }
        @Override
        public void run(SourceContext<String> sourceContext) throws Exception {
            while (flag){
                sourceContext.collect(UUID.randomUUID().toString());
                Thread.sleep(20000);
            }
        }
        @Override
        public void cancel() {
            flag = false;
            System.out.println("SubTask:"+getRuntimeContext().getIndexOfThisSubtask()+" Cancel MySource!");
        }
        @Override
        public void close() throws Exception {
            super.close();
            System.out.println("SubTask:"+getRuntimeContext().getIndexOfThisSubtask()+" Close MySource!");
        }
    }

输出结果:

MySource3创建的DataStream并行度为:8
SubTask:2 Open MySource!
SubTask:4 Open MySource!
SubTask:0 Open MySource!
SubTask:7 Open MySource!
SubTask:1 Open MySource!
SubTask:6 Open MySource!
SubTask:3 Open MySource!
SubTask:5 Open MySource!
5> ea3fd0eb-ba53-44be-b167-2d904c985014
7> 74bb7a0e-8715-424a-aed4-0a4c98ba4e1c
3> d7faf33e-0a38-4c5f-8644-9dd36c46548e
6> 3bb4933b-66a8-4c04-99bf-5e5ecc943d4e
2> 1532c2ba-5904-4af2-869b-27ce5e9a36e6
1> 5a374fc4-0c16-43b5-8e05-ffe6704d47ed
8> 3f3f0375-e0d3-499f-9ac5-754403f12bb5
4> 6884d443-1c02-40e7-878e-dbfa1677a86d
SubTask:0 Cancel MySource!
SubTask:1 Cancel MySource!
SubTask:2 Cancel MySource!
SubTask:4 Cancel MySource!
SubTask:3 Cancel MySource!
SubTask:5 Cancel MySource!
SubTask:6 Cancel MySource!
SubTask:7 Cancel MySource!
SubTask:6 Close MySource!
SubTask:5 Close MySource!
SubTask:3 Close MySource!
SubTask:0 Close MySource!
SubTask:7 Close MySource!
SubTask:4 Close MySource!
SubTask:2 Close MySource!
SubTask:1 Close MySource!

你可能感兴趣的:(Flink,实时大数据,flink,java)