flink sql 实战实例 及延伸问题:聚合/数据倾斜/DAU/Hive流批一体 等

Flink SQL 在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理。当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如:在过去的1分钟内有多少用户点击了我们的网页。在这种情况下,我们必须定义一个窗口,用来收集最近一分钟内的数据,并对这个窗口内的数据进行计算。Flink 认为 Batch 是 Streaming 的一个特例,所以 Flink 底层引擎是一个流式引擎,在上面实现了流处理和批处理。而窗口(window)就是从 Streaming 到 Batch 的一个桥梁。 阅读详情

Flink SQL max问题讨论

假如有一张客服打分表,3个字段客服id :staff_id,用户id: user_id ,用户评分:score,我现在要求 每个用户的最大评分,这个sql要怎么写,相信很简答是吧

select staff_id,max(score)
from table
group by staff_id

假如 数据有两条
1001,小明,80
1001,小红,90

得出的结果肯定是 90

那么 此时,假如小红做了修改 把评分改为了 70分,那么最终结果是什么呢
这个问题其实就是最根本的,流式数据中,聚合函数的边界问题,这个max的边界到底是什么?
他的边界就是所有未过期的,flink中保存的state中的数据集,也就是说 如果状态没过期,他会把 90 回撤 ,重新计算出新结果 80 ,然后下发。如果过期了 ,就会重新计算所有数据,也就是一个70,得出一个70的结果 然后下发。

Flink SQL 计算用户分布

⭐ 需求:上游是一个 kafka 数据源,数据内容是用户 QQ 等级变化明细数据(time,uid,level)。需要你求出当前每个等级的用户数。

- 如果需要可以打开 minibatch
select  
    level
    , count(1) as uv
    , max(time) as time
from (
    select 
        uid
        , level
        , time
        , row_number() over (partition by uid order by time desc) rn 
    from source
) tmp
where rn =1 
group by 
    level

Flink SQL 计算 DAU

⭐ 需求:数据源:用户心跳日志(uid,time,type)。计算分 Android,iOS 的 DAU,最晚一分钟输出一次当日零点累计到当前的结果。

SELECT  
    window_start
    , window_end
    , platform
    , sum(bucket_dau) as dau
from (
    SELECT
        window_start
        , window_end
        , platform
        , count(distinct uid) as bucket_dau
    FROM TABLE(
        CUMULATE(
        TABLE user_log,
        DESCRIPTOR(time),
        INTERVAL '60' SECOND
        , INTERVAL '1' DAY))
    GROUP BY                                  
        window_start
        , window_end
        , platform
        , MOD(HASH_CODE(user_id), 1024)
) tmp
GROUP by   
    window_start
    , window_end
    , platform

优点:如果是曲线图的需求,可以完美回溯曲线图。
缺点:大窗口之间如果有数据乱序,有丢数风险;并且由于是 watermark 推动产出,所以数据产出会有延迟。








或或或或或或或或或或或或或或或或或或或或或或或
-- 如果需要可以打开 minibatch
select 
    platform
    , count(1) as dau
    , max(time) as time
from (
    select 
        uid
        , platform
        , time
        , row_number() over (partition by uid, platform, time / 24 / 3600 / 1000 order by time desc) rn
    from source
) tmp
where rn = 1
group by
    platform
 优点:计算快。
 缺点:任务发生 failover,曲线图不能很好回溯。没法支持 cube 计算。




或或或或或或或或或或或或或或或或或或或或或或或
-- 如果需要可以打开 minibatch
SELECT   
    max(time) as time
    , platform
    , sum(bucket_dau) as dau
from (
    SELECT
        max(time) as time
        , platform
        , count(distinct uid) as bucket_dau
    FROM source
    GROUP BY
        platform
        , MOD(HASH_CODE(user_id), 1024)
) t 
GROUP by   
    platform
    
优点:计算快,支持 cube 计算。
缺点:任务发生 failover,曲线图不能很好回溯。

    

多topic 数据更新mysql topic接入mysql

-- 作业开发逻辑

 -- mysql -h数据库 -ubigdata_rw -pe20ycoy3yp09qij0kj8ngpcgxyywgmc9
 -- -Dyarn.application.queue=stream_data   -Dyarn.provided.lib.dirs=/streamx/flink/flink-1.12.5/lib/
