Flink学习笔记(一)

目录

Flink安装

  Standalone模式

  Yarn模式

    Session-cluster 模式

    Per-Job-Cluster 模式

Flink 流处理API

  执行环境-Environment

  读取数据-Source

  数据转换-Transform

  支持的数据类型

  富函数(Rich Functions)

  数据输出-Sink


以下笔记基于对尚硅谷Java版Flink(2020版)的学习,Flink版本1.10

Flink安装


  Standalone模式


    1.解压程序包
    2.修改配置文件 conf/flink-conf.yaml

      jobmanager.rpc.address         作业管理器访问地址
      taskmanager.numberOfTaskSlots  每个任务管理器任务插槽数量,一般设置为CPU核心数
      parallelism.default            默认并行数


    3.修改配置文件 conf/slaves ,填入其他从动主机名
    4.文件分发给其他从动主机
    5.启动Flink集群

./start-cluster.sh


      访问http://localhost:8081可以对flink集群和任务进行监控管理
    6.提交任务
      浏览器中提交
        在Submit New Job页面上传jar包,填写下面的信息:
          入口类
          并行数
          程序参数
      命令行提交

./flink run -c com.aiccfly.wc.StreamWordCount –p 3 StreamWordCount.jar --host lcoalhost –port 7777
./flink list
./flink list -a
./flink cancel 任务ID
  立即调用作业算子的 cancel() 方法,以尽快取消它们。如果算子在接到 cancel() 调用后没有停止,Flink 将开始定期中断算子线程的执行,直到所有算子停止为止。
./flink stop 任务ID
  更优雅的停止正在运行流作业的方式。stop() 仅适用于 source 实现了StoppableFunction 接口的作业。当用户请求停止作业时,作业的所有 source 都将接收 stop() 方法调用。直到所有 source 正常关闭时,作业才会正常结束。这种方式,使作业正常处理完所有作业。


  Yarn模式


    Session-cluster 模式


      Session-Cluster模式需要先启动集群,然后再提交作业,接着会向yarn申请一块空间后,资源永远保持不变。如果资源满了,下一个作业就无法提交,只能等到yarn中的其中一个作业执行完成后,释放了资源,下个作业才会正常提交。
      所有作业共享Dispatcher和ResourceManager;共享资源;适合规模小执行时间短的作业。
      在yarn中初始化一个flink集群,开辟指定的资源,以后提交任务都向这里提交。这个flink集群会常驻在yarn集群中,除非手工停止。
        1) 启动hadoop集群
        2) 启动yarn-session

./yarn-session.sh -n 2 -s 2 -jm 1024 -tm 1024 -nm test -d
其中:
  -n(--container):TaskManager的数量。新版本不再使用,可以动态分配。
  -s(--slots):    每个TaskManager的slot数量,默认一个slot一个core,默认每个taskmanager的slot的个数为1,有时可以多一些taskmanager,做冗余。
  -jm:JobManager的内存(单位MB)。
  -tm:每个taskmanager的内存(单位MB)。
  -nm:yarn 的appName(现在yarn的ui上的名字)。
  -d:后台执行。


        3) 执行任务

./flink run -c com.aiccfly.wc.StreamWordCount –p 3 StreamWordCount.jar --host lcoalhost –port 7777


        4) 去yarn控制台查看任务状态
        5) 取消yarn-session

yarn application --kill application_1577588252906_0001

    Per-Job-Cluster 模式


      一个Job会对应一个集群,每提交一个作业会根据自身的情况,都会单独向yarn申请资源,直到作业执行完成,一个作业的失败与否并不会影响下一个作业的正常提交和运行。独享Dispatcher和ResourceManager,按需接受资源申请;适合规模大长时间运行的作业。
      每次提交都会创建一个新的flink集群,任务之间互相独立,互不影响,方便管理。任务执行完成之后创建的集群也会消失。
        1) 启动hadoop集群
        2) 不启动yarn-session,直接执行job

