一、KafkaSource
在流式处理过程中,Kafka 和 Flink 的整合是许多公司所使用的架构。而 Flink 和 Kafka 的整合也非常友好,代码非常简单,实际开发中使用较多
package cn.kgc.source
import java.util.Properties
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer
import org.apache.kafka.clients.consumer.ConsumerConfig
class KafkaSource {
def main(args: Array[String]): Unit = {
//创建环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
//Kafka消费者配置信息,可以使用ConsumerConfig
val props = new Properties()
props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"master:9092")
props.setProperty(ConsumerConfig.GROUP_ID_CONFIG,"test1")
//接收数据 Source
val inputStream = env.addSource(new FlinkKafkaConsumer[String]("test", new SimpleStringSchema(), props))
//结果输出
inputStream.print()
//执行程序
env.execute()
}
}
二、单线程自定义 Source
2.1 SourceFunction
package cn.kgc.source
import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala._
import scala.util.Random
object MySource {
def main(args: Array[String]): Unit = {
//创建环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
//读取数据 Source
val inputStream = env.addSource(new MySourceFunc)
//结果输出
inputStream.print()
//执行程序
env.execute()
}
}
//创建一个名为Student的样例类
case class Student(stuId:Int,stuName:String,stuAge:Int,score:Int)
//创建一个继承SourceFunction的单线程自定义Source,类型为Student
class MysourceFunc extends SourceFunction[Student]{
var flag:Boolean = true
//重写run方法
override def run(sourceContext: SourceFunction.SourceContext[Student]): Unit = {
while (flag){
//线程休眠500毫秒
Thread.sleep(500)
val random = new Random().nextInt(10)
//数据通过上下文中collect方法将数据发送出去
sourceContext.collect(Student(random,"jack-0"+random,20+random,90+random))
}
}
//重写cancel方法
override def cancel(): Unit = {
flag = false
}
}
值的注意的是,单线程自定义 Source 在创建环境是并行度只能设置为1
三、多线程自定义Source
以RichParallelSourceFunction并发读取Mysql数据库为例
package cn.kgc.source
import java.sql.{DriverManager, PreparedStatement}
import com.mysql.jdbc.Connection
import org.apache.flink.configuration.Configuration
import org.apache.flink.streaming.api.functions.source.{RichParallelSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.scala._
object MyJDBCSource1 {
def main(args: Array[String]): Unit = {
//创建环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(2)
//接收数据 Source
val inputStream = env.addSource(new MyJDBCSourceFunc)
//结果输出
inputStream.print()
//执行程序
env.execute()
}
}
//自定义样例类
case class Worker(name:String,salary:Long)
//自定义实现并行化接口
class MyJDBCSourceFunc extends RichParallelSourceFunction[Worker]{
var conn:Connection = _
var pst:PreparedStatement = _
var flag:Boolean = true
override def open(parameters: Configuration): Unit = {
conn = DriverManager.getConnection("jdbc:mysql://hadoop101:3306/test?characterEncoding=utf-8&&serverTimezone=UTC&&useSSL=false","root","12345678")
pst = conn.prepareStatement("select * from worker")
}
override def close(): Unit = super.close()
override def run(sourceContext: SourceFunction.SourceContext[Worker]): Unit = {
while (flag){
Thread.sleep(5000)
val resultSet = pst.executeQuery()
while (resultSet.next()){
val name = resultSet.getString(1)
val salary = resultSet.getInt(2)
sourceContext.collect(Worker(name,salary))
}
}
}
override def cancel(): Unit = {
flag = false
}
}
四、补充(富函数(RichXxxFunction)的作用)
“富函数”是DataStream API提供的一个函数类的接口,所有Flink函数类都有其Rich版本。它与常规函数的不同在于,可以获取运行环境的上下文,并拥有一些生命周期方法,所以可以实现更复杂的功能。
Rich Function有一个生命周期的概念。典型的生命周期方法有:
open()方法是rich function的初始化方法,当一个算子例如map或者filter被调用之前open()会被调用。
close()方法是生命周期中的最后一个调用的方法,做一些清理工作。
getRuntimeContext()方法提供了函数的RuntimeContext的一些信息,例如函数执行的并行度,任务的名字,以及state状态