CREATE TABLE Direction_Wind_create_source (

       properties ROW< area VARCHAR,comment_count BIGINT,share_count BIGINT,like_count BIGINT,user_id  VARCHAR,app_id BIGINT,feed_type BIGINT ,feed_id VARCHAR,`timestamp` VARCHAR >
,    proctime AS PROCTIME()
 ) WITH (
        'connector.type' = 'kafka',
        'connector.version' = 'universal',
        'connector.topic' = 'Direction_Wind_create_feed',
        'connector.properties.bootstrap.servers'='Direction_Wind-hadoop-hdp-kafka-01:9092,Direction_Wind-hadoop-hdp-kafka-02:9092,Direction_Wind-hadoop-hdp-kafka-03:9092',
        'connector.startup-mode' = 'latest-offset',
        'update-mode' = 'append',
        'format.type' = 'json',
        'connector.properties.group.id' = 'dynamicRelease_bigdata_Direction_Wind_sql_test',
        'format.derive-schema' = 'true'
 );

 CREATE TABLE Direction_Wind_like_source (
       properties ROW< area VARCHAR,comment_count BIGINT,share_count BIGINT,like_count BIGINT,user_id  VARCHAR,app_id BIGINT,feed_type BIGINT ,feed_id VARCHAR,`timestamp` VARCHAR >
,    proctime AS PROCTIME()
 ) WITH (
        'connector.type' = 'kafka',
        'connector.version' = 'universal',
        'connector.topic' = 'Direction_Wind_like_feed',
        'connector.properties.bootstrap.servers'='Direction_Wind-hadoop-hdp-kafka-01:9092,Direction_Wind-hadoop-hdp-kafka-02:9092,Direction_Wind-hadoop-hdp-kafka-03:9092',
        'connector.startup-mode' = 'latest-offset',
        'update-mode' = 'append',
        'format.type' = 'json',
        'connector.properties.group.id' = 'dynamicRelease_bigdata_Direction_Wind_sql_test',
        'format.derive-schema' = 'true'
 );

 CREATE TABLE Direction_Wind_comment_source (

       properties ROW< area VARCHAR,comment_count BIGINT,share_count BIGINT,like_count BIGINT,user_id  VARCHAR,app_id BIGINT,feed_type BIGINT ,feed_id VARCHAR,`timestamp` VARCHAR >
,    proctime AS PROCTIME()
 ) WITH (
        'connector.type' = 'kafka',
        'connector.version' = 'universal',
        'connector.topic' = 'Direction_Wind_comment_feed',
        'connector.properties.bootstrap.servers'='Direction_Wind-hadoop-hdp-kafka-01:9092,Direction_Wind-hadoop-hdp-kafka-02:9092,Direction_Wind-hadoop-hdp-kafka-03:9092',
        'connector.startup-mode' = 'latest-offset',
        'update-mode' = 'append',
        'format.type' = 'json',
        'connector.properties.group.id' = 'dynamicRelease_bigdata_Direction_Wind_sql_test',
        'format.derive-schema' = 'true'
 );


 CREATE TABLE Direction_Wind_share_source (

       properties ROW< area VARCHAR,comment_count BIGINT,share_count BIGINT,like_count BIGINT,user_id  VARCHAR,app_id BIGINT,feed_type BIGINT ,feed_id VARCHAR,`timestamp` VARCHAR >
,    proctime AS PROCTIME()
 ) WITH (
        'connector.type' = 'kafka',
        'connector.version' = 'universal',
        'connector.topic' = 'Direction_Wind_share_feed',
        'connector.properties.bootstrap.servers'='Direction_Wind-hadoop-hdp-kafka-01:9092,Direction_Wind-hadoop-hdp-kafka-02:9092,Direction_Wind-hadoop-hdp-kafka-03:9092',
        'connector.startup-mode' = 'latest-offset',
        'update-mode' = 'append',
        'format.type' = 'json',
        'connector.properties.group.id' = 'dynamicRelease_bigdata_Direction_Wind_sql_test',
        'format.derive-schema' = 'true'
 );




CREATE TABLE Direction_Wind_create_sink (
  feed_id VARCHAR
  ,user_id VARCHAR
  ,feed_type VARCHAR
  ,time_stamp timestamp(3)
  ,area VARCHAR
  , PRIMARY KEY (feed_id) NOT ENFORCED
 ) WITH (
        'connector.type' = 'jdbc',
        'connector.url' = 'jdbc:mysql://数据库:3306/bireport?useUnicode=true&characterEncoding=UTF-8&useSSL=false',
        'connector.用户' = 'bigdata_all',
        'connector.pass@word' = '密码',
                'connector.table' = 'Direction_Wind_dynamic_test',

        'connector.write.flush.max-rows' = '1',
        'connector.write.flush.interval' = '2s'
       --  'connector' = 'print'
 );

INSERT INTO Direction_Wind_create_sink
select * from (
SELECT  properties.feed_id as feed_id
        ,properties.user_id as user_id
        ,cast(properties.feed_type as varchar) as feed_type
       --  ,TO_DATE(properties.`timestamp`) as time_stamp
       ,TO_TIMESTAMP(FROM_UNIXTIME(cast(properties.`timestamp` as bigint))) as time_stamp
        ,properties.area  as area
        ,ROW_NUMBER() OVER (PARTITION BY properties.feed_id ORDER BY properties.`timestamp` asc) as rowNum
FROM    Direction_Wind_create_source
) where rowNum = 1
;


CREATE TABLE Direction_Wind_like_sink (
  feed_id VARCHAR
  ,like_count BIGINT
  ,feed_type VARCHAR
  ,area VARCHAR
  , PRIMARY KEY (feed_id) NOT ENFORCED
 ) WITH (
        'connector.type' = 'jdbc',
        'connector.url' = 'jdbc:mysql://数据库:3306/bireport?useUnicode=true&characterEncoding=UTF-8&useSSL=false',
        'connector.用户' = 'bigdata_all',
        'connector.pass@word' = '密码',
        'connector.table' = 'Direction_Wind_dynamic_test',
                'connector.write.flush.max-rows' = '1',
        'connector.write.flush.interval' = '2s'
       --  'connector' = 'print'
 );


INSERT INTO Direction_Wind_like_sink
select * from (
SELECT  properties.feed_id as feed_id
        ,properties.like_count  as like_count
        ,cast(properties.feed_type as varchar) as feed_type
        ,properties.area  as area
                ,ROW_NUMBER() OVER (PARTITION BY properties.feed_id ORDER BY properties.`timestamp` asc) as rowNum
FROM    Direction_Wind_like_source
) where rowNum = 1
;




