接上文: 【翻译】The Broadcast State Pattern(广播状态) 

最近尝试了一下Flink 的 Broadcase 功能,在Etl,流表关联场景非常适用:一个流数据量大,一个流数据量小(配置表)需要更新

业务逻辑如下:

  

注: 正常情况广播流只有一个输出源,更新也在这个源里,这里做了个优化:将广播流的输入源改为两部分配置文件和更新topic(原因:flink 读取文件,读完就结束了无法做更新,而每次从kafka获取全量配置数据,涉及到kafka topic数据的删除时间,除非涉及非常长的删除时间,不然每次读取全量也不太方便),这里不使用flink的CacheFile,因为不能更新

具体业务如下:转码三位城市编码为对应城市中文

  1. 自定义输入流,输入三位的城市编码和五位的随机字符串

  2. 广播流读取配置文件和配置文件更新topic

  3. connect两个流,读取配置文件对应的数据解析数据流输入的数据

自定义输入流如下:

class RadomFunction extends SourceFunction[String]{
var flag = true
override def cancel(): Unit = {
flag = false
} override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
while (flag){
for (i <- 0 to 300) {
var nu = i.toString
while (nu.length < 3) {
nu = "0" + nu
}
ctx.collect(nu + "," + StringUtil.getRandomString(5))
Thread.sleep(2000)
}
}
}
}

Etl 代码如下:

import java.io.File
import com.venn.flink.util.{StringUtil}
import com.venn.index.conf.Common
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.api.common.state.MapStateDescriptor
import org.apache.flink.api.common.typeinfo.BasicTypeInfo
import org.apache.flink.api.scala._
import org.apache.flink.runtime.state.filesystem.FsStateBackend
import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction
import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.{CheckpointingMode, TimeCharacteristic}
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer
import org.apache.flink.util.Collector /**
* broadcast
*/
object BroadCastDemo { def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
if ("/".equals(File.separator)) {
val backend = new FsStateBackend(Common.CHECK_POINT_DATA_DIR, true)
env.setStateBackend(backend)
env.enableCheckpointing(10 * 1000, CheckpointingMode.EXACTLY_ONCE)
} else {
env.setMaxParallelism(1)
env.setParallelism(1)
}
// 配置更新流
val configSource = new FlinkKafkaConsumer[String]("broad_cast_demo", new SimpleStringSchema, Common.getProp)
// 配置流的初始化,可以通过读取配置文件实现
var initFilePath = ""
if ("/".equals(File.separator)){
initFilePath = "hdfs:///venn/init_file.txt"
}else{
initFilePath = "D:\\idea_out\\broad_cast.txt"
}
val init = env.readTextFile(initFilePath)
val descriptor = new MapStateDescriptor[String, String]("dynamicConfig", BasicTypeInfo.STRING_TYPE_INFO, BasicTypeInfo.STRING_TYPE_INFO)
val configStream = env.addSource(configSource).union(init).broadcast(descriptor) val input = env.addSource(new RadomFunction)
.connect(configStream)
.process(new BroadcastProcessFunction[String, String, String] {
override def processBroadcastElement(value: String, ctx: BroadcastProcessFunction[String, String, String]#Context, out: Collector[String]): Unit = { println("new config : " + value)
val configMap = ctx.getBroadcastState(descriptor)
// process update configMap,读取配置数据,写入广播状态中
val line = value.split(",")
configMap.put(line(0), line(1))
}
override def processElement(value: String, ctx: BroadcastProcessFunction[String, String, String]#ReadOnlyContext, out: Collector[String]): Unit = {
// use give key, return value
val configMap = ctx.getBroadcastState(descriptor)
// 解析三位城市编码,根据广播状态对应的map,转码为城市对应中文
// println(value)
val line = value.split(",")
val code = line(0)
var va = configMap.get(code)
// 不能转码的数据默认输出 中国(code=xxx)
if ( va == null){
va = "中国(code="+code+")";
}else{
va = va + "(code="+code+")"
}
out.collect(va + "," + line(1))
}
})
input.print() env.execute("BroadCastDemo")
}
}

配置数据如下:

001,邯郸市
002,石家庄
003,保定市
004,张家口
005,承德市
006,唐山市
007,廊坊市
008,沧州市
009,衡水市
010,邢台市

数据源数据如下:

001,bGTqQM
002,sCfdSK
003,RWtLNC
004,qkGita
005,fOemDF
006,KRaUmj
007,MNwKdS
008,RgZDlI
009,QbUyeh

转码后输出如下:

邯郸市(code=001),bGTqQM
石家庄(code=002),sCfdSK
保定市(code=003),RWtLNC
张家口(code=004),qkGita
承德市(code=005),fOemDF
唐山市(code=006),KRaUmj
廊坊市(code=007),MNwKdS
沧州市(code=008),RgZDlI
衡水市(code=009),QbUyeh

执行结果如下:

...
new config : 047,十堰市
new config : 048,随枣市
new config : 049,荆门市
new config : 050,江汉(仙桃)
邯郸市(code=001),ovLKQN
石家庄(code=002),QTgxXn
保定市(code=003),bIPefX
张家口(code=004),XcdHUd
...
宜昌市(code=045),sQRonA
恩施市(code=046),gfipAY
十堰市(code=047),ASPulh
随枣市(code=048),mqurwg
荆门市(code=049),hfTlue
江汉(仙桃)(code=050),EfiXec
中国(code=051),xGuihq # 不能转码数据
中国(code=052),niMlrb
中国(code=053),fHvIpU
中国(code=054),MdqqCb
中国(code=055),CFgNmM
...

