代码地址

一、Source

输入 Controlling Latency(控制延迟)
默认情况下,流中的元素并不会一个一个的在网络中传输(这会导致不必要的网络流量消耗) ,而是缓存起来,缓存 的大小可以在Flink的配置文件、ExecutionEnvironment、或者某个算子上进行配置(默认为100ms)。

  • 好处:提高吞吐
  • 坏处:增加了延迟
  • 为了最大吞吐量,可以设置 setBufferTimeout(-1),这会移除 timeout 机制,缓存中的数据一满就会被发送 。
  • 为了最小的延迟,可以将超时设置为 0 ,但是会有一些性能的损耗。

1.1、flink内置数据源

1、基于文件

env.readTextFile("file://path")
env.readFile(inputFormat, "file://path");

2、基于socket数据源

env.socketTextStream("localhost", 6666, '\n')

3. 基于Collection 

import org.apache.flink.api.scala._
env.fromCollection(List(1,2,3))
env.fromElements(1,2,3)
env.generateSequence(0, 1000)

1.2、自定义数据源

1、实现SourceFunction

SourceFunction 是非并行的,所以不能指定并行度,即不能用setParallelism(num) 算子;

SocketTextStreamFunction就是实现的SourceFunction ,源码中也有详细的用例;

import org.apache.flink.api.common.functions.FlatMapFunction
import org.apache.flink.configuration.{ConfigConstants, Configuration}
import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.util.Collector
// 需要加上这一行隐式转换 否则在调用flatmap方法的时候会报错
import org.apache.flink.api.scala._ // SourceFunction 是非并行的,所以不能指定并行度 即 不能 用 setParallelism(num) 算子
class MySourceFunction extends SourceFunction[String]{
var num: Long = 0
var isCancel: Boolean = true //在cancel的时候被执行,传递变量用于控制run方法中的执行
override def cancel(): Unit = {
println("cancel")
isCancel = false
} // 调用run 方法向下游产生数据
override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
while (isCancel){
ctx.collect(s"xxd\t${num}")
Thread.sleep(1000)
num += 1
}
} } object SourceFunctionWordCount{
def main(args: Array[String]): Unit = {
val logPath: String = "/tmp/logs/flink_log"
var conf: Configuration = new Configuration()
// 开启spark-webui
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
//配置webui的日志文件
conf.setString("web.log.path", logPath)
// 配置 taskManager 的日志文件,否则打印日志到控制台
conf.setString(ConfigConstants.TASK_MANAGER_LOG_PATH_KEY,logPath)
// 配置有多少个solor
conf.setString("taskmanager.numberOfTaskSlots","3")
// 获取本地运行环境
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
// 设置延时时间
env.setBufferTimeout(3000)
// 定义数据源
val sourceDataStream: DataStream[String] = env.addSource(new MySourceFunction)
// 增加 setParallelism就会报错
// val sourceDataStream: DataStream[String] = env.addSource(new MySourceFunction).setParallelism(2)
// 定义 operators,作用是解析数据,分组,窗口化,并且聚合就SUM
val wordCountData: DataStream[(String, Int)] = sourceDataStream.flatMap(new FlatMapFunction[String, (String, Int)] {
override def flatMap(value: String, out: Collector[(String, Int)]): Unit = {
val strings: Array[String] = value.split(" ")
for (f <- strings) {
out.collect((f, 1))
}
}
}).setParallelism(2).keyBy(_._1).sum(1).setParallelism(2)
// 定义sink打印输出
wordCountData.print().setParallelism(2)
// 打印任务执行计划
println(env.getExecutionPlan)
// 运行
env.execute("Socket Window WordCount") }
}

2、实现ParallelSourceFunction

ParallelSourceFunction是并行化的source所以能指定并行度

import org.apache.flink.api.common.functions.FlatMapFunction
import org.apache.flink.configuration.{ConfigConstants, Configuration}
import org.apache.flink.streaming.api.functions.source.{ParallelSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.util.Collector
import org.apache.flink.api.scala._
//ParallelSourceFunction是并行化的source所以能指定并行度
class MyParallelSource extends ParallelSourceFunction[String] {
var num = 0
var isCancel = true override def cancel(): Unit = {
println("cancel")
isCancel = false
} override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
while (isCancel) {
ctx.collect(s"xxd\t${num}")
Thread.sleep(1000)
num += 1
}
}
} object ParallelSourceWordCount {
def main(args: Array[String]): Unit = {
val logPath: String = "/tmp/logs/flink_log"
var conf: Configuration = new Configuration()
// 开启spark-webui
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
//配置webui的日志文件
conf.setString("web.log.path", logPath)
// 配置 taskManager 的日志文件,否则打印日志到控制台
conf.setString(ConfigConstants.TASK_MANAGER_LOG_PATH_KEY, logPath)
// 配置有多少个solor
conf.setString("taskmanager.numberOfTaskSlots", "8")
// 获取本地运行环境
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
// 定义数据源
val sourceDataStream: DataStream[String] = env.addSource(new MyParallelSource).setParallelism(4)
// 定义 operators,作用是解析数据,分组,窗口化,并且聚合就SUM
val wordCountData: DataStream[(String, Int)] = sourceDataStream.flatMap(new FlatMapFunction[String, (String, Int)] {
override def flatMap(value: String, out: Collector[(String, Int)]): Unit = {
val strings: Array[String] = value.split(" ")
for (f <- strings) {
out.collect((f, 1))
}
}
}).setParallelism(2).keyBy(_._1).sum(1).setParallelism(2)
// 定义sink打印输出
wordCountData.print().setParallelism(2)
// 打印任务执行计划
println(env.getExecutionPlan)
// 运行
env.execute("Socket Window WordCount") }
}

