分享嘉宾:中国好胖子
编辑整理:柠檬妹
出品平台:数据仓库与Python大数据
目录
- 1、ETL背景
2、解决方案
2.1 直接查库定时更新
2.2 异步IO
2.3 Broadcast的方式
2.4 异步io结合Cache
3、完整源码
正文
Tips:推荐收藏,PC端观看效果更佳哦
1、ETL背景
在我们实时数仓日常工作中,经常会有一些实时的需求,这些需求往往都是一些拉宽的需求。为了给实时数仓来进行OLAP对来进行Ad-hoc查询,但是我们工作中一些维度表的数据是会发生变化的,可能是缓慢变化维度。那么这个时候就需要进行flink连接其他数据源来进行查询。那么这个时候我们肯定可以想到就是来一条查一次,这个是肯定可以做到的。
但是在大数据场景下,我们是不是会觉得有点慢呢?
我们是否有更好的解决方案,就像我写代码的时候 有时候就会思考有没有更好的解决方案。但是针对于要进行交付给用户,所以我们并没有那么多的时间进行思考来进行,因为产品一直都在催你哦。那么我们就来看看有几种解决方案:
上图 是一个实时架构图。当然我们公司已经引入了clickhouse 实时数仓这些已经不是我们所追求的了,但是并不妨碍我们的需求。下面我们就来看一下数据。
{"dt":"2019-11-19 20:33:39","countryCode":"TW","data": [{"type":"s1","score":0.8,"level":"D"},{"type":"s2","score":0.1,"level":"B"}]}
{"dt":"2019-11-19 20:33:41","countryCode":"KW","data": [{"type":"s2","score":0.2,"level":"A"},{"type":"s1","score":0.2,"level":"D"}]}
{"dt":"2019-11-19 20:33:43","countryCode":"HK","data": [{"type":"s5","score":0.5,"level":"C"},{"type":"s2","score":0.8,"level":"B"}]}
{"dt":"2019-11-19 20:33:39","countryCode":"TW","data": [{"type":"s1","score":0.8,"level":"D"},{"type":"s2","score":0.1,"level":"B"}]}
当然之上 是我们的模拟数据,接下来我们看看 业务人员需要什么数据
"dt":"2019-11-19 20:33:39","countryCode":"AREA_CT","type":"s1","score":0.8,"level":"D"
"dt":"2019-11-19 20:33:39","countryCode":"AREA_CT","type":"s2","score":0.1,"level":"B"
那么这个时候我们可以发现了,其实就是把国家 换成大区,这样入仓之后可以进行 大区的olap实时的一些分析。例如实时的绩效考核等,还有一些营销活动等。我们就不细细考量了,因为毕竟都是假数据。
那么我们看到原始数据和结果数据,我们发现,是进行了拆解,例如 一条记录中带有多个 type 也就是直播平台,但是结果数据拆成了两个,这个不是udtf吗?
同时将国家编码转化为大区编码,那么我们这时候假定大区编码会有变化,因为组织的重构问题,或者组织的架构演进等。
那么我们思考一下 有几种解决方案呢?
2、解决方案
2.1 直接查库定时更新
温馨提示:手机端左右滑动即可查看完整代码哦
static class SimpleFlatMapFunction extends RichFlatMapFunction<String,OutData>{
private transient ConcurrentHashMap<String, String> hashMap = null;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
Jedis jedisCluster = RedisFactory.getJedisCluster();
ScanResult<Map.Entry<String, String>> areas = jedisCluster.hscan("areas", "0");
List<Map.Entry<String, String>> result = areas.getResult();
System.out.println("更新缓存");
hashMap = new ConcurrentHashMap<>();
for (Map.Entry<String, String> stringStringEntry : result) {
String key = stringStringEntry.getKey();
String[] split = stringStringEntry.getValue().split(",");
for (String s : split) {
hashMap.put(s, key);
}
}
jedisCluster.close();
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("更新缓存");
Jedis jedisCluster = RedisFactory.getJedisCluster();
ScanResult<Map.Entry<String, String>> areas = jedisCluster.hscan("areas", "0");
List<Map.Entry<String, String>> result = areas.getResult();
hashMap = new ConcurrentHashMap<>();
for (Map.Entry<String, String> stringStringEntry : result) {
String key = stringStringEntry.getKey();
String[] split = stringStringEntry.getValue().split(",");
for (String s : split) {
hashMap.put(s, key);
}
}
jedisCluster.close();
}
}, 0, 3, TimeUnit.SECONDS);
}
@Override
public void flatMap(String s, Collector<OutData> collector) throws Exception {
OriginData originData = JSONObject.parseObject(s, OriginData.class);
String countryCode = originData.countryCode;
ArrayList<Data> data = originData.data;