CREATE TABLE Direction_Wind_comment_sink (
  feed_id VARCHAR
  ,comment_count BIGINT
  ,feed_type VARCHAR
  ,area VARCHAR
  , PRIMARY KEY (feed_id) NOT ENFORCED
 ) WITH (
        'connector.type' = 'jdbc',
        'connector.url' = 'jdbc:mysql://数据库:3306/bireport?useUnicode=true&characterEncoding=UTF-8&useSSL=false',
        'connector.用户' = 'bigdata_all',
        'connector.pass@word' = '密码',
        'connector.table' = 'Direction_Wind_dynamic_test',
                'connector.write.flush.max-rows' = '1',
        'connector.write.flush.interval' = '2s'
       --  'connector' = 'print'
 );


INSERT INTO Direction_Wind_comment_sink
select * from (
SELECT  properties.feed_id as feed_id
        ,properties.comment_count  as comment_count
        ,cast(properties.feed_type as varchar) as feed_type
        ,properties.area  as area
        ,ROW_NUMBER() OVER (PARTITION BY properties.feed_id ORDER BY properties.`timestamp` asc) as rowNum
FROM    Direction_Wind_comment_source
) where rowNum = 1
;





CREATE TABLE Direction_Wind_share_sink (
  feed_id VARCHAR
  ,use_count BIGINT
  ,feed_type VARCHAR
  ,area VARCHAR
  , PRIMARY KEY (feed_id) NOT ENFORCED
 ) WITH (
        'connector.type' = 'jdbc',
        'connector.url' = 'jdbc:mysql://数据库:3306/bireport?useUnicode=true&characterEncoding=UTF-8&useSSL=false',
        'connector.用户' = 'bigdata_all',
        'connector.pass@word' = '密码',
        'connector.table' = 'Direction_Wind_dynamic_test',
                'connector.write.flush.max-rows' = '1',
        'connector.write.flush.interval' = '2s'
       --  'connector' = 'print'
 );


INSERT INTO Direction_Wind_share_sink
select * from (
SELECT  properties.feed_id as feed_id
        ,properties.share_count  as   use_count
        ,cast(properties.feed_type as varchar) as feed_type
        ,properties.area  as area
        ,ROW_NUMBER() OVER (PARTITION BY properties.feed_id ORDER BY properties.`timestamp` asc) as rowNum
FROM    Direction_Wind_share_source
) where rowNum = 1
;
这里要注意,如果去重直接用group by的方式,在批处理中还好,流式处理中,这部分数据会存放到内容中,并且越积越大,没有ttl,时间一长就会oom了,
Flink SQL Deduplicate 写法,row_number partition by user_id order by proctime asc,此 SQL 最后生成的算子只会在第一条数据来的时候更新 state,后续访问不会更新 state TTL,因此 state 会在用户设置的 state TTL 时间之后过期。  所以按理说 这种去重方式 不会百分百 有用,只能保持一段时间的 去重,感觉是不对的,正在测试中。






经过测试 在flink 1.12 版本时,flinksql的upsert into 功能 ,也就是 这种写法
在这里插入图片描述
是可以实现 update 功能的,但 必须要 group by 数据才行,并且要求把 把所有select 语句中的字段 都加入到 group by 语句,但这么写,又会导致 state 不停增大,过一段时间就会 OOM

引入 upsert-kafka-connector 以1.14.4版本为例

基本工作机制:

  • source:

在这里插入图片描述

  • sink:
    在这里插入图片描述
tenv.executeSql(
    "CREATE TABLE upsert_kafka ("
        + "province STRING, "
        + "pv BIGINT, "
        + "PRIMARY KEY (province) NOT ENFORCED"
        + ") WITH ("
        + "'connector' = 'upsert-kafka', "
        + "'topic' = 'upsert_kafka2', "
        + "'properties.bootstrap.servers' = 'doitedu:9092', "
        + "'key.format' = 'csv', "
        + "'value.format' = 'csv'"
        + ")"
);

DataStreamSource<Row> stream = env.fromElements(
    Row.ofKind(RowKind.INSERT, "sx", 1),
    Row.ofKind(RowKind.INSERT, "sx", 2),
    Row.ofKind(RowKind.INSERT, "gx", 1),
    Row.ofKind(RowKind.INSERT, "sx", 2),
    Row.ofKind(RowKind.INSERT, "gx", 2)
);

tenv.createTemporaryView("s", stream, Schema.newBuilder()
    .column("f0", DataTypes.STRING().notNull())
    .column("f1", DataTypes.INT())
    .build());
// 将查询结果(changelog 流),写入 kafka
tenv.executeSql("insert into upsert_kafka select f0, sum(f1) as pv from s group by f0");

写入的数据为
在这里插入图片描述

// 从 kafka 再读出上面的 changelog 结果 tenv.executeSql(" select * from upsert_kafka").print();
tenv.executeSql("select * from upsert_kafka").print();

读出的数据为
在这里插入图片描述

数据倾斜问题:

⭐ 场景:拿计算直播间的同时在线观看用户数来说,大 v 直播间的人数会比小直播间的任务多几个量级,因此如果计算一个直播间的数据需要注意这种业务数据倾斜的特点
⭐ 解决方案:计算这种数据时,我们可以先按照直播间 id 将数据进行打散,如下 SQL 案例所示(DataStream 也是相同的解决方案),内层打散,外层合并:

select 
    id
    , sum(bucket_uv) as uv
from (
    select 
        id
        , count(distinct uid) as bucket_uv 
    from source 
    group by
        id
        , mod(uid, 1000) -- 将大 v 分桶打散
)
group by id

