之前负责flink平台的规划以及开发,这里记录flink如何写数据到hive。我们的场景都是些基于埋点数据的分析,用户活跃、用户新增之类的。用图表示大概如下:
原本是希望使用flink sql开发的,综合考虑后使用StreamingFileSink(点击连接查看官网),demo如下:
//前提是启用 Checkpoint,不然部分文件(part file)将永远处于 'in-progress' 或 'pending' 状态,下游系统无法安全地读取。
String outputBasePath = "hdfs://.../test/tablename/"
final StreamingFileSink<Row> sink = StreamingFileSink
.forRowFormat(new Path(outputPath), new SimpleStringEncoder<Row>("UTF-8"))
//.withRollingPolicy(OnCheckpointRollingPolicy.build())
.withRollingPolicy(
DefaultRollingPolicy.builder()
.withRolloverInterval(TimeUnit.MINUTES.toMillis(30))
.withInactivityInterval(TimeUnit.MINUTES.toMillis(5))
.withMaxPartSize(1024 * 1024 * 128)
.build())
.withBucketAssigner(new CustomEventTimeBucketAssigner("yyyy-MM-dd"))
.withOutputFileConfig(
OutputFileConfig.builder()
.withPartPrefix("prefix")
.withPartSuffix(".csv")
.build())
.build();
input.addSink(sink);
1)withRollingPolicy方法设置滚动策略,该策略在以下三种情况下滚动处于 In-progress 状态的部分文件(part file):
2)withBucketAssigner方法设置分桶策略,CustomEventTimeBucketAssigner类是一个自定义的根据eventTime分桶的分配器。可以参考默认的DateTimeBucketAssigner自定义分配器。
3)withOutputFileConfig方法是配置文件名的前缀和后缀的。
以上demo是基于行编码格式写HDFS,还有一种是以批量编码格式写的方式,其实现方式与行编码格式的sink差不多。需要注意的是,批量编码模式仅支持 OnCheckpointRollingPolicy 策略, 在每次 checkpoint 的时候切割文件。
StreamingFileSink支持 Exactly-Once,我们知道想实现端到端的 Exactly-Once是需要实现两阶段提交协议的。想详细了解的可以到官网去看。
数据是按照yyyy-MM-dd策略写入到HDFS的(当然,也可以按小时yyyy-MM-dd–HH),也就是数据按天写入到相应的日期目录下,并没有直接落地到hive。我们的办法是定时执行alter table添加partition,类似如下sql:
#hive sql
create external table stream_file_sink(
mid_id string,
user_id int,
version_code string,
version_name string,
lang string,
source string,
os string,
area string,
model string,
brand string,
sdk_version string,
height_width string,
app_time bigint,
network string,
lng float,
lat float
)
comment 'test streaming file sink'
partitioned by(dt string)
row format delimited fields terminated by ','
stored as textfile
location '/test/stream_file_sink';
//添加分区
alter table stream_file_sink add partition(dt='yyyy-MM-dd') location '/test/stream_file_sink/dt=yyyy-MM-dd';
定时脚本可以类似:
#!/usr/bin/env bash
d=`date -d "-1 day" +%Y%m%d`
# 每天HDFS的数据导入hive分区中
/hive-2.7.3/bin/hive -e "alter table default.users add partition (dt='${d}') location '/test/stream_file_sink/dt=${d}'"
使用crontab每天凌晨调度就行。
hive 添加partiotion后就可以查询该目录下的数据。
写HDFS有可能产生很多小文件,可以适当调整滚动策略,或者定期在后台程序对小文件进行 merge。