问题 解决:
1、(Constants.A, Constants.B) 是定位到具体配置
2、设置flink全局变量
env.getConfig.setGlobalJobParameters(C)
但是某些算子可能用到非全局变量中的一些配置例如:map、process中open 函数中的配置需要局部配置变量。
3、map和process的联系:
map方法不允许缺少数据,也就是原来多少条数据,处理后依然是多少条数据,只是用来做转换。
本次开发map函数用来将source流中的数据转换成json model 对象
.map(JsonUtil.fromJson[LogModel] _).setParallelism(dealParallelism)
为什么不在map中写逻辑规则,是因为map方法不允许缺少数据,数据不知道什么时候来数据调用map需要吃资源,采用process,可以懒加载???
process中:
events (流元素)
state (容错,一致性,只在Keyed Stream)
timers (事件时间和处理时间, 只在keyed stream)
eg:
.process(new FProcess)
class FProcess extends ProcessFunction[LogModel, (Object, Boolean)] {
//mutable.HashSet可变的hashset
val cmdSet: mutable.HashSet[String] = new mutable.HashSet[String]()
override def open(parameters: Configuration): Unit = {
//配置局部变量
val globConf = getRuntimeContext.getExecutionConfig.getGlobalJobParameters.asInstanceOf[Configuration]
val cmdStr = globConf.getString(Constants.D, "")
val splits = cmdStr.split("\\|")
for (cmd <- splits) {
cmdSet.add(cmd)
}
}
override def processElement(model: LogModel, ctx: ProcessFunction[LogModel, (Object, Boolean)]#Context,
out: Collector[(Object, Boolean)]): Unit = {
val action = model.action
if (action.length > 0) {
breakable {
for (cmd <- cmdSet) {
if (action.contains(cmd)) {
val entity = new E
entity.setCmd()
entity.setSourceIp(model.A)
entity.setUserName(model.B)
entity.setDestinationIp(model.C)
entity.setWarnLevel(4)
out.collect((entity, true))
break()
}
}
}
}
4、
E:RabbitMQ 中该模块的queue,类似kafka中的topic
val stream4A = env.addSource(new RMQSource(connectionConfig, E, false, new SimpleStringSchema()))
5、个人理解:因为某些业务有时间限制,而数据源本身会因为网略等因素出现延迟等现象,采用时间戳得方式判断不够严谨,所以采用封装event采用判断事件发生的时间更加合理。
AssignerWithPeriodicWatermarks 周期性的生成watermark,生成间隔可配置,根据数据的eventTime来更新watermark时间
AssignerWithPunctuatedWatermarks 不会周期性生成watermark,只根据元素的eventTime来更新watermark。
当用EventTime和ProcessTime来计算时,元素本身都是不带时间戳的,只有以IngestionTime计算时才会打上进入系统的时间戳。
以下为AssignerWithPunctuatedWatermarks需要重写得两个方法
override def checkAndGetNextWatermark(lastElement: LogModel, extractedTimestamp: Long): Watermark = {
//设定一个10s的缓冲区
new Watermark(extractedTimestamp - 10000)
}
override def extractTimestamp(element: LogModel, previousElementTimestamp: Long): Long = {
//事件时间
element.logTime
}
无论何时一个特定的事件表明一个新的watermark可能需要被创建,都使用AssignerWithPunctuatedWatermarks来生成。
在这个类中Flink首先调用extractTimestamp(…)来为元素分配一个timestamp,然后立即调用该元素上的checkAndGetNextWatermark(…)方法。
checkAndGetNextWatermark(…)方法传入在extractTimestamp(…)方法中分配的timestamp,并决定是否需要生产watermark。一旦checkAndGetNextWatermark(…)返回一个非空的watermark并且watermark比前一个watermark大的话,这个新的watermark将会被发送。
6、Timestamp和Watermark的关系和区别:
指定时间戳(Assigning Timestamps)
为了使用eventtime,Flink需要知道事件的时间戳,也就是说数据流中的元素需要分配一个事件时间戳。
这个通常是通过抽取或者访问事件中某些字段的时间戳来获取的。
时间戳的分配伴随着水印的生成,告诉系统事件时间中的进度。
这里有两种方式来分配时间戳和生成水印:
1、直接在数据流源中进行
2、通过timestamp assigner和watermark generator生成:在Flink中,timestamp 分配器也定义了用来发射的水印。
注意:timestamp和watermark都是通过从1970年1月1日0时0分0秒到现在的毫秒数来指定的。
有Timestamp和Watermark的源函数(Source Function with Timestamps And Watermarks)
数据流源可以直接为它们产生的数据元素分配timestamp,并且他们也能发送水印。
这样做的话,就没必要再去定义timestamp分配器了,需要注意的是:如果一个timestamp分配器被使用的话,由源提供的任何timestamp和watermark都会被重写。
为了通过源直接为一个元素分配一个timestamp,源需要调用SourceContext中的collectWithTimestamp(…)方法。为了生成watermark,源需要调用emitWa