乐趣区

袋鼠云研发手记 | 开源·数栈-扩展FlinkSQL实现流与维表的join

作为一家创新驱动的科技公司,袋鼠云每年研发投入达数千万,公司 80% 员工都是技术人员,袋鼠云产品家族包括企业级一站式数据中台 PaaS 数栈、交互式数据可视化大屏开发平台 Easy[V] 等产品也在迅速迭代。在进行产品研发的过程中,技术小哥哥们能文能武,不断提升产品性能和体验的同时,也把这些提升和优化过程记录下来,现录入“袋鼠云研发手记”专栏中,以和业内童鞋们分享交流。
下为“袋鼠云研发手记”专栏第三期,本期作者为袋鼠云数栈引擎团队。
袋鼠云数栈引擎团队
袋鼠云数栈引擎团队拥有多名专家级别,经验丰富的后端开发工程师,分别支撑公司大数栈产品线的不同子项目的开发需求,从项目中提取并开源了 FlinkX(基于 Flink 的数据同步),Jlogstash(logstash 的 java 版本实现),FlinkStreamSQL(扩展原生 FlinkSQL,实现流与维表的 join)多个项目。
在长期的项目实践与产品迭代过程中,团队成员在 Hadoop 技术栈上不断深耕探索,积累了丰富的经验与最佳实践。
第三期
数栈·开源 拓展 FlinkSQL 实现流与维表的 join
FlinkStreamSQL 已经开源在 Github 上 目前已获 380+Star
1、为什么要扩展 FlinkSQL?
实时计算需要完全 SQL 化
SQL 是数据处理中使用最广泛的语言。它允许用户简明扼要地声明他们的业务逻辑。大数据批计算使用 SQL 很常见,但是支持 SQL 的实时计算并不多。其实,用 SQL 开发实时任务可以极大降低数据开发的门槛,在袋鼠云数栈 - 实时计算模块,我们决定实现完全 SQL 化。
数据计算采用 SQL 的优势
☑ 声明式。用户只需要表达我想要什么,至于怎么计算那是系统的事情,用户不用关心。
☑ 自动调优。查询优化器可以为用户的 SQL 生成最有的执行计划。用户不需要了解它,就能自动享受优化器带来的性能提升。
☑ 易于理解。很多不同行业不同领域的人都懂 SQL,SQL 的学习门槛很低,用 SQL 作为跨团队的开发语言可以很大地提高效率。
☑ 稳定。SQL 是一个拥有几十年历史的语言,是一个非常稳定的语言,很少有变动。所以当我们升级引擎的版本时,甚至替换成另一个引擎,都可以做到兼容地、平滑地升级。
实时计算还需要流与维表的 JOIN
在实时计算的世界里不只是流与流的 JOIN,还需要流与维表的 JOIN
在实时计算的世界里不只是流与流的 JOIN,还需要流与维表的 JOIN。在去年,袋鼠云数栈 V3.0 版本研发期间,当时最新版本——flink1.6 中 FlinkSQL,已经将 SQL 的优势应用到 Flink 引擎中,但还未支持流与维表的 JOIN。
关于 FlinkSQL
FlinkSQL 于 2017 年 7 月开始面向阿里巴巴集团开放流计算服务的,虽然是一个非常年轻的产品,但是到双 11 期间已经支撑了数千个作业,在双 11 期间,Blink 作业的处理峰值达到了 5 + 亿每秒,而其中仅 Flink SQL 作业的处理总峰值就达到了 3 亿 / 秒。
参考链接:https://yq.aliyun.com/article…
这里先解释下什么是维表;维表是动态表,表里所存储的数据有可能不变,也有可能定时更新,但是更新频率不是很频繁。在业务开发中一般的维表数据存储在关系型数据库如 mysql,oracle 等,也可能存储在 hbase,redis 等 nosql 数据库。
2、所以要用 FlinkSQL 实现流与维表的 join 分两步:
一、用 Flink api 实现维表的功能
要实现维表功能就要用到 Flink Aysnc I/O 这个功能,是由阿里巴巴贡献给 Apache Flink 的。
Async I/O 是由阿里巴巴贡献给社区的,于 1.2 版本引入,主要目的是为了解决与外部系统交互时网络延迟成为了系统瓶颈的问题。具体介绍可以看这篇文章:http://wuchong.me/blog/2017/0…
对应到 Flink 的 api 就是 RichAsyncFunction 这个抽象类,继层这个抽象类实现里面的 open(初始化),asyncInvoke(数据异步调用),close(停止的一些操作)方法,最主要的是实现 asyncInvoke 里面的方法。
流与维表的 join 会碰到两个问题:
第一个是性能问题。因为流速要是很快,每一条数据都需要到维表做下 join,但是维表的数据是存在第三方存储系统,如果实时访问第三方存储系统,不仅 join 的性能会差,每次都要走网络 io;还会给第三方存储系统带来很大的压力,有可能会把第三方存储系统搞挂掉。
所以解决的方法就是维表里的数据要缓存,可以全量缓存,这个主要是维表数据不大的情况,还有一个是 LRU 缓存,维表数据量比较大的情况。
LRU 维表的实现
第二个问题是流延迟过来的数据这么跟之前的维表数据做关联。这个就涉及到维表数据需要存储快照数据,所以这样的场景用 HBase 做维表是比较适合的,因为 HBase 是天生支持数据多版本的。
ALL 维表的实现
二、解析流与维表 join 的 SQL 语法转化成底层的 FlinkAPI
因为 FlinkSQL 已经做了大部分 SQL 场景,我们不可能在去解析 SQL 的所有语法,在把他转化成底层 FlinkAPI。
所以我们做的就是解析 SQL 语法,来找到 join 表里有没有维表,如果有维表,那我们会把这个 join 的维表的语句单独拆来,用 Flink 的 TableAPI 和 StreamAPi 生成新 DataStream,在把这个 DataStream 与其他的表在做 join 这样就能用 SQL 来实现流与维表的 join 语法了。
SQL 解析的工具就是用 Apache calcite,Flink 也是用这个框架做 SQL 解析的。所以所有语法都是可以解析的。
1. DEMO SQL

Calcite 解析 Insert into 语句,拆分出子语句

3. Calcite 继续解析 select 语句

Calcite 继续解析 select 语句
Calcite 继续解析 select 语句

退出移动版