flink使用StatementSet降低资源浪费

发布于:2024-07-01 ⋅ 阅读:(10) ⋅ 点赞:(0)

背景

项目中有很多ods层(mysql 通过cannal)kafka,需要对这些ods kakfa做一些etl操作后写入下一层的kafka(dwd层)。

一开始采用的是executeSql方式来执行每个ods→dwd层操作,即类似:

 def main(args: Array[String]): Unit = {
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv: StreamTableEnvironment = StreamTableEnvironment.create(env)
    val configuration: Configuration = tableEnv.getConfig.getConfiguration
 
    tableEnv.createTemporarySystemFunction("etl_handle", classOf[ETLFunction])
 
    // source/sink ddl
    tableEnv.executeSql(CREATE_DB_DDL)
    tableEnv.executeSql(SOURCE_KAFKA_ODS_TABLE1)
    tableEnv.executeSql(SINK_KAFKA_DWD_TABLE1)
    tableEnv.executeSql(SOURCE_KAFKA_ODS_TABLE2)
    tableEnv.executeSql(SINK_KAFKA_DWD_TABLE2)
    ....
 
    // insert dml,在insert语句中调用etl_handle进行预处理和写入
    tableEnv.executeSql(INSERT_DWD_TABLE1)
    tableEnv.executeSql(INSERT_DWD_TABLE2)
    ... 
}

当有多个ods->dwd操作放在同一个flink作业中时,发现这种方式会导致每次insert操作都是单独的DAG,非常消耗资源,特别是这些处理都是比较轻量级的,最好是能融合在同一个DAG中共享资源。

解决方案

查看flink文档:INSERT 语句 | Apache Flink

因此,可以采用statementset的方式,将不同insert sql进行分组执行,每组的insert sql会先被缓存到 StatementSet 中,并在StatementSet.execute() 方法被调用时,同一组的 insert sql(sink) 会被优化成一张DAG共用taskmanager,减少资源浪费,即类似:

def main(args: Array[String]): Unit = {
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv: StreamTableEnvironment = StreamTableEnvironment.create(env)
    val configuration: Configuration = tableEnv.getConfig.getConfiguration
 
    tableEnv.createTemporarySystemFunction("etl_handle", classOf[ETLFunction])
 
    // source/sink ddl
    tableEnv.executeSql(CREATE_DB_DDL)
    tableEnv.executeSql(SOURCE_KAFKA_ODS_TABLE1)
    tableEnv.executeSql(SINK_KAFKA_DWD_TABLE1)
    tableEnv.executeSql(SOURCE_KAFKA_ODS_TABLE2)
    tableEnv.executeSql(SINK_KAFKA_DWD_TABLE2)
    ....
 

     // insert dml
    tableEnv.createStatementSet()
      .addInsertSql(INSERT_DWD_TABLE1)
      .addInsertSql(INSERT_DWD_TABLE2)
      .addInsertSql(INSERT_DWD_TABLE3)
      .execute()
 
 
    tableEnv.createStatementSet()
      .addInsertSql(INSERT_DWD_TABLE4)
      .addInsertSql(INSERT_DWD_TABLE5)
      .addInsertSql(INSERT_DWD_TABLE6)
      .execute()
}

其他

如果是纯flink sql而不用data stream api,也是可以达到同样的效果的。