Flink-to-Hive实现

之前负责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):

  • 它至少包含 30分钟的数据
  • 最近 5 分钟没有收到新的记录
  • 文件大小达到 128MB (写入最后一条记录后)

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。

你可能感兴趣的:(flink)