3、继承RichParallelSourceFunction

RichParallelSourceFunction不仅实现了ParallelSourceFunction,还继承了AbstractRichFunction

所以RichParallelSourceFunction不仅能够并行化,还比ParallelSourceFunction增加了open和close方法、getRuntimeContext

import org.apache.flink.api.common.functions.FlatMapFunction
import org.apache.flink.configuration.{ConfigConstants, Configuration}
import org.apache.flink.streaming.api.functions.source.{RichParallelSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.util.Collector
import org.apache.flink.api.scala._ //RichParallelSourceFunction不但能并行化
//还比ParallelSourceFunction增加了open和close方法、getRuntimeContext
class MyRichParallelSource extends RichParallelSourceFunction[String]{
var num = 0
var isCancel = true
//初始化 在source开启的时候执行一次,比如可以在这里开启mysql的连接
override def open(parameters: Configuration): Unit = {
println("open")
num = 100
}
//在source关闭的时候执行一次
//比如mysql连接用完了,给还回连接池
override def close(): Unit = {
while (isMysql){
Thread.sleep(1000)
println("close sleep")
}
println("close")
num = 0
} //在输出的时候被执行,传递变量用于控制run方法中的执行
//这个是被手动触发,在执行完cancel之后,会再执行close
override def cancel(): Unit = {
println("cancel")
isCancel = false
} //调用run方法向下游产生数据
//手动cancel之后,不会等待run方法中处理结束而是强制执行close方法
//这样就可能导致run方法中正在使用的连接被close了
//所以此时需要加一个处理完成标识,用于判断是否可以进行close
var isMysql = false
override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
import scala.util.control.Breaks._
breakable{
while (isCancel){
println(getRuntimeContext.getIndexOfThisSubtask) // 获取执行的taskid
ctx.collect(s"xxd\t${num}")
Thread.sleep(2000)
num += 1
if (num > 1200){
break()
}
}
}
isMysql = true
} } object RichParallelSourceWordCount{
def main(args: Array[String]): Unit = {
val logPath: String = "/tmp/logs/flink_log"
var conf: Configuration = new Configuration()
// 开启spark-webui
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
//配置webui的日志文件
conf.setString("web.log.path", logPath)
// 配置 taskManager 的日志文件,否则打印日志到控制台
conf.setString(ConfigConstants.TASK_MANAGER_LOG_PATH_KEY,logPath)
// 配置有多少个solor
conf.setString("taskmanager.numberOfTaskSlots","8")
// 获取本地运行环境
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
// 定义数据源
val sourceDataStream: DataStream[String] = env.addSource(new MyRichParallelSource).setParallelism(4)
// 定义 operators,作用是解析数据,分组,窗口化,并且聚合就SUM
val wordCountData: DataStream[(String, Int)] = sourceDataStream.flatMap(new FlatMapFunction[String, (String, Int)] {
override def flatMap(value: String, out: Collector[(String, Int)]): Unit = {
val strings: Array[String] = value.split(" ")
for (f <- strings) {
out.collect((f, 1))
}
}
}).setParallelism(2).keyBy(_._1).sum(1).setParallelism(2)
// 定义sink打印输出
wordCountData.slotSharingGroup("xxd").print().setParallelism(2)
// 打印任务执行计划
println(env.getExecutionPlan)
// 运行
env.execute("Socket Window WordCount") }
}

二、sink

2.1、内置数据输出源

1、基于文件

#使用TextOutputFormat
stream.writeAsText("/path/to/file")
#使用CsvOutputFormat
stream.writeAsCsv("/path/to/file")

2、基于socket

stream.writeToSocket(host, port, SerializationSchema)

3、基于标准/错误输出

#注: 线上应用杜绝使用,采用抽样打印或者日志的方式
stream.print()
stream.printToErr()

2.2、自定义输出源

1、实现SinkFunction

