实时数仓维度关联的旁路缓存与异步IO

由于存在dim层中的维度表数据是在Hbase中,查询关联时一般是一行一行的读取如

select * from t where v=v1 and v=v2;

而Hbase读取一条数据大概时间在10ms左右。因此Hbase的读数据速度就不能满足时效性要求,上游kafka数据发送过多而下游处理时间不够导致flink反压机制触发,任务处于亚健康状态。时间长了上游就会阻塞,flink1.5之前是通过TCP的反压机制来控制的,在1.5版本以后,引进了credit这种反压机制(和TCP反压机制类似,不过是在flink层面上的)。具体感兴趣的可以去官网看下这方面的资料。

老六办法一般可以将开窗时间加大,这样数据量减少但时效性降低。

实时数仓中dws中如果需要用dwd中数据关联dim维表的数据。

维度表保存在 Hbase,首先要在 PhoenixUtil 工具类中补充查询方法。

我们可以拼接查询语句,通过参数传递给查询方法,在方法内部执行注册驱动、获取连接对象、预编译(获取数据库操作对象)、执行、解析结果集、关闭资源六个步骤即可取出数据。此处选择自定义实体类作为集合元素,查询结果的每一行对应一个实体类对象,将所有对象封装到 List 集合中,返回给方法调用者。

外部数据源的查询常常是流式计算的性能瓶颈。每次查询都要连接 Hbase,数据传输需要做序列化、反序列化,还有网络传输,严重影响时效性。可以通过旁路缓存对查询进行优化。

旁路缓存模式是一种非常常见的按需分配缓存模式。所有请求优先访问缓存,若缓存命中,直接获得数据返回给请求者。如果未命中则查询数据库,获取结果后,将其返回并写入缓存以备后续请求使用。

(1)旁路缓存策略应注意两点

a)缓存要设过期时间,不然冷数据会常驻缓存,浪费资源。

b)要考虑维度数据是否会发生变化,如果发生变化要主动清除缓存。

(2)缓存的选型

一般两种:堆缓存或者独立缓存服务(memcache,redis)

堆缓存,性能更好,效率更高,因为数据访问路径更短。但是难于管理,其它进程无法维护缓存中的数据。

独立缓存服务(redis,memcache),会有创建连接、网络IO等消耗,较堆缓存略差,但性能尚可。独立缓存服务便于维护和扩展,对于数据会发生变化且数据量很大的场景更加适用,此处选择独立缓存服务,将 redis 作为缓存介质。

(3)实现步骤

从缓存中获取数据。

① 如果查询结果不为 null,则返回结果。

② 如果缓存中获取的结果为 null,则从 Phoenix 表中查询数据。

a)如果结果非空则将数据写入缓存后返回结果。

b)否则提示用户:没有对应的维度数据

       注意:缓存中的数据要设置超时时间,本程序设置为 1 天。此外,如果原表数据发生变化,要删除对应缓存。为了实现此功能,需要对维度分流程序做如下修改:

       i)在 MyBroadcastFunction的 processElement 方法内将操作类型字段添加到 JSON 对象中。

       ii)在 DimUtil 工具类中添加 deleteCached 方法,用于删除变更数据的缓存信息。

       iii)在 MyPhoenixSink 的 invoke 方法中补充对于操作类型的判断,如果操作类型为 update 则清除缓存。

 Jedis 相关依赖

<dependency>

    <groupId>redis.clients</groupId>

    <artifactId>jedis</artifactId>

    <version>3.3.0</version>

</dependency>

异步 IO

在Flink 流处理过程中,经常需要和外部系统进行交互,如通过维度表补全事实表中的维度字段。

默认情况下,在Flink 算子中,单个并行子任务只能以同步方式与外部系统交互:将请求发送到外部存储,IO阻塞,等待请求返回,然后继续发送下一个请求。这种方式将大量时间耗费在了等待结果上。

为了提高处理效率,可以有两种思路。

(1)增加算子的并行度,但需要耗费更多的资源。

(2)异步 IO。

Flink 在1.2中引入了Async I/O,将IO操作异步化。在异步模式下,单个并行子任务可以连续发送多个请求,按照返回的先后顺序对请求进行处理,发送请求后不需要阻塞式等待,省去了大量的等待时间,大幅提高了流处理效率。

Async I/O 是阿里巴巴贡献给社区的特性,呼声很高,可用于解决与外部系统交互时网络延迟成为系统瓶颈的问题。

异步查询实际上是把维表的查询操作托管给单独的线程池完成,这样不会因为某一个查询造成阻塞,因此单个并行子任务可以连续发送多个请求,从而提高并发效率。对于涉及网络IO的操作,可以显著减少因为请求等待带来的性能损耗。

总结:在flink中要根据数据本身特点和干什么用来决定用什么存数据,此处选用redis是因为Redis是基于内存的,当数据读进数据库中后再次读取是毫秒级以内的,而且Redis有过期时间设置ttl,flink中状态存储或者用集合存不好管理数据。而加入异步io后可以提高并发效率,不用长时间等待,但用到java中这种多线程比较高级的东西时需要注意数据安全性问题。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值