技本功丨用短平快的方式告诉你:Flink-SQL的扩展实现 ...

本文介绍阿里云开源项目Blink对Flink-SQL进行扩展的具体实现,包括创建源表和输出表语句、自定义函数及维表关联等功能。通过这些扩展,简化了数据开发流程,提升了实时数据处理效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2019年1月28日,阿里云宣布开源“计算王牌”实时计算平台Blink。回馈给ApacheFlink社区。官方称,计算延迟已经降到毫秒级,也就是你在浏览网页的时候,眨了一下眼睛,淘宝、天猫处理的信息已经刷新了17亿次。

1

作为一家对技术有追求、有渴望的公司,怎么少得了为Flink社区做些贡献呢?

2

夫子说

首先,本文所述均基于flink 1.5.4。

我们为什么扩展Flink-SQL?

由于Flink 本身SQL语法并不提供在对接输入源和输出目的的SQL语法。数据开发在使用的过程中需要根据其提供的Api接口编写Source和 Sink, 异常繁琐,不仅需要了解FLink 各类Operator的API,还需要对各个组件的相关调用方式有了解(比如kafka,redis,mongo,hbase等),并且在需要关联到外部数据源的时候没有提供SQL相关的实现方式,因此数据开发直接使用Flink编写SQL作为实时的数据分析时需要较大的额外工作量。

我们的目的是在使用Flink-SQL的时候只需要关心做什么,而不需要关心怎么做。不需要过多的关心程序的实现,专注于业务逻辑。

接下来,我们一起来看下Flink-SQL的扩展实现吧!

01、扩展了哪些flink相关sql

(1)创建源表语句

3

(2)创建输出表语句

4

(3)创建自定义函数

5

(4)维表关联

6

02、各个模块是如何翻译到flink的实现

(1)如何将创建源表的sql语句转换为flink的operator;

Flink中表的都会映射到Table这个类。然后调用注册方法将Table注册到environment。
StreamTableEnvironment.registerTable(tableName, table);
当前我们只支持kafka数据源。Flink本身有读取kafka 的实现类, FlinkKafkaConsumer09,所以只需要根据指定参数实例化出该对象。并调用注册方法注册即可。

另外需要注意在flink sql经常会需要用到rowtime, proctime, 所以我们在注册表结构的时候额外添加rowtime,proctime。
当需要用到rowtime的使用需要额外指定DataStream.watermarks(assignTimestampsAndWatermarks),自定义watermark主要做两个事情:1:如何从Row中获取时间字段。 2:设定最大延迟时间。

( 2 ) 如何将创建的输出表sql语句转换为flink的operator;

Flink输出Operator的基类是OutputFormat, 我们这里继承的是RichOutputFormat, 该抽象类继承OutputFormat,额外实现了获取运行环境的方法getRuntimeContext(), 方便于我们之后自定义metric等操作。

我们以输出到mysql插件mysql-sink为例,分两部分:
将create table 解析出表名称,字段信息,mysql连接信息。
该部分使用正则表达式的方式将create table 语句转换为内部的一个实现类。该类存储了表名称,字段信息,插件类型,插件连接信息。
继承RichOutputFormat将数据写到对应的外部数据源。
主要是实现writeRecord方法,在mysql插件中其实就是调用jdbc 实现插入或者更新方法。

(3)如何将自定义函数语句转换为flink的operator;

Flink对udf提供两种类型的实现方式:
(1)继承ScalarFunction
(2)继承TableFunction
需要做的将用户提供的jar添加到URLClassLoader, 并加载指定的class (实现上述接口的类路径),然后调用TableEnvironment.registerFunction(funcName, udfFunc);即完成了udf的注册。之后即可使用改定义的udf;

( 4 ) 维表功能是如何实现的?

流计算中一个常见的需求就是为数据流补齐字段。因为数据采集端采集到的数据往往比较有限,在做数据分析之前,就要先将所需的维度信息补全,但是当前flink并未提供join外部数据源的SQL功能。

