1、Flink读取外部数据源的方式
Flink是一个流批一体的分布式计算框架,它不会存储数据,编写Flink计算任务的第一步就是通过连接器去读取外部数据
Flink提供了多种`预定义 data sources` 来读取外部数据,如 文件、目录、Socket、集合、Kafka等外部数据源,另外也是要通过自定义数据源来读取外部数据
2、数据源的类型
Flink 中读取的数据源,根据知否支持切片,分为 非并行数据源 和 并行数据源 两大类
并行数据源 : 可以将数据源拆分成多个 子任务,并行执行( 并行度允许大于1)
非并行数据源 : 不可以将数据源拆分,只能有单独的任务处理数据 (并行度必须1)
我们可以通过 StreamExecutionEnvironment.addSource(SourceFunction) 将一个 source对象 关 联到编写的 flink应用程序中
Flink API中 自带了许多 SourceFunction的实现类
我们也可以 通过实现 SourceFunction接口 来编写 自定义的非并行的source对象
通过实现 ParallelSourceFunction 接口
继承 RichParallelSourceFunction 类 来编写 自定义的并行source对象
3、Flink 中的数据类型(TypeInformation)
Flink 会将外部的数据加载到 DataStreamSource 对象中,加载过程中会将外部的数据的类型转换为 Flink 定义的数据类型
为了方便 数据序列化和反序列化,Flink定义了自己的数据类型系统
4、从集合中读取数据
5、从文件中读取数据
6、从Socket中读取数据
语法说明:
语法:
def socketTextStream(hostname: String, port: Int, delimiter: Char = '\n', maxRetry: Long = 0):
DataStream[String] =
asScalaStream(javaEnv.socketTextStream(hostname, port))
功能:
执行监控,socket中的文本流,按行读取数据(默认分隔符为 \n)
参数:
hostname : socket服务ip
prot : socket服务端口号
Char : 行分隔符
maxRetry : 当 socket服务 停止时,flink程序 重试连接时间(单位为秒)
=0 时,表示 连接不到 socket服务后,立刻停止 flink程序
=-1 时,表示 永远保持重试连接
tips:
scala API 只提供了一种 socketTextStream方法的实现
如果想使用其他参数,需要使用java api
代码示例:
package com.baidu.datastream.source;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
// --------------------------------------------------------------------------------------------
// TODO 从Socket中读取数据
// --------------------------------------------------------------------------------------------
/*
* TODO socketTextStream(hostname: String, port: Int, delimiter: String, maxRetry: Long)
* 功能说明:
* 包含从套接字接收到的字符串的数据流
* 参数说明:
* @hostname : 指定ip
* @port : 指定端口号
* @delimiter : 指定元素分隔符(默认为\n)
* @maxRetry : 指定连接失败时,重试连接的时间间隔(以秒为单位)
* 默认为为0,表示连接失败时,程序立即终止
* 负值时,表示一直重试连接
* */
public class ReadSocket {
public static void main(String[] args) throws Exception {
// 1.获取执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 2.将socket作为数据源(开启socket端口: nc -lk 9999)
env.socketTextStream("localhost", 9999).print();
// 3.触发程序执行
env.execute();
}
}
7、从Kafka中读取数据
6. 从DataGen中读取数据
传送门:从DataGen中读取数据
7. 自定义数据源
7.1 自定义非并行数据源
代码示例:
/*
* TODO 自定义非并行数据源
* 实现步骤:
* 1.实现 SourceFunction接口
* 2.实现 run方法
* 调用 collect方法 发送数据
* 3.实现 cancel方法
* 注意事项:
* 1.接口的泛型为 数据源的数据类型
* */
class CustomNonParallelSource extends SourceFunction[String] {
// 标志位,用来控制循环的退出
var isRunning = true
override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
val list = List("刘备1", "关羽2", "张飞3", "赵云4", "马超5")
while (isRunning) {
// 调用 collect 方法向下游发送数据
list.foreach(
e => {
ctx.collect(e)
Thread.sleep(1000)
}
)
}
}
// 通过将 isRunning 设置为false,来终止消息的发送
override def cancel(): Unit = isRunning = false
}
/*
* TODO 从 自定义数据源中 读取数据
*
* */
test("从 自定义非并行数据源中 读取数据") {
// 1. 获取流执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 2. 将 自定义数据源 作为数据源
val ds: DataStream[String] = env.addSource(new CustomNonParallelSource).setParallelism(1)
// 3. 打印DataStream
ds.print().setParallelism(1)
// 4. 出发程序执行
env.execute()
}
执行结果:
7.2 自定义并行数据源
代码示例:
/*
* TODO 自定义并行数据源
* 实现步骤:
* 1.实现 ParallelSourceFunction接口 或者 继承RichParallelSourceFunction
* 2.实现 run方法
* 调用 collect方法 发送数据
* 3.实现 cancel方法
* 注意事项:
* 1.接口的泛型为 数据源的数据类型
* */
class CustomParallelSource extends RichParallelSourceFunction[String] {
// 标志位,用来控制循环的退出
var isRunning = true
override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
val list = List("刘备1", "关羽2", "张飞3", "赵云4", "马超5")
while (isRunning) {
// 调用 collect 方法向下游发送数据
// 调用 collect 方法向下游发送数据
list.foreach(
e => {
ctx.collect(e)
Thread.sleep(1000)
}
)
}
}
// 通过将 isRunning 设置为false,来终止消息的发送
override def cancel(): Unit = isRunning = false
}
test("从 自定义并行数据源中 读取数据") {
// 1. 获取流执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 2. 将 自定义数据源 作为数据源
val ds: DataStream[String] = env.addSource(new CustomParallelSource).setParallelism(4)
// 3. 打印DataStream
ds.print().setParallelism(1)
// 4. 出发程序执行
env.execute()
}
执行结果:
7.3 使用自定义数据源读取MySQL
传送门:使用自定义源算子读取MySQL