⭐ 数据任务处理时参数\代码处理逻辑导致倾斜:
⭐ 场景:比如有时候虽然用户已经按照 key 进行分桶计算,但是【最大并发度】设置为 150,【并发度】设置为 100,会导致 keygroup 在 sub-task 的划分不均匀(其中 50 个 sub-task 的 keygroup 为 2 个,剩下的 50 个 sub-task 为 1 个)导致数据倾斜。
⭐ 解决方案:设置合理的【最大并发度】【并发度】,【最大并发度】最好为【并发度】的倍数关系,比如【最大并发度】1024,【并发度】512
⭐ 我已经设置【数据分桶打散】+【最大并发为并发 n 倍】,为啥还出现数据倾斜?
⭐ 场景:你的【数据分桶】和【最大并发数】之间可能是不均匀的。因为 Flink 会将 keyby 的 key 拿到之后计算 hash 值,然后根据 hash 值去决定发送到那个 sub-task 去计算。这是就有可能出现你的【数据分桶】key 经过 hash 计算完成之后,并不能均匀的发到所有的 keygroup 中。比如【最大并发数】4096,【数据分桶】key 只有 1024 个,那么这些数据必然最多只能到 1024 个 keygroup 中,有可能还少于 1024,从而导致剩下的 3072 个 keygroup 没有任何数据
⭐ 解决方案:其实可以利用【数据分桶】key 和【最大并行度】两个参数,在 keyby 中实现和 Flink key hash 选择 keygroup 的算法一致的算法,在【最大并发数】4096,【数据分桶】为 4096 时,做到分桶值为 1 的数据一定会发送到 keygroup1 中,2 一定会发到 keygroup2 中,从而缓解数据倾斜。

最大并行度的设置:最大并行度可以自己设置,也可以框架默认生成;默认的算法是取当前算子并行度的 1.5 倍和 2 的 7 次方比较,取两者之间的最大值,然后用上面的结果和 2 的 15 次方比较,取其中的最小值为默认的最大并行度,非常不建议自动生成,建议用户自己设置。

flinksql 流流+流维join乱序问题

如果A流 join 维表B, 再join流C ,下游会出现乱序问题
可能由于A流数据变更 -U +U 点查B表时,谁先获取结果不一定,所以下游接受到的数据是乱序的

让你使用用户心跳日志(20s 上报一次)计算同时在线用户、DAU 指标,你怎么设计链路?

在这里插入图片描述
⭐ 有提到将用户上线标记为 1,下线标记为 0 的,然后将上线下线数据发到消息队列用实时计算引擎统计的

⭐ 有提到将用户心跳日志借助 Session Window Dynamic Gap 计算的

在这里插入图片描述

多维高阶聚合

在这里插入图片描述

FlinkSql Upsert 与 Primary Key

在flink1.11 及以后,flinksql 与blink 做了merge 所以有重大变更
流计算的一个典型场景是把聚合的数据写入到 Upsert Sink 中,比如 JDBC、HBase,当遇到复杂的 SQL 时,时常会出现:
在这里插入图片描述
UpsertStreamTableSink 需要上游的 Query 有完整的 Primary Key 信息,不然就直接抛异常。这个现象涉及到 Flink 的 UpsertStreamTableSink 机制。顾名思义,它是一个更新的 Sink,需要按 Key 来更新,所以必须要有 Key 信息。

如何发现 Primary Key?一个方法是让优化器从 Query 中推断,如下图发现 Primary Key 的例子。

这种情况下在简单 Query 当中很好,也满足语义,也非常自然。但是如果是一个复杂的 Query,比如聚合又 Join 再聚合,那就只有报错了。不能期待优化器有多智能,很多情况它都不能推断出 PK,而且,可能业务的 SQL 本身就不能推断出 PK,所以导致了这样的异常。

在这里插入图片描述
怎么解决问题?Flink 1.11 彻底的抛弃了这个机制,不再从 Query 来推断 PK 了,而是完全依赖 Create table 语法。比如 Create 一个 jdbc_table,需要在定义中显式地写好 Primary Key(后面 NOT ENFORCED 的意思是不强校验,因为 Connector 也许没有具备 PK 的强校验的能力)。当指定了 PK,就相当于就告诉框架这个Jdbc Sink 会按照对应的 Key 来进行更新。如此,就跟 Query 完全没有关系了,这样的设计可以定义得非常清晰,如何更新完全按照设置的定义来。

CREATE TABLE jdbc_table (
    id BIGINT,
    ...
    PRIMARY KEY (id) NOT ENFORCED
)

flinksql Hive 流批一体

首先看传统的 Hive 数仓。一个典型的 Hive 数仓如下图所示。一般来说,ETL 使用调度工具来调度作业,比如作业每天调度一次或者每小时调度一次。这里的调度,其实也是一个叠加的延迟。调度产生 Table1,再产生 Table2,再调度产生 Table3,计算延时需要叠加起来
在这里插入图片描述
问题是慢,延迟大,并且 Ad-hoc 分析延迟也比较大,因为前面的数据入库,或者前面的调度的 ETL 会有很大的延迟。Ad-hoc 分析再快返回,看到的也是历史数据。

所以现在流行构建实时数仓,从 Kafka 读计算写入 Kafka,最后再输出到 BI DB,BI DB 提供实时的数据服务,可以实时查询。Kafka 的 ETL 为实时作业,它的延时甚至可能达到毫秒级。实时数仓依赖 Queue,它的所有数据存储都是基于 Queue 或者实时数据库,这样实时性很好,延时低。但是:

第一,基于 Queue,一般来说就是行存加 Queue,存储效率其实不高。
第二,基于预计算,最终会落到 BI DB,已经是聚合好的数据了,没有历史数据。而且 Kafka 存的一般来说都是 15 天以内的数据,没有历史数据,意味着无法进行 Ad-hoc 分析。所有的分析全是预定义好的,必须要起对应的实时作业,且写到 DB 中,这样才可用。对比来说,Hive 数仓的好处在于它可以进行 Ad-hoc 分析,想要什么结果,就可以随时得到什么结果。
在这里插入图片描述
能否结合离线数仓和实时数仓两者的优势,然后构建一个 Lambda 的架构?

