1. 场景复现:先把问题固定下来
1.1 先说清楚我是怎么搭的这条链路
我手上这个任务很典型:Flink 1.12.2 读 Kafka 里的用户行为事件,按天分区写入 Hive 数仓 ODS 层,表是分区表dwd_user_events,分区字段是dt,文件格式用的 ORC + Snappy,下游用 Hive 客户端和 HiveServer2 做临时查询。
集群环境是 Hadoop 2.10 + Hive 3.1.2,Flink 跑在 YARN 上。任务启动后,从 Flink Web UI 看作业状态一直是 RUNNING,没有反压,没有重启,Kafka 消费组的 Lag 也在稳定下降。从表面看,整条链路没有任何报错。
然后我去 Hive 客户端里执行查询:
SELECT COUNT(*) FROM dwd_user_events;返回 0。
再执行:
SHOW PARTITIONS dwd_user_events;结果是空的。
但 HDFS 上明明已经在写文件了:
hdfs dfs -ls /warehouse/tables/dwd/dt=2024-11-25/能看到一堆part-xxxx-aabbcc文件,大小还一直在涨。
这就是标题里那个问题的完整画像:Flink 任务“自觉”写得很欢,但 Hive 客户端就是看不见数据。这里有个非常容易误导人的地方——任务不报错,Kafka 数据也确实进了 HDFS,所以很多人会先去查 SQL、查 Join、查类型转换,折腾一圈才发现问题根本不在数据计算逻辑上,而在“写 Hive”这个动作本身没做完。
1.2 故障现象拆分:先判断属于哪一类
遇到“Hive 查不到数据”,我建议先画一条分界线:是 HDFS 上没有文件,还是 HDFS 有文件但 Hive 元数据里没有分区,还是元数据里有分区但查询结果为空。这三类现象对应的排查方向完全不同。
我把当时的排查过程整理成一张速查表:
| 检查项 | 命令/操作 | 结果说明 |
|---|---|---|
| HDFS 文件是否生成 | hdfs dfs -ls /warehouse/tables/dwd/dt=2024-11-25/ | 有文件但后缀为.part或.in-progress,说明提交链路未完成 |
| Hive 元数据分区是否存在 | hive -e "SHOW PARTITIONS dwd_user_events" | 为空表示分区未注册到 Metastore |
| Hive 查询是否有数据 | hive -e "SELECT COUNT(*) FROM dwd_user_events" | 返回 0 可能是分区存在但路径/格式不匹配 |
| 表定义是否正常 | hive -e "DESCRIBE FORMATTED dwd_user_events" | 检查 Location 和存储格式是否与 Flink 写的一致 |
我当时的结果是:HDFS 有文件,元数据分区为空,查询返回 0。也就是说,文件已经落到了 Hive 表的 Location 目录里,但 Hive 的 Metastore 完全不知道有这些分区存在。这个问题如果在 Hive 里查不到数据,是因为 Hive 查询引擎定位数据靠的是 Metastore 里的分区元数据,而不是直接去扫目录。文件在,元数据不在,就等于数据“隐身”了。
2. 根因拆解:为什么数据会“隐身”
2.1 Hive 查询的两层可见性
在深入排查之前,得先把 Hive 的运行机制说透。Hive 有一套元数据体系,存放在 Metastore 里(通常是一个 MySQL 或者 PostgreSQL 库),里面记录表结构、分区信息、文件路径、存储格式。而真正的数据文件在 HDFS 上。
Hive 执行SELECT的时候,流程是这样的:先去 Metastore 查到表对应哪些分区,每个分区的 Location 是什么,然后去 HDFS 上读对应路径下的文件。如果分区元数据里没有登记某个目录,即使这个目录真实存在,Hive 也完全不会去读它。
用生活里的例子类比:HDFS 是图书馆的书架,Metastore 是图书馆的检索卡片目录。你把书放上书架了(文件落盘),但没做卡片登记(分区没提交到 Metastore),读者翻开检索系统自然查不到这本书。目录系统里查不到,书再好也借不出去。
很多刚接触 Flink + Hive 集成的人会默认“写到 Hive 表的 Location 就是写入 Hive 表了”,这个认知在大数据体系里是不成立的。写入 HDFS 和写入 Hive 表是两个动作,中间隔着一层 Metastore 的注册。
2.2 Flink 写 Hive 的两条不同路径
排查时要先弄清楚:你的 Flink 任务到底是用什么方式写的“Hive”。这里存在两条完全不同的路径,很多人就是在这上面踩了坑。
路径 A:用 FileSystem Connector 直接指到 Hive 表的 Location。
有人图省事,用 Flink SQL 的通用文件系统连接器建表时,把表的path直接配置成了 Hive 表的 Location,例如:
CREATE TABLE hive_target ( user_id BIGINT, event_type STRING, dt STRING ) WITH ( 'connector' = 'filesystem', 'path' = 'hdfs://ns1/warehouse/tables/dwd/dt=${dt}', 'format' = 'orc' );这种写法的本质是:Flink 只负责往 HDFS 目录里吐文件,它根本不感知 Metastore,更不会往 Metastore 里登记分区。数据确实进去了,但对 Hive 来说这些文件是“野文件”。Hive 客户端查不到数据是必然结果,不是偶发现象。
路径 B:用 HiveCatalog + Hive 方言建表,走 Flink 的 Hive Sink。
这才是真正意义上的“写入 Hive 表”。建表时通过 Hive 方言创建,表注册在 HiveCatalog 里,Flink 在作业执行过程中会通过 Hive 的连接器写数据,并在 checkpoint 完成后把分区信息提交到 Metastore。这样 Hive 客户端才能查到数据。
我当时的问题就是混用了这两种路径:Kafka 源表用默认方言建,目标表想省事直接用了 FileSystem Connector 指到 Hive 路径。结果文件写了一堆,Metastore 里一个分区都没有。后来我把目标表改成通过 HiveCatalog 定义,问题才彻底解决。
判断自己属于哪条路径,最直接的方式是在 Flink SQL CLI 里执行:
SHOW CREATE TABLE hive_target;如果WITH里面出现'connector' = 'filesystem',那你就是路径 A,需要换掉整个表的定义;如果表定义是从 Hive 方言里创建出来、连接器是 Hive 的,那就是路径 B。
2.3 Checkpoint 不开启,文件永远停留在临时态
还有一个常见坑:即使你走了路径 B,如果 Flink 作业没有开启 Checkpoint,Hive 客户端照样查不到数据。
原因在于 Flink 的流式文件写入采用了“两阶段提交”的机制。数据写进 HDFS 后,文件先以.part-xxx.in-progress的形式存在,等一次 Checkpoint 快照完成,文件会被重命名为.part-xxx.pending,再等 Checkpoint 确认成功,才会变成正式的.part-xxx文件。而 Hive 元数据的分区提交,也是挂在 Checkpoint 成功回调上的。没有 Checkpoint,就没有文件提交,更没有分区注册。
所以我在检查 HDFS 的时候特意看了文件后缀。如果看到一堆.in-progress结尾的文件,那基本可以断定:作业没开 Checkpoint,或者 Checkpoint 一直没成功。
这里有一个容易忽略的细节:Checkpoint 的触发间隔不能太长。我当时把间隔设成 60 秒,还能接受。如果业务上把间隔设成几小时甚至不设置,那么流式写入的数据会一直攒在临时文件里,Hive 客户端长时间看不到新数据,业务方就会来投诉。
2.4 目录命名和格式不一致也会导致“查得到分区但查不到数据”
还有一种情况是分区在 Metastore 里能看到,但SELECT依然返回 0 行。这个问题往往出在路径细节上。
Hive 分区表的默认目录规则是分区键=分区值,比如dt=2024-11-25。如果你在 Flink 里手动拼接路径时写成了2024-11-25(少了dt=),或者写成了dt=20241125这种和分区值不匹配的格式,那么即使你在 Metastore 里手动注册了dt='2024-11-25',实际文件路径对不上,查询时照样读不到数据。
另外,文件格式也要对齐。Hive 表定义是 ORC,Flink 实际写的是 Parquet,或者压缩方式不一致,Hive 客户端在读取时要么直接报错,要么读出来的数据解析失败。我在排查时对比过 Hive 表定义的STORED AS和 Flink 写入侧的format,确保两边完全一致,才排除了这个因素。
3. 解决方案:让数据真正对 Hive 可见
3.1 快速止血:用 MSCK REPAIR TABLE 同步元数据
如果你现在线上就在跑着这样的任务,业务方又催着要数据,最快的止血办法是用MSCK REPAIR TABLE手动把 HDFS 上的分区同步到 Metastore。
MSCK REPAIR TABLE dwd_user_events;这条命令会扫描表的 Location 目录,找出 HDFS 上存在但 Metastore 里缺失的分区,然后批量注册。执行完再查:
SHOW PARTITIONS dwd_user_events; SELECT COUNT(*) FROM dwd_user_events;数据马上就能查到了。这个方案适合“救火”,因为它是间歇性动作,不是自动的。你总不能每隔几分钟让运维手动敲一次吧?生产环境还是得让 Flink 自己完成分区提交。
如果分区数量特别大(比如几万个),可以用:
MSCK REPAIR TABLE dwd_user_events ADD PARTITIONS;只添加缺失的分区,不执行全量扫描,效率会高很多。还有一个小参数可以关掉路径校验:
SET hive.msck.path.validation=ignore;这个参数在目录命名稍微不规范的时候有用,但不建议默认打开,因为你可能因此掩盖真正的问题。
3.2 治本方案:让 Flink 走 Hive Sink 并自动提交分区
要彻底解决“Hive 客户端查不到数据”,正确做法是让 Flink 走完整的 Hive Sink 链路,并且把分区提交策略配置好。
我在重构作业时,做了这么几步:
第一步,把hive-conf-dir配到 Flink 的 SQL 客户端和集群环境里,保证 Flink 能拿到 Hive 的hive-site.xml,从而找到 Metastore 地址:
CREATE CATALOG myhive WITH ( 'type' = 'hive', 'default-database' = 'dwd', 'hive-conf-dir' = '/etc/hive/conf' ); USE CATALOG myhive;第二步,用 Hive 方言建目标表,并显式声明分区提交策略:
SET table.sql-dialect = hive; CREATE TABLE dwd_user_events ( user_id BIGINT, event_type STRING, event_time TIMESTAMP ) PARTITIONED BY (dt STRING) STORED AS ORC TBLPROPERTIES ( 'sink.partition-commit.trigger' = 'process-time', 'sink.partition-commit.policy.kind' = 'metastore,success-file', 'sink.partition-commit.success-file.name' = '_SUCCESS', 'sink.rolling-policy.file-size' = '128MB', 'sink.rolling-policy.rollover-interval' = '10min' );这里重点解释三个属性:
sink.partition-commit.trigger决定什么时候触发分区提交。process-time表示当某个分区第一次被写入且 Checkpoint 成功后就提交,简单直接;partition-time则需要配合 Watermark 和延迟时间,适合处理迟到数据。如果业务对数据延迟要求不高,用process-time最省心。sink.partition-commit.policy.kind是提交策略。metastore代表把分区注册到 Hive Metastore,这是 Hive 客户端能看到数据的关键;success-file表示在分区目录下写一个完成的标记文件(比如_SUCCESS),方便下游任务判断数据是否写完。两者用逗号分隔可以同时生效。sink.rolling-policy.file-size和sink.rolling-policy.rollover-interval控制文件滚动,避免产生过多小文件。这个后面会详细说。
第三步,切回默认方言,创建 Kafka 源表并写入:
SET table.sql-dialect = default; CREATE TABLE kafka_user_events ( user_id BIGINT, event_type STRING, event_time BIGINT, ts AS TO_TIMESTAMP_LTZ(event_time, 3) ) WITH ( 'connector' = 'kafka', 'topic' = 'ods_user_events', 'properties.bootstrap.servers' = 'kafka1:9092,kafka2:9092', 'properties.group.id' = 'flink-hive-sink-group', 'format' = 'json', 'scan.startup.mode' = 'latest-offset', 'json.ignore-parse-errors' = 'true' ); INSERT INTO dwd_user_events SELECT user_id, event_type, event_time, FROM_UNIXTIME(event_time, 'yyyy-MM-dd') AS dt FROM kafka_user_events;配置完这些,重启作业,等一个 Checkpoint 周期后去 Hive 客户端查,分区就出来了,数据也能查到。
这里有个实操细节:如果用了partition-time触发方式,还得配置sink.partition-commit.watermark-time-zone。这个参数指定分区时间使用的时区。我当时把数据源时间戳按北京时间处理,却忘了配置时区,导致分区提交总是比预期晚 8 小时。后来加上:
'sink.partition-commit.watermark-time-zone' = 'Asia/Shanghai'才恢复正常。
3.3 如果短期改不了作业,用定时补偿兜底
有些团队用的调度平台或者自研的 SQL 网关暂时不支持上述复杂的属性配置,作业又不好马上改,这时可以用定时补偿的方式兜底。
具体做法是在调度系统里加一个周期任务,每隔几分钟执行一次:
hive -e "MSCK REPAIR TABLE dwd_user_events ADD PARTITIONS;"或者用 Hive 的ALTER TABLE手动补分区:
ALTER TABLE dwd_user_events ADD PARTITION (dt='2024-11-25') LOCATION '/warehouse/tables/dwd/dt=2024-11-25';这个方案不优雅,但能够快速让下游查询到数据。它只适合作为过渡方案,治本还是要回到 3.2 的 Hive Sink 自动提交上。
4. 实操细节:从 Kafka 到 Hive 的全链路配置
4.1 环境层面的几个配置容易踩坑
Flink 1.12 集成 Hive 时,环境配置不对会引发各种莫名其妙的问题,而且这些问题往往不是直接报“查不到数据”,而是更隐蔽的异常。
首先要确保hive-conf-dir在 Flink 集群的所有节点上都存在,并且包含完整的hive-site.xml。HiveCatalog 初始化时要读这个文件里的hive.metastore.uris,如果配置缺失,Flink 会退化成嵌入式 Metastore 模式,导致 Hive 客户端根本连不上这个独立的 Metastore,数据提交也就无从谈起。
其次,要注意 Hive 版本和 Flink 1.12 的兼容性。Flink 1.12 的 Hive 集成对 Hive 2.3 和 Hive 3.1 的兼容情况不一样。当时我用的是 Hive 3.1.2,就得用对应的flink-sql-connector-hive-3.1.2_2.11-1.12.jar,不能把 Hive 2.x 的依赖也一起放进去。我见过有人把 Hive 2.3 和 3.1 的 jar 同时塞到 lib 目录,结果作业启动时报NoSuchMethodError,排查了很久才发现是依赖冲突。
还有一个小参数通常会被忽略:
classloader.resolve-order: parent-first将这个参数配置在flink-conf.yaml里,能规避部分由于类加载顺序导致的 Hive 连接异常。特别是在开启了child-first默认策略的发行版环境中,Hive 相关类可能会加载错版本。
4.2 Kafka 源表设计的三个细节
Kafka 源表看似简单,但有几个地方会直接影响后续写入 Hive。
一是scan.startup.mode的选择。如果你要补历史数据,用earliest-offset;如果只要实时增量,用latest-offset。这个参数还和 Job 重启后的行为有关:一旦作业重启,如果是从 Savepoint 恢复,会从上次提交的 Offset 继续消费;如果是从零启动且是earliest-offset,就会从头消费,很可能造成重复写入。
二是时间字段的处理。我用的数据里时间戳是毫秒级的 Long,需要转成 Hive 可读的时间格式。Flink SQL 里可以先定义一个计算列:
ts AS TO_TIMESTAMP_LTZ(event_time, 3)然后写入时再格式化为分区字段:
FROM_UNIXTIME(event_time / 1000, 'yyyy-MM-dd') AS dt注意单位,毫秒要除以 1000,不然日期会偏差巨大。
三是容错配置。生产数据不可能保证每一条 JSON 都是合法的,把json.ignore-parse-errors设为true能防止单条脏数据把整个作业拖垮。代价是脏数据会被静默丢弃,需要根据业务情况权衡。
4.3 Hive 表定义中分区字段的一个隐性约束
Hive 分区表有个容易搞错的地方:分区字段在逻辑上也是表的列,但在物理文件中并不存在。也就是说,你在 Hive 里SELECT dt是可以的,但 ORC 文件里的列并不包含dt。Flink 写入时,dt是单独参与目录命名的,不会写进文件本身。
所以创建 Kafka 源表时,不要把源数据里的日期字段和目标表的分区字段直接看成同一列。写入的时候,你要保证INSERT INTO的列顺序和目标表定义完全一致,分区字段排在最后。我一开始建目标表时习惯把dt写在最前面,结果 Flink 报 schema 不匹配,调整顺序后就好了。
4.4 完整的作业提交与验证流程
作业配置完成后,我的验证流程分四步:
第一步,看 HDFS 文件状态。确认分区目录下出现的是正式的.part-xxx文件,而不是.in-progress:
hdfs dfs -ls /warehouse/tables/dwd/dt=2024-11-25/第二步,查 Metastore 分区:
hive -e "SHOW PARTITIONS dwd_user_events;"这一条能返回分区,说明metastore提交策略在起作用。
第三步,直接查数据:
hive -e "SELECT * FROM dwd_user_events LIMIT 10;"如果前三步都通过,基本可以确认问题解决。
第四步,持续观察一段时间,确认新分区能自动出现。我通常会让作业跑 30 分钟到 1 小时,确认跨了一个 Checkpoint 周期和分区滚动周期后,新分区依然能自动注册,才算是稳定下线。
5. 常见问题与排查技巧实录
5.1 文件始终是 .part 开头,正式文件一直不出现
这个现象我见过太多次了。原因几乎都出在 Checkpoint 上。要么没开 Checkpoint,要么 Checkpoint 间隔设置得太长,要么 Checkpoint 一直在失败。
排查时,先在 Flink Web UI 上找到作业的 Checkpoint 详情页。如果显示Checkpoint Timeout或者Checkpoint 失败,那问题就在状态后端大小、网络带宽或者 HDFS 写入延迟上。如果根本没有 Checkpoint 记录,那就回到 SQL 里加:
SET execution.checkpointing.interval = 60s;然后重启作业。
还有一个容易被忽略的点:如果作业是从不开启 Checkpoint 的状态下重启的,有些 SQL 客户端不会自动加载之前修改的 Session 配置。我建议把 Checkpoint 配置写进作业的提交脚本里,每次启动都重新设置,避免依赖客户端残留配置。
5.2 Metastore 能连上但分区提交一直失败
这种场景下,HDFS 文件是正常的,但 Metastore 里分区时有时无,或者一直不出现。日志里通常会看到类似Failed to commit partition这样的关键字。
我当时遇到的情况是权限问题。Flink 作业运行在 YARN 上,提交分区时需要通过 Metastore 往数据库里写记录,同时也要在 HDFS 上有写权限。如果作业提交用户的权限不足,Metastore 的写操作会失败。排查方法是检查 YARN 作业的运行用户,再看 Hive 数仓目录的属主和权限:
hdfs dfs -ls /warehouse/tables/dwd/如果文件属主和作业用户不一致,就需要在 HDFS 上调整 ACL,或者让任务以正确的用户运行。
另一个可能的原因是 Hive 方言建表时的数据库不对。USE CATALOG myhive;之后,如果default-database没选对,数据写到了 A 库的表里,你在 Hive 客户端却查 B 库的表,自然什么都查不到。
5.3 分区能查到,但查询结果还是 0 行
这种情况比“查不到分区”更隐蔽。分区在,文件在,Hive 查询也返回了,但就是没数据。
我排查时遇到过两种原因。
第一种是 Location 路径不匹配。Hive 表的分区元数据里记录的 Location 和文件实际所在目录不一致。这通常发生在手动ALTER TABLE ADD PARTITION指定了 LOCATION,但路径写成绝对路径后少了或者多了层目录。对比一下:
DESCRIBE FORMATTED dwd_user_events PARTITION (dt='2024-11-25');输出里有Location:字段,和 HDFS 实际路径对比就能发现差异。
第二种是统计信息问题。Hive 在某些配置下会依赖统计信息判断是否有数据,如果表的统计信息是空的,COUNT(*)可能直接返回 0。解决方案是先执行:
ANALYZE TABLE dwd_user_events PARTITION (dt='2024-11-25') COMPUTE STATISTICS;或者在查询前设置:
SET hive.compute.query.using.stats=false;强制 Hive 实际扫描数据。
5.4 写入成功但产生了大量小文件
流式写入最头疼的问题之一就是小文件。Flink 默认的滚动策略可能几秒钟就滚一个新文件,如果数据量不大,一小时能产生几十上百个小文件,严重拖慢后续查询。
解决方案是显式配置滚动策略。在 Hive 表的 TBLPROPERTIES 里加上:
'sink.rolling-policy.file-size' = '128MB', 'sink.rolling-policy.rollover-interval' = '30min', 'sink.rolling-policy.check-interval' = '5min'file-size表示文件超过 128MB 就滚动,rollover-interval表示即使文件不到 128MB,超过 30 分钟也会滚动,防止数据一直卡在内存缓冲区里不落盘。check-interval是检查周期。
有一点需要提醒:滚动间隔设得太长,会导致查询时当前文件不可见的时间变长。如果业务上要求分钟级看到数据,滚动间隔不能超过 10 分钟。这个参数需要根据业务延迟和数据量综合权衡。
5.5 重启后数据重复写入
流式作业重启后,如果状态恢复正常,Kafka 的 Offset 会从上次 Checkpoint 位置继续消费,通常不会重复。但如果作业是从零启动且 Kafka 源表用的earliest-offset,再加上目标表没有去重机制,就可能写入重复数据。
我当时遇到的情况是作业因为日志磁盘满了被 YARN 杀掉,而 Checkpoint 目录因为清理策略被删掉了,重启后只能从 Kafka 的 earliest 开始消费,结果 Kafka 里积压了 3 小时的数据,全部重新写入了一遍。从那以后我就把 Checkpoint 外部化配置打开:
SET execution.checkpointing.externalized.checkpoint-cleanup = RETAIN_ON_CANCELLATION;这样即使作业被取消或者异常退出,Checkpoint 数据还在,重启能恢复到之前的位置。
5.6 Flink 版本和 Hive 版本不兼容的典型报错
Fl欣欣向荣的社区里,最常见的兼容性报错是ClassNotFoundException: org.apache.hadoop.hive.ql.metadata.Hive,或者NoSuchMethodError: org.apache.hive...。出现这类问题的原因基本就是 jar 包冲突或者版本不匹配。
我的建议是:不要手动往 Flink 的 lib 目录里塞一堆 Hive 依赖,直接使用对应版本的官方连接器 jar,并且只放一个版本。Flink 1.12 对应 Hive 3.1 的 jar 是flink-sql-connector-hive-3.1.2_2.11-1.12.jar,只需要这一个文件就能跑通 HiveCatalog 和 Hive Sink。
另外,如果集群里还跑了 Spark,Spark 和 Flink 可能共用一份 Hive 依赖,版本不一致时也会出现兼容性问题。隔离 Flink 的依赖目录是最干净的做法。
6. 一些实际运维中的补充心得
最后结合我自己的运维经历,补充几个不太容易从文档里找到的经验。
第一个是“先确认三件事,再动手排查”。我后来遇到任何“写 Hive 查不到数据”的反馈,都先问自己三个问题:Checkpoint 开了没有?目标表是用 Hive 方言建的还是 FileSystem Connector 指的路?HDFS 上文件是正式的.part文件还是.in-progress?这三个问题能覆盖掉九成以上的故障原因,省去大量无效排查时间。
第二个是“分区提交延迟和迟到数据的关系”。如果业务上有明显的晚到数据(比如手机端上报延迟超过半小时),process-time提交方式会带来一个问题:迟到的数据会落到之前已经提交过的分区目录里。这个目录的分区元数据已经注册,所以查询没问题。但如果之前分区已经交付给下游做拉链或者统计,迟到的数据就会导致结果修正,整个数据链路需要做幂等设计。在这种情况下,建议用partition-time和sink.partition-commit.delay,把提交时间往后压一段,给迟到数据留出缓冲时间。
第三个是“不要只信 Web UI 上的成功状态”。Flink 作业 RUNNING 不代表数据写成功,更不代表 Hive 能查到。最可靠的验证方式是直接查 Metastore,不要看 Web UI。我见过不少团队在 Web UI 上看到 Sink 算子数据量在涨,就觉得一切正常,直到业务方提交工单说数据丢了,才暴露问题。
第四个经验是关于分区粒度。如果业务上查得没那么频繁,建议只用天级分区。用小时甚至分钟级分区在流式写入场景下会产生大量分区,Metastore 的管理压力会成倍增加,MSCK REPAIR也会越来越慢。数据量没到那个量级之前,天级分区是最稳的选择。
这条链路我后来在多个项目里复用,基本思路都是一样的:Kafka 源表用默认方言建,目标表用 HiveCatalog + Hive 方言建,分区提交走metastore策略,Checkpoint 稳定开启。只要这三条守住,Hive 客户端看不到数据的问题基本就不会再出现了。