import org.apache.flink.configuration.{ConfigConstants, Configuration}
import org.apache.flink.streaming.api.functions.sink.SinkFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.api.scala._ class MySinkFunction extends SinkFunction[(String, Int)] {
override def invoke(value: (String, Int), context: SinkFunction.Context[_]): Unit = {
println(s"value:${value}," +
s"processTime:${context.currentProcessingTime()}," +
s"waterMark:${context.currentWatermark()}")
}
} object SinkFunctionWordCount {
def main(args: Array[String]): Unit = {
val logPath: String = "/tmp/logs/flink_log"
var conf: Configuration = new Configuration()
// 开启spark-webui
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
//配置webui的日志文件
conf.setString("web.log.path", logPath)
// 配置 taskManager 的日志文件,否则打印日志到控制台
conf.setString(ConfigConstants.TASK_MANAGER_LOG_PATH_KEY, logPath)
// 配置有多少个solor
conf.setString("taskmanager.numberOfTaskSlots", "8")
// 获取本地运行环境
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
// 定义数据源
val input = env.fromElements("xxd xxd xxd")
val output: DataStream[(String, Int)] = input.flatMap(f => f.split(" ")).map((_, 1))
// 使用自定义的sink
output.addSink(new MySinkFunction)
env.execute() }
}

2、继承RichSinkFunction

package com.xxd.flink.sink
import org.apache.flink.configuration.{ConfigConstants, Configuration}
import org.apache.flink.streaming.api.functions.sink.{RichSinkFunction, SinkFunction}
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.api.scala._ class MyRichSinkFunction extends RichSinkFunction[(String, Int)]{
//在Sink开启的时候执行一次,比如可以在这里开启mysql的连接
override def open(parameters: Configuration): Unit = {
println("open")
} //在Sink关闭的时候执行一次
//比如mysql连接用完了,给还回连接池
override def close(): Unit = {
println("close")
} //调用invoke方法,执行数据的输出
override def invoke(value: (String, Int), context: SinkFunction.Context[_]): Unit = {
//在rich方法中可以使用getRuntimeContext方法得到比如广播变量和累加器
//getRuntimeContext.getBroadcastVariable("")
println(s"value:${value}," +
s"processTime:${context.currentProcessingTime()}," +
s"waterMark:${context.currentWatermark()}")
}
} object RichSinkFunctionWordCount {
def main(args: Array[String]): Unit = {
val logPath: String = "/tmp/logs/flink_log"
var conf: Configuration = new Configuration()
// 开启spark-webui
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
//配置webui的日志文件
conf.setString("web.log.path", logPath)
// 配置 taskManager 的日志文件,否则打印日志到控制台
conf.setString(ConfigConstants.TASK_MANAGER_LOG_PATH_KEY,logPath)
// 配置有多少个solor
conf.setString("taskmanager.numberOfTaskSlots","8")
// 获取本地运行环境
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
// 定义数据源
val input = env.fromElements("xxd xxd xxd")
val output: DataStream[(String, Int)] = input.flatMap(f => f.split(" ")).map((_, 1))
// 使用自定义的sink
output.addSink(new MyRichSinkFunction)
env.execute()
}
}

3、使用自定义OutputFormat,然后使用stream.writeUsingOutputFormat("自定义outputFormat") 

import org.apache.flink.api.common.io.OutputFormat
import org.apache.flink.configuration.{ConfigConstants, Configuration}
import org.apache.flink.api.scala._
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment} class MyOutPutFormat extends OutputFormat[(String, Int)]{
//配置outputformat
override def configure(parameters: Configuration): Unit = {
println("configure")
}
//在Sink开启的时候执行一次,比如可以在这里开启mysql的连接
override def open(taskNumber: Int, numTasks: Int): Unit = {
//taskNumber第几个tak,numTasks总任务数
println(s"taskNumber:${taskNumber},numTasks:${numTasks}")
}
//调用writeRecord方法,执行数据的输出
override def writeRecord(record: (String,Int)): Unit = {
println(record)
}
//在Sink关闭的时候执行一次
//比如mysql连接用完了,给还回连接池
override def close(): Unit = {
println("close")
} } object OutputFormatWordCount {
def main(args: Array[String]): Unit = {
val logPath: String = "/tmp/logs/flink_log"
var conf: Configuration = new Configuration()
// 开启spark-webui
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
//配置webui的日志文件
conf.setString("web.log.path", logPath)
// 配置 taskManager 的日志文件,否则打印日志到控制台
conf.setString(ConfigConstants.TASK_MANAGER_LOG_PATH_KEY,logPath)
// 配置有多少个solor
conf.setString("taskmanager.numberOfTaskSlots","8")
// 获取本地运行环境
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
// 定义数据源
val input = env.fromElements("xxd xxd xxd")
val output: DataStream[(String, Int)] = input.flatMap(f => f.split(" ")).map((_,1))
//使用自定义的outputFormat
output.writeUsingOutputFormat(new MyOutPutFormat)
env.execute()
}
}
 