核心问题在于成本过高。无论是维护成本、计算成本还是存储成本等都很高。并且两边的数据还要保持一致性,离线数仓写完 Hive 数仓、SQL,然后实时数仓也要写完相应 SQL,将造成大量的重复开发。还可能存在团队上分为离线团队和实时团队,两个团队之间的沟通、迁移、对数据等将带来大量人力成本。如今,实时分析会越来越多,不断的发生迁移,导致重复开发的成本也越来越高。少部分重要的作业尚可接受,如果是大量的作业,维护成本其实是非常大的。

如何既享受 Ad-hoc 的好处,又能实现实时化的优势?一种思路是将 Hive 的离线数仓进行实时化,就算不能毫秒级的实时,准实时也好。所以,Flink 1.11 在 Hive 流批一体上做了一些探索和尝试,如下图所示。它能实时地按 Streaming 的方式来导出数据,写到 BI DB 中,并且这套系统也可以用分析计算框架来进行 Ad-hoc 的分析。这个图当中,最重要的就是 Flink Streaming 的导入。
在这里插入图片描述

Streaming Sink

早期 Flink 版本在 DataStreaming 层,已经有一个强大的 StreamingFileSink 将流数据写到文件系统。它是一个准实时的、Exactly-once 的系统,能实现一条数据不多,一条数据不少的 Sink。
在这里插入图片描述
具体原理是基于两阶段提交:

第一阶段:SnapshotPerTask,关闭需要 Commit 的文件,或者记录正在写的文件的 Offset。
第二阶段:NotifyCheckpointComplete,Rename 需要 Commit 的文件。注意,Rename 是一个原子且幂等的操作,所以只要保证 Rename 的 At-least-once,即可保证数据的 Exactly-once。

这样一个 File system 的 Writer 看似比较完美了。但是在 Hive 数仓中,数据的可见性是依赖 Hive Metastore 的,那在这个流程中,谁来通知 Hive Metastore 呢?
在这里插入图片描述
SQL 层在 StreamingFileSink,扩展了 Partition 的 Committer。

相当于不仅要进行 File 的 Commit,还要进行 Partition 的 Commit。如图所示,FileWriter 对应之前的 StreamingFileSink,它提供的是 Exactly-once 的 FileWriter。而后面再接了一个节点 PartitionCommitter。支持的 Commit Policy 有:

  • 内置支持 Add partition 到 Hive metastore;
  • 支持写 SuccessFile 到文件系统当中;
  • 并且也可以自定义 Committer,比如可以 analysis partition、合并 partition 里面的小文件。

Committer 挂在 Writer 后, 由 Commit Trigger 决定什么时机来 commit :

  • 默认的 commit 时机是,有文件就立即 commit。因为所有 commit 都是可重入的,所以这一点是可允许的。

  • 另外,也支持通过 partition 时间和 Watermark 来共同决定的。比如小时分区,如果现在时间到 11 点,10 点的分区就可以 commit 了。Watermark 保证了作业当前的准确性。

Streaming Source

Hive 数仓中存在大量的 ETL 任务,这些任务往往是通过调度工具来周期性的运行,这样做主要有两个问题:

  • 实时性不强,往往调度最小也是小时级。
  • 流程复杂,组件多,容易出现问题。

针对这些离线的 ETL 作业,Flink 1.11 为此开发了实时化的 Hive 流读,支持:

  • Partition 表,监控 Partition 的生成,增量读取新的 Partition。
  • 非 Partition 表,监控文件夹内新文件的生成,增量读取新的文件。

甚至可以使用 10 分钟级别的分区策略,使用 Flink 的 Hive streaming source 和 Hive streaming sink ,可以大大提高 Hive 数仓的实时性到准实时分钟级,在实时化的同时,也支持针对 Table 全量的 Ad-hoc 查询,提高灵活性。

SELECT * FROM hive_table /*+ OPTIONS('streaming-source.enable'=’true’, 'streaming-source.consume-start-offset'='2020-05-20') */;


/*+ OPTIONS('streaming-source.enable' = 'true','streaming-source.partition.include' = 'latest',
            'streaming-source.partition-order' = 'create-time','streaming-source.monitor-interval' = '1 h') */

另外除了 Scan 的读取方式,Flink 1.11 也支持了 Temporal Join 的方式,也就是以前常说的 Streaming Dim Join。

SELECT
  o.amout, o.currency, r.rate, o.amount * r.rate
FROM
  Orders AS o
  JOIN LatestRates FOR SYSTEM_TIME AS OF o.proctime AS r
  ON r.currency = o.currency

目前支持的方式是 Cache All,并且是不感知分区的,比较适合小表的情况。

Hive Dialect

Flink SQL 遵循的是 ANSI-SQL 的标准,而 Hive SQL 有它自己的 HQL 语法,它们之间的语法、语义都有些许不同。

如何让 Hive 用户迁移到 Flink 生态中,同时避免用户太大的学习成本?为此, Flink SQL 1.11 提供了 Hive Dialect,可以使得用户在 Flink 生态中使用 HQL 语言来计算。目前只支持 DDL,后续版本会逐步攻坚 Qeuries。

Filesystem Connector

Hive Integration 提供了一个重量级的集成,功能丰富,但是环境比较复杂。如果只是想要一个轻量级的 Filesystem 读写呢?

