写点什么

什么是 Flink SQL 解决不了的问题?

  • 2024-07-09
    北京
  • 本文字数:1667 字

    阅读完需:约 5 分钟

简介

在实时数据开发过程中,大家经常会用 Flink SQL 或者 Flink DataStream API 来做数据加工。通常情况下选用 2 者都能加工出想要的数据,但是总会有 Flink SQL 覆盖不了的问题,但 SQL 的易用性又难以让人释怀。所以有些场景在使用 FLink SQL 开始就与需要额外注意,下面就介绍一种多表关联时存在部分列更新(partial Update)场景,在 DataStream API 和 Flink SQL 开发时都容易忽视的情况而导致的问题。为了简化问题描述,采用了 Flink SQL 来阐述此类问题。

场景介绍

多表关联时表 A 关联表 B, 表 A 具有 pk1, field1, field2, field3 字段,表 B 具有 pk2, field4, field5, field6 字段,表 A 通过 pk1 关联表 B pk2。使用 Flink SQL 会如下实现:


CREATE TABLE jdq_source(pk1 INT,field1 STIRNG,field2 STIRNG,field3 STIRNG,PRIMARY KEY(pk1) NOT ENFORCED) WITH(...);
CREATE TABLE sr_sink(pk1 INT,field1 STRING,field2 STRING,field3 STRING,field4 STRING,field5 STRING,field6 STRING,PRIMARY KEY(pk2) NOT ENFORCED) WITH (...);
INSERT INTO CSELECT A.pk1,A.field1,A.field2,A.field3,B.pk2,B.field4,B.field5,B.field6 FROM jdq_source AINNER JOIN sr_sink BON A.pk1 = B.pk2;
复制代码


上述实例中有明显特征:使用了 Join 关联, 且需要注意的是写入的数据库 sink 是 StarRocks。StarRocks 存在如下特性:当表是主键表时是不支持部分列更新( Partial Update)的,实际上大部分时候大家都用的是主键表。


然后在一个 SQL 查询数据的接口就遇到了如下问题:每次从接口查询返回的结果都不稳定,同样的查询条件不同时机返回的结果不一样。SQL 查询语句如下:


select C.field1,C.field2,C.field3FROM C group by field1,field2,field3;
复制代码


为什么SQL查询的结果会不一致呢?起初排查原因发现 group by 返回结果有多条,而在SQL 中也没有使用 order by 对数据进行排序,所以导致了结果不稳定。后又排查为什么会出现多条结果呢?于是怀疑 field1, field2, field3 有不符合预期的数据。如: 
复制代码


20240530, 2, 3


20240530, 2, null


20240531, 2, 4


其中第 2 条是多余的,不应该出现。结果发现可能是如下原因导致的:这 3 个字段 filed1, field2, filed3 在 StarRocks 数据库中会一直在变化,不停的写入新值。导致 SQL 查询时可以查到 field3 为 null 的数据。


为什么 field3 为不断变化呢?究其原因是:StarRocks 主键表不支持部分列更新(Partial Update)。当 field3 为 null 时,同样会被写入 StarRocks。我们在通过 JDQ 读取表 A field1, field2, field3 数据给表 C 写入数据时,当 JDQ 消息队列中表 A 的记录存在乱序场景且 field3 字段可能为 null 时,最终写入 StarRocks 的 field3 字段会出现时而为 null,时而不为 null。 所以 SQL 查询接口中 group by 的结果会出现不稳定。

总结

  1. 为什么在开发的时候当时没有发现 StarRocks 主键表这个问题呢?原因:1. 大家所关注的部分列更新,多数是关注 insert into table_C(field1, field2, field3) 中不包含的字段 field4,field5...等被更新为 null,而当前场景是会把 field3 为 null 的值也写入 SR 数据库中,这不是我们期望的结果。2.表 A 作为主表,通常不会出现开始 field3 有值后来又没有值(null)的场景。出现这个现象大概率是因为上游 JDQ 消息队列中的数据乱序了,导致 field3 为 null 的后出现了。而这种问题又比较难发现。

  2. 什么情况下会出现此类问题呢?写入的数据库不支持部分列更新场景时会出现。如 StarRocks, Doris。因为 MySQL, ES,ClickHouse 的部分表引擎支持部分列更新,所以在 MySQL, ES,ClickHouse 中不会出现。

  3. 同理在 DataStream API 中如果表 A,表 B 关联后的数据直接写入 StarRocks 的话,也会出现此类问题。

  4. 以上这个问题在 Flink SQL 中无法解决,在 Flink DataStream API 中可以模拟部分列更新来避免此类问题。具体方法:在 DatStream 任务中增加一个 MapState, 用来在新数据到来时从 MapState 拿出缓存的数据,并和新到来的数据进行合并,来实现部分列更新功能,最后再写入 StarRocks。

  5. 虽然问题不是 Flink SQL 导致的,但是上面的问题可以通过 Flink DataStream API 来规避。

发布于: 19 分钟前阅读数: 5
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
什么是 Flink SQL 解决不了的问题?_京东科技开发者_InfoQ写作社区