目录
- 1 自定义的数据源函数_读取
- 1.1 应用场景:
- 1.2 自定义连接器实现
- 1.3 自定义连接器实现注意事项
- 2 SourceFunction和ParallSourceFunction中定义了有两个方法
- 2.1 Run()
- 2.2 Cancel()
- 2.3 代码示例
- 3 自定义函数读取Mysql数据源
- 3.1 代码示例
1 自定义的数据源函数_读取
1.1 应用场景:
我将读取到的kafka的数据和mysql数据进行连接,此时就可以使用自定义的连接器;
1.2 自定义连接器实现
实现自定义的数据源函数读取,Flink为我们提供了两个方法:
- SourceFunction通过实现RichSourceFunction来定义非并行的数据源连接器。
- ParllelSourceFunction通过实现RichParalleSourceFunction来定义能并行的数据源连接器。
1.3 自定义连接器实现注意事项
在使用SourceFunction定义连接器的时候,在上述场景中是有个问题的。
- 由于SourceFunction是非并行的数据连接器,使用kafka连接器如果是并行的话,会导致数据丢失。
- 因为,假如Kafka数据源是3个并发程序,而SourceFunction数据源只有1个,那么它们在连接的时候比然会导致有2个线程中的数据是无法关联的,会导致数据丢失。
解决办法
- 将SourceFunction变为ParllelSourceFunction连接器;
- 同时定义一个全局的并行度: env.setParalllize()即可,又或者kafka连接器和ParllelSourceFunction都定义一个相同的并行度即可。
2 SourceFunction和ParallSourceFunction中定义了有两个方法
(分别是run()方法和cancel()方法)
2.1 Run()
- Run只会被Flink调用一次,且Flink会专门为它而开放一个线程。该线程通常会不断的循环读取或接收数据,然后将他们发出。
2.2 Cancel()
- Cancel会在应用被取消或关闭时调用。且为了关闭过程可以顺利完成,运行再单独线程内的run()方法需要在cancel()方法被调用会立即终止。
2.3 代码示例
class define_dataSource(number:Int) extends SourceFunction[Int]{
var isRunning: Boolean = true
override def run(ctx: SourceFunction.SourceContext[Int]): Unit = {
var cnt = -1;
while (isRunning && cnt < number){
cnt +=1
ctx.collect(cnt)
}
}
override def cancel(): Unit = isRunning = false
}
object 自定义数据源函数 extends App {
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
val streamLocal = StreamExecutionEnvironment.createLocalEnvironment(1)
//获取集群的配置或提交客户端来指定默认并行度
import org.apache.flink.api.scala._ //如果数据是有限的(静态数据集)可以引入这个包
streamLocal.addSource(new define_dataSource(10)).map(x=>x).print()
streamLocal.execute()
}
3 自定义函数读取Mysql数据源
(注意在这这里实现的是RichSourceFunction而非SourceFunction,因为在RichSourceFunction中我们可以重写open方法)
Q:这里有个知识点,即为什么我们要实现open()方法?
A:因为open是富函数中的一个初始方法。它在每个任务首次调用转换方法(如map,flter等算子)前调用一次。open方法通常只用于那些只需要进行一次的设置工作
3.1 代码示例
class jdbc_reader extends RichSourceFunction[(String, Int)] {
private var connect: Connection = _
private var ps: PreparedStatement = _
override def open(parameters: Configuration): Unit = {
super.open(parameters)
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager.getConnection("jdbc:mysql://master:3306", "root", "msb_mk")
ps = connect.prepareStatement("select * from friends.`ceshi`")
}
override def run(ctx: SourceFunction.SourceContext[(String, Int)]): Unit = {
val result = ps.executeQuery()
while (result.next()) {
ctx.collect(result.getString("name"), result.getInt("age"))
}
}
override def cancel(): Unit = {
try {
super.close()
if (connect != null) connect.close()
if (ps != null) ps.close()
} catch {
case e: Exception =>
e.printStackTrace()
}
}
}