Flink table 在长久以来只支持一个 CSV 的 Filesystem Table,并且还不支持 Partition,行为上在某些方面也有些不符合大数据计算的直觉。

Flink 1.11 重构了整个 Filesystem connector 的实现:

  • 结合 Partition,现在,Filesystem connector 支持 SQL 中 Partition 的所有语义,支持 Partition 的 DDL,支持 Partition Pruning,支持静态 / 动态 Partition 的插入,支持 Overwrite 的插入。
  • 支持各种 Formats: ■ CSV ■ JSON ■ Aparch AVRO ■ Apache Parquet ■ Apache ORC
  • 支持 Batch 的读写。
  • 支持 Streaming sink,也支持 Partition commit,支持写 Success 文件。

用几句简单的 SQL,不用搭建 Hive 集成环境即可:

  • 启动一个流作业写入 Filesystem 中,然后在 Hive 端即可查询到 Filesystem 上的数据,相比之前 Datastream 的作业,简单 SQL 即可搞定离线数据的入库。
  • 通过 Filesystem Connector 来查询 Hive 数仓中的数据,功能没有 Hive 集成那么全,但是定义简单。

常用参数

– state ttl机制
set state.retention.time.min=15d;
set state.retention.time.max=20d;
set execution.checkpointing.mode=exactly_once;
set execution.checkpointing.interval=6min;
– 超时时间
set execution.checkpointing.timeout=30min;
set execution.checkpointing.min-pause=0ms;

– 开启sql hit语法支持
set table.dynamic-table-options.enabled=true;
– checkpoint容忍失败次数
set execution.checkpointing.tolerable-failed-checkpoints=0;
– 设置时区
set table.local-time-zone=Asia/Shanghai;
set execution.type = streaming;
– hive
set hive.enable=true;
– rank结果保持输出
set table.exec.fast.retractable.top1=true;

set table.exec.mini-batch.enabled=true;
set table.exec.mini-batch.allow-latency=1000;
set table.exec.mini-batch.size=200;
– set table.exec.source.cdc-events-duplicate=true;
set table.exec.sink.drops=UPDATE_BEFORE;
– 参数名字配置
set table.optimizer.simplify-operator-name-enabled=true;

常用配置

broadcastjoin 查询 解决数据倾斜(图片后面应该是+*)

在这里插入图片描述
yarn.provided.lib.dirs=hdfs://zjyprc-hadoop/user/s_flink/metric-group-restore-test2
slot.request.timeout=360000
yarn.provided.lib.dirs=hdfs://zjyprc-hadoop/user/s_flink/cdc-connector-test
execution.backup-task-finished-fail-enabled=false
execution.checkpointing.checkpoints-after-tasks-finish.enabled=true
taskmanager.memory.jvm-overhead.fraction=0.3
state.backend.latency-track.keyed-state-enabled=true
state.backend.rocksdb.native-metrics-enabled=true

开启增量ck
set execution.checkpointing.incremental=true
– state ttl机制
set state.retention.time.min=15d;
set state.retention.time.max=20d;
set execution.checkpointing.mode=exactly_once;
set execution.checkpointing.interval=10min;
– 超时时间
set execution.checkpointing.timeout=60min;
set execution.checkpointing.min-pause=10min;
set execution.checkpointing.incremental=true

– 开启sql hit语法支持
set table.dynamic-table-options.enabled=true;
– checkpoint容忍失败次数
set execution.checkpointing.tolerable-failed-checkpoints=0;
– 设置时区
set table.local-time-zone=Asia/Shanghai;
set execution.type = streaming;
– hive
set hive.enable=true;

set table.exec.mini-batch.enabled=true;
set table.exec.mini-batch.allow-latency=1000;
set table.exec.mini-batch.size=2000;
– SET pipeline.operator-chaining=false;

常用方法

炸裂函数: lateral table(explode(split(replace(replace(bg_trn_reson,‘]’,‘’),‘[’,‘’),‘,’))) as t(rs)
字符串拼接: array_join(sort_array(collect_distinct_list(c.reson_lv2_name)), ‘,’) as reson_lv2_name

多维聚合实战:从SQL GROUP BY到OLAP立方体的工程化落地 多维聚合是现代数据分析的核心能力,本质是支持在多个业务维度(如时间、地域、产品)上对度量指标(如销售额、用户数)进行灵活切片、钻取与交叉分析。其技术原理源于OLAP立方体模型,通过维度建模分离分析逻辑与计算逻辑,实现可复用、可扩展、低延迟的聚合能力。相比传统GROUP BY的静态降维,多维聚合具备动态上卷/下钻、热点预计算与实时补算融合等工程优势,广泛应用于BI自助分析、实时用户行为洞察及风控标签体系构建等场景。本文聚焦多维聚合在SQL、Pandas与Polars中的落地实践,覆盖维度建模、GROUPING 阅读详情

相关推荐

机器学习系统工程:从模型训练到生产落地的闭环实践

机器学习系统(ML Systems)是将算法能力转化为稳定业务价值的关键工程范式,其核心在于构建可监控、可回滚、可追溯的数据-特征-模型-反馈闭环。不同于传统软件或纯算法开发,它强调特征一致性、数据漂移检测、在线服务SLA保障与跨角色协作契约。随着企业级AI应用深化,Feature Store、Delta Lake、Triton Serving等技术组合成为支撑高可用特征服务与模型推理的基础设施标配。本文聚焦真实生产挑战——如特征偏移、时区不一致、服务雪崩与模型OOM——提炼出覆盖数据层、特征层、模型层和服

weixin_34195546的博客 505

flink sql实战案例

flink sql实战案例