./flink run –m yarn-cluster -c com.aiccfly.wc.StreamWordCount FlinkTutorial-1.0-SNAPSHOT-jar-with-dependencies.jar --host lcoalhost –port 7777
   –m yarn-cluster为固定写法

Flink 流处理API


  Environment   ->   Source    ->  Transform       -> Sink


  执行环境-Environment


    getExecutionEnvironment 创建一个执行环境

// 批处理
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// 流处理
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    createLocalEnvironment 获取本地执行环境,需要在调用时指定默认的并行度

StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment(1);

    createRemoteEnvironment
      获取集群执行环境,将Jar提交到远程服务器。需要在调用时指定JobManager的IP和端口号,并指定要在集群中运行的Jar包

StreamExecutionEnvironment env = StreamExecutionEnvironment.createRemoteEnvironment("jobmanage-hostname", 6123,"YOURPATH//wordcount.jar");

  读取数据-Source

// 从集合读取数据
env.fromCollection(Collection<OUT> data)
env.fromElements(OUT... data)

// 从文件读取数据
env.readTextFile(String filePath)
env.readFile(FileInputFormat<OUT> inputFormat, String filePath)

// 从Socket读取数据
env.socketTextStream(String hostname, int port)
env.socketTextStream(String hostname, int port, String delimiter, long maxRetry)

// 从Kafka获取数据
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "hadoop102:9092");
properties.setProperty("group.id", "consumer-group");
properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.setProperty("auto.offset.reset", "latest");
DataStreamSource<String> stream = env.addSource(new FlinkKafkaConsumer<String>(
        "sensor",
        new SimpleStringSchema(),
        properties
));

// 自定义Source
env.addSource(SourceFunction<OUT> function)
  // 继承SoruceFunction,实现run和cancel方法,run方法里通过ctx.collect(T element)对外输出

  数据转换-Transform

// 一进一出
dataStream.map(MapFunction<T,R> mapper)
  // 实现MapFunction接口,在map方法里返回新的内容

// 一进多出
dataStream.flatMap(FlatMapFunction<T,R> flatMapper)
  // 实现FlatMapFunction接口,在flatMap方法里通过out.collect(T record)添加输出

// 条件过滤
dataStream.filter(FilterFunction<T> filter)
  // 实现FilterFunction接口,在filter方法里通过返回True/False表示是否输出

// 流操作的分组,返回KeyedStream<T,Tuple>,会造成数据重分区
dataStream.keyBy(int... fields)
  // 流数据为元组的时候,可以使用0开始的位置
dataStream.keyBy(String... fields)
dataStream.keyBy(KeySelector<T,K> key)

// 滚动聚合算子(Rolling Aggregation)
keyedStream.sum(int positionToSum)
keyedStream.sum(String field)
keyedStream.max(int positionToMax)
keyedStream.max(String field)
keyedStream.min(int positionToMin)
keyedStream.min(String field)
  // 指定字段以外的部分,取第一条记录的信息
keyedStream.maxBy(int positionToMax)
keyedStream.maxBy(String field)
keyedStream.minBy(int positionToMin)
keyedStream.minBy(String field)
  // 指定字段以外的部分,取最大/最小记录的信息

// Reduce,有状态一进一出
keyedStream.reduce(ReduceFunction<T> reducer)
  // 实现ReduceFunction接口,在reduce方法里参数1为状态行,参数2为新数据,返回值为输出

// Split 和 Select 分流操作,split为数据打标签,返回SplitStream,select选择数据,已经Deprecated
dataStream.split(OutputSelector<T> outputSelector)
  // 实现OutputSelector接口,在select方法里参数为新数据,返回值为数据标签迭代器
splitStream.select(String... outputNames)