实现该功能需要注意的几个问题:
(1)维表的数据是不断变化的
在实现的时候需要支持定时更新内存中的缓存的外部数据源,比如使用LRU等策略。
(2)IO吞吐问题
如果每接收到一条数据就串行到外部数据源去获取对应的关联记录的话,网络延迟将会是系统最大的瓶颈。这里我们选择阿里贡献给flink社区的算子RichAsyncFunction。该算子使用异步的方式从外部数据源获取数据,大大减少了花费在网络请求上的时间。
(3)如何将sql 中包含的维表解析到flink operator
为了从sql中解析出指定的维表和过滤条件, 使用正则明显不是一个合适的办法。需要匹配各种可能性。将是一个无穷无尽的过程。查看flink本身对sql的解析。它使用了calcite做为sql解析的工作。将sql解析出一个语法树,通过迭代的方式,搜索到对应的维表;然后将维表和非维表结构分开。

7

通过上述步骤可以通过SQL完成常用的从kafka源表,join外部数据源,写入到指定的外部目的结构中。

Starting Job Manager [ERROR] The execution result is empty. [ERROR] Could not get JVM parameters and dynamic configurations properly. [ERROR] Raw output from BashJavaUtils: INFO [] - Using standard YAML parser to load flink configuration file from /opt/flink/conf/config.yaml. ERROR [] - Failed to parse YAML configuration org.snakeyaml.engine.v2.exceptions.YamlEngineException: expected '<document start>', but found '<scalar>' in reader, line 1, column 9 at org.snakeyaml.engine.v2.parser.ParserImpl$ParseDocumentStart.produce(ParserImpl.java:493) ~[flink-dist-2.0.0.jar:2.0.0] at org.snakeyaml.engine.v2.parser.ParserImpl.lambda$produce$1(ParserImpl.java:232) ~[flink-dist-2.0.0.jar:2.0.0] at java.util.Optional.ifPresent(Unknown Source) ~[?:?] at org.snakeyaml.engine.v2.parser.ParserImpl.produce(ParserImpl.java:232) ~[flink-dist-2.0.0.jar:2.0.0] at org.snakeyaml.engine.v2.parser.ParserImpl.peekEvent(ParserImpl.java:206) ~[flink-dist-2.0.0.jar:2.0.0] at org.snakeyaml.engine.v2.parser.ParserImpl.checkEvent(ParserImpl.java:198) ~[flink-dist-2.0.0.jar:2.0.0] at org.snakeyaml.engine.v2.composer.Composer.getSingleNode(Composer.java:131) ~[flink-dist-2.0.0.jar:2.0.0] at org.snakeyaml.engine.v2.api.Load.loadOne(Load.java:110) ~[flink-dist-2.0.0.jar:2.0.0] at org.snakeyaml.engine.v2.api.Load.loadFromInputStream(Load.java:123) ~[flink-dist-2.0.0.jar:2.0.0] at org.apache.flink.configuration.YamlParserUtils.loadYamlFile(YamlParserUtils.java:100) [flink-dist-2.0.0.jar:2.0.0] at org.apache.flink.configuration.GlobalConfiguration.loadYAMLResource(GlobalConfiguration.java:252) [flink-dist-2.0.0.jar:2.0.0] at org.apache.flink.configuration.GlobalConfiguration.loadConfiguration(GlobalConfiguration.java:150) [flink-dist-2.0.0.jar:2.0.0] at org.apache.flink.runtime.util.ConfigurationParserUtils.loadCommonConfiguration(ConfigurationParserUtils.java:153) [flink-dist-2.0.0.jar:2.0.0] at org.apache.flink.runtime.util.bash.FlinkConfigLoader.loadConfiguration(FlinkConfigLoader.java:41) [flink-dist-2.0.0.jar:2.24.1] at org.apache.flink.runtime.util.bash.BashJavaUtils.runCommand(BashJavaUtils.java:66) [bash-java-utils.jar:2.24.1] at org.apache.flink.runtime.util.bash.BashJavaUtils.main(BashJavaUtils.java:54) [bash-java-utils.jar:2.24.1] Exception in thread "main" java.lang.RuntimeException: Error parsing YAML configuration. at org.apache.flink.configuration.GlobalConfiguration.loadYAMLResource(GlobalConfiguration.java:257) at org.apache.flink.configuration.GlobalConfiguration.loadConfiguration(GlobalConfiguration.java:150) at org.apache.flink.runtime.util.ConfigurationParserUtils.loadCommonConfiguration(ConfigurationParserUtils.java:153) at org.apache.flink.runtime.util.bash.FlinkConfigLoader.loadConfiguration(FlinkConfigLoader.java:41)--- services: kafka-0: image: apache/kafka:3.9.1 container_name: kafka-0 ports: - "19092:9092" - "19093:9093" environment: KAFKA_NODE_ID: 1 KAFKA_PROCESS_ROLES: broker,controller KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:19093 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:19092,CONTROLLER://localhost:19093 KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_LOG_DIRS: /var/lib/kafka/data KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" volumes: - ./kafka/conf/log4j.properties:/opt/kafka/config/log4j.properties - ./kafka/0/conf/kraft/server.properties:/opt/kafka/config/kraft/server.properties - ./kafka/0/data:/var/lib/kafka/data command: - sh - -c - > if [ ! -f /var/lib/kafka/data/meta.properties ]; then # 生成随机 UUID 并格式化存储(-c 指定配置文件路径) /opt/kafka/bin/kafka-storage.sh format \ -t $(/opt/kafka/bin/kafka-storage.sh random-uuid) \ -c /opt/kafka/config/kraft/server.properties fi exec /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties healthcheck: test: - CMD - kafka-broker-api-versions.sh - --bootstrap-server - localhost:19092 interval: 10s timeout: 10s retries: 5 networks: - datacamp-net flink-jobmanager-0: image: flink:2.0.0-java17 container_name: flink-jobmanager-0 ports: - "18081:8081" environment: FLINK_PROPERTIES: | jobmanager.rpc.address: flink-jobmanager-0 state.backend: filesystem state.checkpoints.dir: file:///tmp/flink-checkpoints heartbeat.interval: 1000 heartbeat.timeout: 5000 rest.flamegraph.enabled: true web.upload.dir: /opt/flink/usrlib volumes: - ./flink/jobmanager/conf:/opt/flink/conf - ./flink/jobmanager/0/flink-checkpoints:/tmp/flink-checkpoints - ./flink/jobmanager/0/usrlib:/opt/flink/usrlib command: jobmanager healthcheck: test: - CMD - curl - -f - http://localhost:8081 interval: 15s timeout: 5s retries: 10 networks: - datacamp-net flink-taskmanager-0: image: flink:2.0.0-java17 container_name: flink-taskmanager-0 environment: FLINK_PROPERTIES: | jobmanager.rpc.address: flink-jobmanager-0 taskmanager.numberOfTaskSlots: 2 state.backend: filesystem state.checkpoints.dir: file:///tmp/flink-checkpoints heartbeat.interval: 1000 heartbeat.timeout: 5000 volumes: - ./flink/taskmanager/conf:/opt/flink/conf - ./flink/taskmanager/0/flink-checkpoints:/tmp/flink-checkpoints - ./flink/taskmanager/0/usrlib:/opt/flink/usrlib command: taskmanager depends_on: flink-jobmanager-0: condition: service_healthy networks: - datacamp-net flink-taskmanager-1: image: flink:2.0.0-java17 container_name: flink-taskmanager-1 environment: FLINK_PROPERTIES: | jobmanager.rpc.address: flink-jobmanager-0 taskmanager.numberOfTaskSlots: 2 state.backend: filesystem state.checkpoints.dir: file:///tmp/flink-checkpoints heartbeat.interval: 1000 heartbeat.timeout: 5000 volumes: - ./flink/taskmanager/conf:/opt/flink/conf - ./flink/taskmanager/1/flink-checkpoints:/tmp/flink-checkpoints - ./flink/taskmanager/1/usrlib:/opt/flink/usrlib command: taskmanager depends_on: flink-jobmanager-0: condition: service_healthy networks: - datacamp-net networks: datacamp-net: driver: bridge
最新发布
06-01
<think>好的,我现在需要帮助用户解决FlinkJobManager启动时遇到的YAML配置文件解析错误的问题。用户提到了YamlEngineException,具体是“expected '<document start>', butfound '<scalar>'”这个错误,发生在SnakeYAML解析过程中。我需要先分析可能的原因,然后逐步给出解决方案。首先,用户的问题可能出在YAML文件的格式上。YAML对缩进、冒号、特殊字符等有严格的要求。常见的错误包括缩进使用了Tab而不是空格,键名后缺少冒号后的空格,或者值中包含未转义的特殊字符。例如,用户可能在配置中写了类似`parallelism:10`而没有空格,或者路径中包含冒号未正确转义。接下来,我需要考虑JVM参数的配置是否正确。Flink的配置中,尤其是JVM参数部分,如果使用多行参数,需要用正确的YAML多行语法,比如使用`>-`来折叠多行内容,避免因为换行导致的解析错误。此外,用户可能错误地嵌套了配置项,比如将`java.opts.jobmanager`写成多级嵌套的结构,而实际上应该在同一层级下。 然后,动态配置部分,比如使用`configuration`节点下的参数,需要确保这些参数的键是正确的,并且值符合Flink的预期格式。例如,时间间隔参数需要加上单位,如`5min`,而数值参数则不需要引号,但涉及特殊字符时需要引号包裹。特殊字符的处理也是一个重点。比如在路径中出现的冒号,在Windows和Linux下可能需要不同的转义方式。用户可能在配置文件中直接写了包含冒号的路径而没有转义,导致解析器误认为是YAML的结构符号。 调试和验证方面,用户可能需要使用YAMLLint这样的工具来检查配置文件的基本语法。此外,启动Flink时添加调试参数,如`-Dyamllint.debug=true`,可以输出更详细的日志,帮助定位问题所在。最后,提供一个完整的正确配置示例会有助于用户对照检查自己的文件。例如,展示正确的缩进、JVM参数的多行写法、特殊字符的转义方法等,让用户能够直观地看到问题所在并进行修正。 在生成相关问题的时候,我需要围绕用户可能遇到的后续问题,比如如何验证配置生效、处理特殊符号密码、Kubernetes环境下的配置差异,以及监控JVM参数的方法。这些问题都是用户在解决当前错误后可能会进一步需要了解的,因此需要提前考虑并提供指引。</think>### Flink YAML配置文件解析错误的深度解决方案 #### 1. 基础语法错误排查 - **缩进问题**:YAML要求严格使用空格缩进,且每级缩进推荐2个空格[^1]。错误示例: ```yaml taskmanager: memory.process.size: 4096m # ❌使用Tab缩进 ``` 正确写法应使用空格: ```yaml taskmanager: memory.process.size: 4096m # ✅ ``` - **冒号处理规范**:键值对必须使用`key: value`格式,冒号后必须加空格。数学表达式参数需特别注意: ```yaml state.ttl: 3600000 # ✅正确 state.ttl:3.6e6 # ❌错误(冒号后无空格) ``` #### 2. JVM参数配置解析 - **多行参数的正确写法**: ```yaml env.java.opts.jobmanager: >- -Xmx$8g$ -XX:+UseG1GC -Dlog4j.configuration=file:///opt/flink/conf/log4j.properties ``` 其中`$8g$`表示数学表达式变量,实际配置应写具体值如`8g` - **错误嵌套结构**: ```yaml env: java: opts: jobmanager: "-Xmx4g" # ❌错误层级结构 ``` 正确结构应为: ```yaml env.java.opts.jobmanager: "-Xmx4g" # ✅ ``` #### 3. 动态配置数学表达式处理 当配置参数包含数学表达式时,需用$符号包裹: ```yaml taskmanager.memory.flink.size: $2048*2$m # ✅公式写法 taskmanager.memory.flink.size: 4096m # ✅最终值 ``` 但实际配置中应直接使用计算结果值,因为Flink不支持运行时计算表达式[^2] #### 4. 特殊结构验证方法 - **YAML层级验证工具**: ```bash python3 -c 'import yaml; yaml.safe_load(open("config.yaml"))' ``` 此命令可快速检测YAML结构错误 - **Flink配置预检命令**: ```bash ./bin/flink check /opt/flink/conf/config.yaml ``` 输出结果示例: ``` Validating configuration... [SUCCESS] YAML syntax verification passed [WARNING] Unrecognized configuration key: 'parallelsim.default' ``` #### 5. 完整配置示例(含数学表达式) ```yaml # config.yaml jobmanager.rpc.address: "flink-master" taskmanager: numberOfTaskSlots: $4*2$ # 实际应直接写8 memory: flink.size: 4096m managed.fraction: 0.7 parallelism.default: 8 state.backend: rocksdb state.checkpoints.dir: "file:///checkpoints" ``` #### 6. 调试日志分析 在启动命令中添加调试参数: ```bash ./bin/start-cluster.sh -Dlog4j.configuration=file:///conf/log4j-debug.xml ``` 关键日志标识: ``` DEBUG org.apache.flink.configuration.GlobalConfiguration - Loading configuration from: /opt/flink/conf/config.yaml ERROR org.apache.flink.runtime.entrypoint.ClusterEntrypoint - Failed to parse YAML configuration at line 23 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值