chimchim66的博客 2485

大数据处理利器:Flink Table 与 SQL 实战案例

其中,Table API 提供了一种基于关系型表格的编程模型,使得开发人员可以使用类似 SQL 的语法来处理数据。本文将介绍如何使用 Flink 的 Table API 和 SQL 来进行数据处理,并提供相应的源代码。本文介绍了如何使用 Flink 的 Table API 和 SQL 来进行大数据处理,并提供了相应的案例代码。通过使用 Flink 的高级功能和易于使用的编程模型,开发人员可以快速构建强大的数据处理应用程序。首先,我们需要创建一个新的 Flink 程序,并导入所需的依赖库。

AlianBlank的博客 208

flink-sql大量使用案例

本文是 flink sql 的一些使用案例,同时也包括了一些特殊用法展示。

第一片心意的博客 8153

(十四)基于 Flink SQL 应用案例

在 11.11 购物节大促活动中,天猫、京东等商家会对外发布购物节对应的交易金额、单量等信息,下面我们以 2023.11.11 购物节大促为背景,完成任务指标计算

springk的专栏 766

电商数据分析19——数据分析在电商平台价格弹性研究中的应用

价格弹性是一个衡量产品价格变化对销量影响的经济学指标,对于电商平台而言,深入理解和有效运用价格弹性,对于制定竞争策略、优化产品定价具有重要意义。随着大数据时代的到来,通过数据分析研究产品的价格弹性,成为了电商企业制定价格策略、调整市场定位、优化促销活动的重要依据。

theskylife的博客 2836

多维聚合实战:维度建模、度量规则与数据变形链路

多维聚合是BI分析与实时数仓的核心能力,本质是围绕维度层级结构和度量聚合性质进行的数据状态转换。理解维度拓扑(如树状层级vs交叉维度)、识别度量类型(可加/半可加/不可加)并设计合理变形链路,直接决定报表的准确性与可解释性。本文聚焦真实生产环境中的关键挑战——包括GROUP BY误用、HAVING与WHERE混淆、窗口函数跨维计算失真、稀疏维度补全及动态时间窗口实现,并覆盖Pandas、Spark SQL与ClickHouse在不同数据规模下的最优实践。内容深度融合维度建模方法论与工程落地细节,为数据工程师

weixin_30328063的博客 448

基于Android Studio的校园智能点餐系统开发实战(附完整源码与部署指南)

本文详细介绍了基于Android Studio开发校园智能点餐系统的完整流程,包括需求分析、环境搭建、数据库设计、客户端与后台功能实现。系统采用SSM框架和MySQL数据库,解决了校园食堂高峰期排队问题,提供高效的点餐体验。附完整源码与部署指南,助力开发者快速构建类似应用。

weixin_29015801的博客 561

Flink SQL 的 9 个示例

作者:贺小令(晓令) 本文由阿里巴巴技术专家贺小令分享,社区志愿者郑仲尼整理。文章基于 Flink 1.9 版本,从用户的角度来讲解 Flink 1.9 版本中 SQL 相关原理及部分功能变更,希望对大家有所帮助。主要内容分享以下三个部分: TableEnvironment 的设计与使用场景 Catalog 的设计以及 DDL 实践 Blink Planner 的几点重要改进及优化 Tab...

阿里云开发者 5774

LVDS系列11:Xilinx Ultrascale系可编程输入延迟(一)

按照IDELAYCTRL的参考时钟频率可以准确计算获取到,如200M参考时钟抽头分辨率为78ps,Ultrascale系列相对于7系列架构大改,体现便是U/U+系列的抽头增加到512个,同时每个抽头的分辨率就无法像7系列那样能得到一个准确的值,是一个波动的范围值,抽头分辨率随着工艺温度电压的变化而变化。EN_VTC:电压温度补偿开启的使用信号,COUNT模式下不能使用,必须保持为0,TIME模式下需要使用,在延迟工作时要启用温度电压补偿,在修改抽头值时需要关闭温度电压补偿,修改完后启用;

weixin_38828382的博客 1942

从零开始:IBM V3700控制器更换与机器代码升级全流程指南

本文详细介绍了IBM V3700存储系统控制器更换与机器代码升级的全流程指南。从前期准备、硬件更换到版本同步,逐步解析如何应对503错误等常见问题,确保系统稳定运行。通过实战案例和优化建议,帮助工程师高效完成维护任务,提升存储系统可用性。

weixin_28365523的博客 312

Flink SQL实现流批一体

1 Flink流批统一思想 1.1 有界流和无界流 在Flink中,批处理时流处理的一个特例。 1.2 Flink老架构与问题 1.从Flink用户角度(企业开发人员) (1)开发的时候,Flink SQL支持的不好,就需要在两个底层API中进行选择,甚至维护两套代码。 (2)不同的语义、不同的connector支持、不同的错误恢复策略等。 (3)Table API也会受不同的底层API、不同的connector等问题的影响。 2.从Flink开发者角度(Flink社区人员)

大数据研习社 8261

【已解决】App unavailable Unfortunately, Claude is only available in certain countries and regions

App unavailable Unfortunately, Claude is only available in certain countries and regions right now. We will soon publish a list of supported locations on our website.

weixin_43941438的博客 3万+

Flink之SQL client使用案例

s(--slots):每个TaskManager的slot数量,默认一个slot一个core,默认每个taskmanager的slot的个数为1,有时可以多一些taskmanager,做冗余。# 在提交n次事务后,进行binlog的落盘,0为不进行强行的刷新操作,而是由文件系统控制刷新日志文件,如果是在线交易和账有>关的数据建议设置成1,如果是其他数据可以保持为0即可。所以该错误可以忽略。Per-Job Mode:单作业模式,我们也是更多的使用这种模式,这个模式会将我们的资源更合理的规划使用。

