持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
本文实用于第一次使用 flink 来操作 hive 的同学阅读借鉴,Flink老鸟和公司设施完善的可以略过不看。
作者会持续更新Flink相关开发经验,欢迎关注加收藏。
背景
推荐项目中需要新增一个报表,计算付费转化率。付费转化率的分子是当天新增付费用户,分母是当天的所有未付费用户。
需求比较么简单,就看怎么选择技术栈。
摆在面前的方案有
- spark sql
- hive sql by python or other language
- flink
前2个方案都可以实现,项目应该也有类似实现,但是比较繁琐,不能实现sql统计直接写入mysql,或者语法不够简洁。
自从使用过flink stream后,再也不想用spark 了,故这次使用flink离线统计来完成。
最后的选择是flink来实现这个需求。
使用方法
调研了行业的使用方法,发现很多是通过一个web ui界面来实现此类需求的,底层通过sql gateway来实现,不是通过jar包来实现。
找了一下,除了自研外,HUE似乎也提供了flink 的支持,但因生产环境的hue上面跑了一堆任务,我不可能去升级那个老的hue来支持flink,因为上面的依赖实在太多了,hive,ooize,spark等等.思来想去,只有折腾自己了.
查看官网flink 读写hive的方式主要有2种,一种是通过flink sql操作(默认dialect),一种是通过hive dialect来实现。
最初想着省事,因为hive sql已经在hue上面跑通,只要通过hive dialect的方式,把sql放进去,应该能跑通,谁知道这是遇到的第二大坑。后面想了一下可能flink对hive sql并不是完全兼容,换成默认dialect了,基本就差不多了
遇到的问题及解决方法
- hive版本问题
生产环境上的hive为2.1.0,有点老,如果真用这个版本的hive-exec,就发现会依赖jdk 1.16,这有点不太可能。还是老实按官方推荐使用flink带的flink-sql-connector-hive 来解决问题,这也是官方推荐的方式 - json deserialize error
因为hive的表在创建时指定ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe',所以要在依赖中加入
org.keedio.openx.data的依赖
<dependency>
<groupId>org.keedio.openx.data</groupId>
<artifactId>json-serde</artifactId>
<version>1.3.7.3</version>
</dependency>
- Distinct without an aggregation.
选用hive dialect后,执行sql报错,我们的sql最小重现为下面的样子
select devid as pdevid,
count(distinct vtype) as vip_type_trans
from events
where dt = '20220702'
and utype > -1
group by devid
having count(distinct vtype) > 1
原因为flink hive dialect对 having count的支持有问题,并不完全兼容,会出现你在hue on hive上面成功执行,在这里不行的情况。
解决方案是放弃hive dialect,选用flink default dialect的方式,即flink sql来执行,把sql改造成flink sql的语法即可
- Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.mapred.JobConf
看起来是没有相关的hadoop包,按照flink上面的说明,已经加入下面的声明的情况下报出来的
export HADOOP_CLASSPATH=`hadoop classpath`
费了老大劲,把 /usr/local/service/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.7.3.jar 放到 flink/lib下了才解决。
- Caused by: java.lang.ClassNotFoundException: org.apache.flink.util.function.SerializableFunction
这个错误是因为在server上确实没有这个类,生产环境的jar包为1.14.2,编译的pom包是1.14.4,导致该问题的发生。
这个应该是在调试过程中修改了flink版本号,导致和生产环境不一致造成的。
- Caused by: org.apache.flink.table.api.ValidationException: Column types of query result and sink for registered table 'xxxx' do not match. Cause: Different number of columns
原因很简单,就是tableEnv.executeSql执行建表,会把表在在hive相同database中存起来,如果你后面修改了sink表定义,如果这个hive中的同名table没有删除,则会显示为修改没有生效。在create table前先drop table就好了。
最终效果
算子执行过程
任务job
任务结束
任务job
\
反思总结
- 保证生产环境的flink和开发环境版本一致
- 根据提示少对应的类,就找对应的包,虽然全程按官方的来,但毕竟每个人的环境不一样,有些依赖的确没有提到。
- 这东西学是要多实践,有太多的不可量化的沉默成本在里面,毕竟是一个大生态,也只能遇到问题解决问题了。