广播流数据更新如下:

new config : 150,xxx   # 获取当新配置数据
中国(code=148),fLtwye
中国(code=149),bEJfMP
new config : 151,fff
xxx(code=150),TTIPii # 新配置数据转码数据
fff(code=151),iJSAjJ
中国(code=152),yBvlUZ
new config : 152,ggg

搞定

基于Broadcast 状态的Flink Etl Demo的更多相关文章

  1. Nancy之基于Nancy.Hosting.Self的小Demo

    继昨天的Nancy之基于Nancy.Hosting.Aspnet的小Demo后, 今天来做个基于Nancy.Hosting.Self的小Demo. 关于Self Hosting Nancy,官方文档的 ...

  2. Nancy之基于Self Hosting的补充小Demo

    前面把Hosting Nancy with ASP.NET.Self Hosting Nancy和Hosting Nancy with OWIN 以demo的形式简单描述了一下. 这篇是为Self H ...

  3. 基于纹理的图片检索及demo(未启动)

    基于纹理的图片检索及demo(未启动)

  4. flink ETL数据处理

    Flink ETL 实现数据清洗   一:需求(针对算法产生的日志数据进行清洗拆分) 1. 算法产生的日志数据是嵌套json格式,需要拆分 2.针对算法中的国家字段进行大区转换 3.最后把不同类型的日 ...

  5. ECharts 初识(基于MVC+jQuery+Angularjs实现的Demo)

    一.背景:      我们这行做web开发的,很多时候都需要做数据统计报表,现在我所使用的是来自百度团队的ECharts.官方网址:http://echarts.baidu.com/      我们知 ...

  6. Nancy之基于Nancy.Hosting.Aspnet的小Demo

    近来学习了一下Nancy这个框架,感觉挺好用的,就写篇简单的文章记录一下大致用法,由于是刚接触,写的代码 可能不规范,也没有具体的分层..莫吐槽... Nancy的官网:http://nancyfx. ...

  7. 基于highcharts封装的组件-demo&源码

    前段时间做的项目中需要用到highcharts绘制各种图表,其实绘制图表本身代码很简单,但是由于需求很多,有大量的图形需要绘制,所以就不得不复制粘贴大量重复(默认配置等等)的代码,所以,后来抽空自己基 ...

  8. 搞了个基于zookeeper的Leader/Follower切换Demo

    基于zookeeper写了个Leader选举类库demo,场景如下: 上图中的Program1..4可以部署在1台server上,也可以部署在多台server上,也可以是一个进程中的多个线程. 运行效 ...

  9. 基于Cocos2dx + box2d 愤怒的小鸟的实现Demo

    1. Demo初始界面 2. 游戏界面 3. 精确碰撞检測 4. 下载  压缩文件文件夹 AngryBird source    愤慨的小鸟Demo源码,基于Cocos2dx C++,以及box2d技 ...

随机推荐

  1. Eclipse中修改了项目,导入Tomcat中时,括号显示原来项目的名字

    Eclipse中Tomcat导入项目并且修改了项目名字,把项目添加到Tomcat上,发现在项目后面带了个括号里面显示原来项目的名字,并且在访问的时候也只能用原来的项目名访问,怎么办呢? 1.打开你的项 ...

  2. Java设计模式的6大原则

    Java设计模式的6大原则 1.开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果.简单来 ...

  3. matlab的diff()函数

    diff():求差分 一阶差分 X = [1 1 2 3 5 8 13 21]; Y = diff(X) 结果: Y = 0 1 1 2 3 5 8 X = [1 1 1; 5 5 5; 25 25 ...

  4. 【CSP-S 2019】【洛谷P5664】Emiya 家今天的饭【dp】

    题目 题目链接:https://www.luogu.org/problem/P5664 Emiya 是个擅长做菜的高中生,他共掌握 \(n\) 种烹饪方法,且会使用 \(m\) 种主要食材做菜.为了方 ...

  5. SpringBoot整合Gson(转)

    第一步:移除jackson依赖 参考代码 <dependency> <groupId>org.springframework.boot</groupId> < ...

  6. (转载) 从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    这一篇是从0开始搭建SQL Server AlwaysOn 的第二篇,主要讲述如何搭建故障转移集群,因为AlwaysOn是基于Windows的故障转移集群的 在讲解步骤之前需要了解一下故障转移集群仲裁 ...

  7. SpringBoot基础及FreeMarker模板

    案例springboot_freemarker application.properties配置文件 ###FreeMarker配置 spring.freemarker.template-loader ...

  8. 学到了林海峰,武沛齐讲的Day37 完

    day1   多用户同时刻下载上传程序分析 day2   htlm介绍 觉得收货的季节到了 day3   htlm介绍 day4   htlm介绍 关键字介绍  Toray大仙 Toray大仙 day ...

  9. WSAStartup() - 使用方法

    当一个应用程序调用WSAStartup函数时, 操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中. 以后应用程序就可以调用所请求的Socket库 ...

  10. Luogu P1903 BZOJ 2120 数颜色 带修改的莫队

    https://www.luogu.org/problemnew/show/P1903 之前切过这道题,复习莫队再切一遍,不过我之前写的是主席树和树状数组,也不知道我当时怎么想的…… 这个题卡常我没写 ...