zxcvbnm0207的博客 2883

效果炸裂_安装midscene_copw基于midscene操作电脑_基于视觉的软件测试执行_MIDSCENE的安装和使用---AI大模型应用探索0012

摘要:本文介绍了如何通过安装MidSceneJS来增强Copaw的屏幕操作能力。首先需要安装Node.js和npm,并配置淘宝镜像源加速安装。然后全局安装MidScene CLI工具(npm install @midscene/cli -g)。接着配置视觉大模型服务,通过设置环境变量指定模型API密钥、名称、基础URL和家族类型(如qwen3.5-27b),配置文件需存放在C:\Users\Administrator.copaw目录。安装成功后,MidScene已能成功识别并操作屏幕,使用效果良好。文中还提

添柴程序猿的专栏 644

为Ollama本地大模型添加持久化记忆层:openclaw-ollama-memory项目详解

在构建基于大型语言模型(LLM)的对话应用时,上下文管理是核心技术挑战之一。其原理在于模型本身不具备跨会话的持久化记忆能力,每次请求都是独立的。这导致在多轮对话中,模型无法有效利用历史信息,用户体验割裂。从技术价值看,独立的记忆层通过解耦推理与存储,能突破模型固定上下文窗口的限制,实现更智能、连贯的交互。其核心应用场景包括聊天机器人、智能助手及需要长期记忆的复杂代理。本文聚焦的 openclaw-ollama-memory 项目,正是为 Ollama 生态提供的记忆层解决方案,它通过向量检索和智能摘要等机制

weixin_42521558的博客 313

【Flink SQL】Flink SQL 语法篇(四):Group 聚合、Over 聚合

Group 聚合定义(支持 Batch / Streaming 任务):Flink 也支持 Group 聚合。Group 聚合和上面介绍到的窗口聚合的不同之处,就在于 Group 聚合是按照数据的类别进行分组,比如年龄、性别,是横向的;而窗口聚合是在时间粒度上对数据进行分组,是纵向的。如下图所示,就展示出了其区别。其中按颜色分 key(横向)就是Group 聚合,按窗口划分(纵向)就是窗口聚合。

Data · Model · Agent · Repeat 3720

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Flink高手之路4-Flink流批一体

env.fromElements(可变参数)env.fromCollection(各种集合)env.generateSequence(开始,结束)env.fromSequence(开始,结束SourceFunction:非并行的随机数据源(并行度为1)RichSourceFunction:丰富的非并行的随机数据源(并行度为1)ParallelSourceFunction:并行的随机数据源(并行度可以大于等于1)

W_chuanqi的博客 2379

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

flink sql 案例

好的。 Flink SQL是一种用于编写和执行Flink程序的语言。它允许用户使用SQL语法从多个来源获取数据并进行转换和处理,然后将结果写入到多个目标。 下面是一个简单的Flink SQL案例: 假设我们有一个名为"user_events"的表,其中包含用户ID和用户事件(如点击或购买)。我们希望每小时计算出每个用户的事件总数。 我们可以使用以下Flink SQL查询实现此目的: SELECT ...

weixin_42600128的博客 312

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Flink系列之:深入理解ttl和checkpoint,Flink SQL应用ttl案例

通过保存作业状态的快照,Flink能够保证作业的一致性,并提供了高可用性和高效率的保存和恢复机制。冷启动和部署:可以使用检查点来实现作业的冷启动,即在作业启动时,从最近的检查点恢复状态和数据,并从上一次检查点的位置继续处理。当窗口中的数据过期时,Flink会自动丢弃这些数据,从而保持窗口中的数据只包含最新的和有效的内容。容错和故障恢复:Checkpoint可以将作业的状态和数据进行持久化,当发生故障时,Flink可以使用最近的检查点来恢复作业的状态和数据,从而避免数据丢失,并继续处理未完成的任务。

zhengzaifeidelushang的博客 4480

1.19.10.Flink SQL工程案例\Flink批式处理\自定义函数\Window窗口计算\将DataSet数据转成Table数据\将Table数据转成DataSet等

1.19.10.Flink SQL工程案例 1.19.10.1.编写Pom.xml文件 1.19.10.2.java案例 1.19.10.3.案例1:Flink批式处理(建表、查询、插入、jdbc connector的使用) 1.19.10.4.案例2:StreamTableEnvironment的使用案例+数据模拟+自定义函数及其应用 1.19.10.5.案例3:StreamTableEnvironment应用+blink/Flink SQL应用 1.19.10.6.案例4:Flink SQL之Strea

涂作权的博客 2133

Flink 系例之 SQL 案例 - 订单统计

示例,对电商实时订单进行聚合计算,分以下两个维度进行:1. 统计每 1 分钟的订单数量、用户数量、销售额、商品数;2. 统计每个分类的订单总数量、用户总数量(未去重)、销售额、商品数

不会飞的小龙人的博客 3610

深入解读 Flink SQL 1.13

摘要:本文由社区志愿者陈政羽整理,Apache Flink 社区在 5 月份发布了 1.13 版本,带来了很多新的变化。文章整理自徐榜江(雪尽)5 月 22 日在北京的 Flink Me...

Ververica的博客 2045
上一篇: 一种基于动态水位值的Flink调度优化算法(flink1.5以前),等同于实现flink的Credit-based反压原理
下一篇: Flink Task退出流程与Failover机制
Direction_Wind
博客等级 码龄8年 6438粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Direction_Wind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值