4、flink自定义source、sink的更多相关文章

  1. Flink 自定义source和sink,获取kafka的key,输出指定key

    --------20190905更新------- 沙雕了,可以用  JSONKeyValueDeserializationSchema,接收ObjectNode的数据,如果有key,会放在Objec ...

  2. 【翻译】Flink Table Api & SQL — 自定义 Source & Sink

    本文翻译自官网: User-defined Sources & Sinks  https://ci.apache.org/projects/flink/flink-docs-release-1 ...

  3. 《从0到1学习Flink》—— 如何自定义 Data Sink ?

    前言 前篇文章 <从0到1学习Flink>-- Data Sink 介绍 介绍了 Flink Data Sink,也介绍了 Flink 自带的 Sink,那么如何自定义自己的 Sink 呢 ...

  4. Flink 从 0 到 1 学习 —— 如何自定义 Data Sink ?

    前言 前篇文章 <从0到1学习Flink>-- Data Sink 介绍 介绍了 Flink Data Sink,也介绍了 Flink 自带的 Sink,那么如何自定义自己的 Sink 呢 ...

  5. Flink自定义Sink

    Flink自定义Sink Flink 自定义Sink,把socket数据流数据转换成对象写入到mysql存储. #创建Student类 public class Student { private i ...

  6. Flume自定义Source、Sink和Interceptor(简单功能实现)

    1.Event event是flume传输的最小对象,从source获取数据后会先封装成event,然后将event发送到channel,sink从channel拿event消费. event由头he ...

  7. 《从0到1学习Flink》—— Data Sink 介绍

    前言 再上一篇文章中 <从0到1学习Flink>-- Data Source 介绍 讲解了 Flink Data Source ,那么这里就来讲讲 Flink Data Sink 吧. 首 ...

  8. Flink 之 Data Sink

    首先 Sink 的中文释义为: 下沉; 下陷; 沉没; 使下沉; 使沉没; 倒下; 坐下; 所以,对应 Data sink 意思有点把数据存储下来(落库)的意思: Source  数据源  ---- ...

  9. flink02------1.自定义source 2. StreamingSink 3 Time 4窗口 5 watermark

    1.自定义sink 在flink中,sink负责最终数据的输出.使用DataStream实例中的addSink方法,传入自定义的sink类 定义一个printSink(),使得其打印显示的是真正的ta ...

随机推荐

  1. Mysql数据库主键,外键,索引概述

    主键: 主键是数据表的唯一索引,比如学生表里有学号和姓名,姓名可能有重名的,但学号确是唯一的,你要从学生表中搜索一条纪录如查找一个人,就只能根据学号去查找,这才能找出唯一的一个,这就是主键;如:id ...

  2. LVS 负载均衡 三种工作模式 十种调度算法

    原文链接:https://blog.csdn.net/weixin_40470303/article/details/80541639 一.LVS简介 LVS(Linux Virtual Server ...

  3. SpringBoot中遇到的一些问题

    1.JQuery和bootstrap报404的问题 在html页面导入的js和css的时候,不要加static这级目录,直接跳过即可,例如 导入的时候不需要加static目录,直接导入js/和css/ ...

  4. 汇编学习-三(VB)

    闲来无事做了一下160个crackme,因为是VB程序,所以将得到的一点心得记录如下(OD加载注释) push eax ; Andréna.004018A8 call dword ptr ds:[&l ...

  5. 《快速认识 Three.js 》

    此文仅作备份之用,为了更好的阅读体验,建议访问原文链接:<Three.js - 走进3D的奇妙世界.> ,感谢原作者的好文.

  6. 部署并测试动态WSGI站点

                                                            部署并测试动态WSGI站点 5.1问题 本例要求为站点webapp0.example.c ...

  7. Golang笔记集

    学习Golang了, 下面分享我的, 还有我收集的Golang的学习资料 我的基础笔记地址: https://github.com/zhuchangwu/go-study-notes 其他参考: Go ...

  8. 使用Cloudflare增强网站

    Cloudflare Cloudflare是美国的一家网络性能和安全公司,近期由于自己域名HTTP证书到期,了解到了Cloudflare,用到了它提供的CDN以及SSL 如何设置CDN 登入Cloud ...

  9. 自动生成四则运算题目(C语言)

    Github项目地址:https://github.com/huihuigo/expgenerator 合作者:马文辉(3118005015).卢力衔(3118005013) 项目简介 1题目:实现一 ...

  10. vue实现首屏加载等待动画 避免首次加载白屏尴尬

    0 直接上效果图 1背景,用户体验良好一直是个重要的问题. 2怎么加到自己项目里面? 复制css html代码到自己的index.html即可 代码链接 源码地址 Vue学习前端群493671066, ...