// Connect和 CoMap 合流
// 连接两个保持他们类型的数据流,两个数据流被Connect之后,只是被放在了同一个流中,内部依然保持各自的数据和形式不发生任何变化,两个流相互独立
dataStream.connect(DataStream<R> dataStream)
// 变换成统一类型的流
connectedStreams.map(CoMapFunction<IN1,IN2,R> coMapper)
  // 实现CoMapFunction接口,在map1和map2方法里分别处理两种类型的数据返回对应的新类型的内容
connectedStreams.flatMap(CoFlatMapFunction<IN1,IN2,R> coFlatMapper)
  // 实现CoFlatMapFunction接口,在flatMap1和flatMap2方法里分别处理两种类型的数据通过out.collect(T record)添加输出

// Union合流,类型必须是一样
dataStream.union(DataStream<T>... streams)

    DataStream  -> map/flatMap/filter/union   ->  DataStream
    DataStream  -> keyBy    ->  KeyedStream   ->  sum/max/min/Reduce  ->   DataStream
    DataStream  -> split    ->  SplitStream   ->  select              ->   DataStream
    DataStream  -> connect  ->  ConnectedStreams  ->  map/flatMap     ->   DataStream

  支持的数据类型


    所有的Java和Scala基础数据类型,Int, Double, Long, String, …
    Java和Scala元组(Tuples)
    Scala样例类(case classes)
    Java简单对象(POJOs)
    其它(Arrays, Lists, Maps, Enums, 等等)

  富函数(Rich Functions)


    富函数是DataStream API提供的一个函数类的接口,所有Flink函数类都有其Rich版本。它与常规函数的不同在于,可以获取运行环境的上下文,并拥有一些生命周期方法,所以可以实现更复杂的功能。
      RichMapFunction
      RichFlatMapFunction
      RichFilterFunction
      …
    Rich Function有一个生命周期的概念。典型的生命周期方法有:
      open()方法是rich function的初始化方法,当一个算子例如map或者filter被调用之前open()会被调用。
      close()方法是生命周期中的最后一个调用的方法,做一些清理工作。
      getRuntimeContext()方法提供了函数的RuntimeContext的一些信息,例如函数执行的并行度,任务的名字,以及state状态

  数据输出-Sink

// 添加输出
dataStream.addSink(SinkFunction<T> sinkFunction)

// 输出到Kafka
Properties properties = new Properties();
properties.put("bootstrap.servers", "hadoop102:9092");
dataStream.addSink(new FlinkKafkaProducer<String>("clicks", new SimpleStringSchema(), properties);

// 输出到Redis
FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("hadoop102").build();
dataStream.addSink(new RedisSink<Event>(conf, new MyRedisMapper()));
public static class MyRedisMapper implements RedisMapper<Event> {
    @Override
    public RedisCommandDescription getCommandDescription() {
        return new RedisCommandDescription(RedisCommand.HSET, "clicks");
    }

    @Override
    public String getKeyFromData(Event data) {
        return data.user;
    }

    @Override
    public String getValueFromData(Event data) {
        return data.url;
    }
}

// 输出到Elasticsearch
ArrayList<HttpHost> httpHosts = new ArrayList<>();
httpHosts.add(new HttpHost("hadoop102", 9200, "http"));
ElasticsearchSinkFunction<Event> elasticsearchSinkFunction = new ElasticsearchSinkFunction<Event>() {
    @Override
    public void process(Event element, RuntimeContext ctx, RequestIndexer indexer) {
        HashMap<String, String> data = new HashMap<>();
        data.put(element.user, element.url);

        IndexRequest request = Requests.indexRequest()
                .index("clicks")
                .type("type")    // Es 6 必须定义 type
                .source(data);

        indexer.add(request);
    }
};
dataStream.addSink(new ElasticsearchSink.Builder<Event>(httpHosts, elasticsearchSinkFunction).build());

// 自定义输出
dataStream.addSink(SinkFunction<T> sinkFunction)
  // 可以实现一个SinkFunction接口或者继承一个RichSinkFunction类,在invoke方法中做数据输出


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值