From f562bc85a8fd5fac6f30f71da8e536bd3ef15025 Mon Sep 17 00:00:00 2001 From: huanwei Date: Wed, 1 Mar 2023 17:31:16 +0800 Subject: [PATCH 1/4] =?UTF-8?q?[docs]=20=E8=B0=83=E6=95=B4fireframework?= =?UTF-8?q?=E7=9A=84=E4=B8=BB=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 241 ++++++++++++++++++++++++++---- docs/_sidebar.md | 53 +++++++ docs/img/fire-framework-logo.jpeg | Bin 0 -> 88766 bytes docs/index.html | 11 +- 4 files changed, 275 insertions(+), 30 deletions(-) create mode 100644 docs/_sidebar.md create mode 100644 docs/img/fire-framework-logo.jpeg diff --git a/docs/README.md b/docs/README.md index 80f57c7..aac8e79 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,55 +17,246 @@ specific language governing permissions and limitations under the License. --> +

+ + + +

+ star + fork +

+

-## 一、开发手册 +# Fire框架 -### 1.1 开发与发布 +  Fire框架是由**中通大数据**自主研发并开源的、专门用于进行**Spark**和**Flink**任务开发的大数据框架。该框架屏蔽技术细节,提供大量简易API帮助开发者更快的构建实时计算任务。同时Fire框架也内置了平台化的功能,用于与实时平台集成。基于Fire框架的任务在中通每天处理的数据量高达**几千亿以上**,覆盖了**Spark计算**(离线&实时)、**Flink计算**等众多计算场景。 -#### [1.1.1 框架集成](dev/integration.md) +## 一、就这么简单! -#### [1.1.2 参数配置](dev/config.md) +### 1.1 Flink开发示例 -#### [1.1.3 集群环境](dev/engine-env.md) +```scala +@Config( + """ + |state.checkpoints.num-retained=30 # 支持任意Flink调优参数、Fire框架参数、用户自定义参数等 + |state.checkpoints.dir=hdfs:///user/flink/checkpoint + |""") +@Hive("thrift://localhost:9083") // 配置连接到指定的hive +@Streaming(interval = 100, unaligned = true) // 100s做一次checkpoint,开启非对齐checkpoint +@Kafka(brokers = "localhost:9092", topics = "fire", groupId = "fire") +object FlinkDemo extends FlinkStreaming { -#### [1.1.4 任务发布](dev/deploy-script.md) + @Process + def kafkaSource: Unit = { + val dstream = this.fire.createKafkaDirectStream() // 使用api的方式消费kafka + sql("""create table statement ...""") + sql("""insert into statement ...""") + } +} +``` -### 1.3 数据源 +### 1.2 Spark开发示例 -#### [1.3.1 Kafka Connector](connector/kafka.md) +```scala +@Config( + """ + |spark.shuffle.compress=true # 支持任意Spark调优参数、Fire框架参数、用户自定义参数等 + |spark.ui.enabled=true + |""") +@Hive("thrift://localhost:9083") // 配置连接到指定的hive +@Streaming(interval = 100, maxRatePerPartition = 100) // 100s一个Streaming batch,并限制消费速率 +@Kafka(brokers = "localhost:9092", topics = "fire", groupId = "fire") +object SparkDemo extends SparkStreaming { -#### [1.3.2 RocketMQ Connector](connector/rocketmq.md) + @Process + def kafkaSource: Unit = { + val dstream = this.fire.createKafkaDirectStream() // 使用api的方式消费kafka + sql("""select * from xxx""").show() + } +} +``` -#### [1.3.3 Hive Connector](connector/hive.md) +***说明:structured streaming、spark core、flink sql、flink批任务均支持,代码结构与上述示例一致。*** -#### [1.3.4 HBase Connector](connector/hbase.md) +## *[二、开发文档](./docs/index.md)* -#### [1.3.5 JDBC Connector](connector/jdbc.md) +## 三、亮点多多! -#### [1.3.6 Oracle Connector](connector/oracle.md) +### 3.1 兼容主流版本 -#### [1.3.7 Clickhouse Connector](connector/clickhouse.md) +  fire框架适配了不同的spark与flink版本,支持spark2.x及以上所有版本,flink1.10及以上所有版本,支持基于scala2.11或scala2.12进行编译。 -#### [1.3.8 ADB Connector](connector/adb.md) +```shell +# 可根据实际需要选择不同的引擎版本进行fire框架的构建 +mvn clean install -DskipTests -Pspark-3.0 -Pflink-1.14 -Pscala-2.12 +``` -#### [1.3.9 Kudu Connector](#) +| Apache Spark | Apache Flink | +| ------------ | ------------ | +| 2.3.x | 1.12.x | +| 2.4.x | 1.13.x | +| 3.0.x | 1.14.x | +| 3.1.x | 1.15.x | +| 3.2.x | 1.16.x | +| 3.3.x | | -### [1.4 累加器](accumulator.md) +### **3.2 简单好用** -### [1.5 定时任务](schedule.md) +  Fire框架高度封装,屏蔽大量技术细节,许多connector仅需一行代码即可完成主要功能。同时Fire框架统一了spark与flink两大引擎常用的api,使用统一的代码风格即可实现spark与flink的代码开发。 -### [1.6 线程池与并发计算](threadpool.md) +- **HBase API** -### [1.7 Spark DataSource增强](datasource.md) +```scala +// 读取HBase中指定rowkey数据并将结果集封装为DataFrame返回 +val studentDF: DataFrame = this.fire.hbaseGetDF(hTableName, classOf[Student], getRDD) +// 将指定数据集分布式插入到指定HBase表中 +this.fire.hbasePutDF(hTableName, studentDF, classOf[Student]) +``` -## 二、实时平台建设 +- **JDBC API** -### [2.1 集成方案](platform.md) +1. **通过注解配置数据源:** -### [2.2 内置接口](restful.md) +```java +@Jdbc(url = "jdbc:mysql://mysql-server:3306/fire", username = "root", password = "root") +``` -## 三、配置与调优 +2. **Spark示例:** -### [3.1 Fire configuration](properties.md) +```scala +// 将DataFrame中指定几列插入到关系型数据库中,每100条一插入 +df.jdbcBatchUpdate(insertSql, Seq("name", "age", "createTime", "length", "sex"), batch = 100) +// 将查询结果通过反射映射到DataFrame中 +val df: DataFrame = this.fire.jdbcQueryDF(querySql, Seq(1, 2, 3), classOf[Student]) +``` + +3. **Flink示例:** + +```scala +val dstream = this.fire.createKafkaDirectStream().map(t => JSONUtils.parseObject[Student](t)) +val sql = +s""" +|insert into spark_test(name, age, createTime) values(?, ?, ?) +|ON DUPLICATE KEY UPDATE age=18 +|""".stripMargin +// sinkJdbc只需指定sql语句即可,fire会自动推断sql中占位符与JavaBean中成员变量的对应关系 +dstream.sinkJdbc(sql) +dstream.sinkJdbcExactlyOnce(sql, keyNum = 2) +``` + +### **3.3 灵活的配置方式** + +  支持基于接口、apollo、配置文件以及注解等多种方式配置,支持将spark&flink等**引擎参数**、**fire框架参数**以及**用户自定义参数**混合配置,支持运行时动态修改配置。几种常用配置方式如下([配置手册](./docs/config.md)): + +1. **基于配置文件:** 创建类名同名的properties文件进行参数配置 +2. **基于接口配置:** fire框架提供了配置接口调用,通过接口获取所需的配置,可用于平台化的配置管理 +3. **基于注解配置:** 通过注解的方式实现集群环境、connector、调优参数的配置,常用注解如下: + +```scala +@Config( + """ + |# 支持Flink调优参数、Fire框架参数、用户自定义参数等 + |state.checkpoints.num-retained=30 + |state.checkpoints.dir=hdfs:///user/flink/checkpoint + |""") +@Hive("thrift://localhost:9083") +@Checkpoint(interval = 100, unaligned = true) +@Kafka(brokers = "localhost:9092", topics = "fire", groupId = "fire") +@RocketMQ(brokers = "bigdata_test", topics = "fire", groupId = "fire", tag = "*", startingOffset = "latest") +@Jdbc(url = "jdbc:mysql://mysql-server:3306/fire", username = "root", password = "..root726") +@HBase("localhost:2181") +``` + +**配置获取:** + +  Fire框架封装了统一的配置获取api,基于该api,无论是spark还是flink,无论是在Driver | JobManager端还是在Executor | TaskManager端,都可以一行代码获取所需配置。这套配置获取api,无需再在flink的map等算子中复写open方法了,用起来十分方便。 + +```scala +this.conf.getString("my.conf") +this.conf.getInt("state.checkpoints.num-retained") +... +``` + +### **3.4 多集群支持** + +  Fire框架的配置支持N多集群,比如同一个任务中可以同时配置多个HBase、Kafka数据源,使用不同的数值后缀即可区分(**keyNum**): + +```scala +// 假设基于注解配置HBase多集群如下: +@HBase("localhost:2181") +@HBase2(cluster = "192.168.0.1:2181", storageLevel = "DISK_ONLY") + +// 代码中使用对应的数值后缀进行区分 +this.fire.hbasePutDF(hTableName, studentDF, classOf[Student]) // 默认keyNum=1,表示使用@HBase注解配置的集群信息 +this.fire.hbasePutDF(hTableName2, studentDF, classOf[Student], keyNum=2) // keyNum=2,表示使用@HBase2注解配置的集群信息 +``` + +### **3.5 常用connector支持** + +  支持kafka、rocketmq、redis、HBase、Jdbc、clickhouse、Hive、hudi、tidb、adb等常见的connector。 + +### **3.6 [checkpoint热修改](./docs/highlight/checkpoint.md)** + +  支持运行时动态调整checkpoint周期、超时时间、并行checkpoint等参数,避免任务重启时由于反压带来的checkpoint压力。 + +### **3.7 [streaming热重启](./docs/highlight/spark-duration.md)** + +  该功能是主要用于Spark Streaming任务,通过热重启技术,可以在不重启Spark Streaming的前提下,实现批次时间的热修改。比如在web端将某个任务的批次时间调整为10s,会立即生效。 + +### **3.8 配置热更新** + +  用户仅需在web页面中更新指定的配置信息,就可以让实时任务接收到最新的配置并且立即生效。最典型的应用场景是进行Spark任务的某个算子partition数调整,比如当任务处理的数据量较大时,可以通过该功能将repartition的具体分区数调大,会立即生效。 + +### **3.9 在线性能诊断** + +  深度集成Arthas,可对运行中的任务动态进行性能诊断。fire为arthas诊断提供rest接口,可通过接口调用的方式选择为driver、jobmanager或executor、taskmanager动态开启与关闭arthas诊断线程,然后向统一的arthas tunnel服务注册,即可在网页端输入arthas命令进行性能诊断。 + +![arthas-shell](docs/img/arthas-shell.png) + +### **3.10 sql在线调试** + +  Fire框架对外暴露了restful接口,平台等系统可通过接口调用的方式将待执行的sql语句动态传递给fire,由fire将sql提交到对应的引擎,并将sql执行结果通过接口调用的方式返回,实现实时任务sql开发的在线调试,避免重复修改代码发布执行带来的时间成本。 + +### **3.11 实时血缘** + +  Fire框架支持运行时统计分析每个任务所使用到的数据源信息、库表信息、操作类型等,并将这些血缘信息通过接口的方式对外暴露。实时平台等web系统通过接口调用的方式即可获取到实时血缘信息。 + +### **3.12 定时调度** + +  Fire框架内部封装了quartz框架,实现通过Scheduled注解即可完成定时任务的注册。 + +```scala + /** + * 声明了@Scheduled注解的方法是定时任务方法,会周期性执行 + * + * @scope 默认同时在driver端和executor端执行,如果指定了driver,则只在driver端定时执行 + * @initialDelay 延迟多长时间开始执行第一次定时任务 + */ + @Scheduled(cron = "0/5 * * * * ?", scope = "driver", initialDelay = 60000) + def loadTable: Unit = { + this.logger.info("更新维表动作") + } +``` + +### **3.13 平台无缝集成** + +  Fire框架内置restful服务,并将许多功能通过接口的方式对外暴露,实时平台可以通过fire框架暴露的接口实现与每个实时任务的信息连接。 + +### **3.14 fire-shell** + +  Fire框架整合spark shell与flink shell,支持通过REPL方式去动态调试spark和flink任务,并且支持fire框架的所有API。fire框架将shell能力通过接口方式暴露给实时平台,如此一来就可以通过web页面去调试spark和flink任务了。 + +## *[四、升级日志](./docs/feature.md)* + +## 五、期待你的加入 + +**社区技术交流:[*35373471(钉钉)*](https://qr.dingtalk.com/action/joingroup?code=v1,k1,yNUn3bjLGYXPHvzVapvFjI7H5LQReBVrksiECWH+WAI=&_dt_no_comment=1&origin=11)** + +**入群请备注:公司名称-岗位-昵称,否则不予理会** + +
+ + +
diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000..9185ee8 --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,53 @@ + + +- 一、开发手册 + + - 1.1 开发与发布 + + - [1.1.1 框架集成](dev/integration.md) + - [1.1.2 参数配置](dev/config.md) + - [1.1.3 集群环境](dev/engine-env.md) + - [1.1.4 任务发布](dev/deploy-script.md) + + - 1.3 数据源 + + - [1.3.1 Kafka Connector](connector/kafka.md) + - [1.3.2 RocketMQ Connector](connector/rocketmq.md) + - [1.3.3 Hive Connector](connector/hive.md) + - [1.3.4 HBase Connector](connector/hbase.md) + - [1.3.5 JDBC Connector](connector/jdbc.md) + - [1.3.6 Oracle Connector](connector/oracle.md) + - [1.3.7 Clickhouse Connector](connector/clickhouse.md) + - [1.3.8 ADB Connector](connector/adb.md) + - [1.3.9 Kudu Connector](#) + + - [1.4 累加器](accumulator.md) + - [1.5 定时任务](schedule.md) + - [1.6 线程池与并发计算](threadpool.md) + - [1.7 Spark DataSource增强](datasource.md) + +- 二、实时平台建设 + + - [2.1 集成方案](platform.md) + - [2.2 内置接口](restful.md) + +- 三、配置与调优 + + - [3.1 Fire configuration](properties.md) diff --git a/docs/img/fire-framework-logo.jpeg b/docs/img/fire-framework-logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9cfb3d988d102a12f85f5a53fd0712dc0a6177b0 GIT binary patch literal 88766 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 C37zQx literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html index 04dd4a7..5d594e3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,18 +2,19 @@ - Document + Fire Framework: Simplify your operations - + -

+
Please wait...
-- Gitee From 563c5c8dc14fd7635369a358332779fc5024133c Mon Sep 17 00:00:00 2001 From: huanwei Date: Wed, 1 Mar 2023 17:41:20 +0800 Subject: [PATCH 2/4] =?UTF-8?q?[docs]=20=E4=BF=AE=E5=A4=8D=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=B8=B2=E6=9F=93=E4=B8=8D=E5=87=BA=E6=9D=A5=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index aac8e79..75ac642 100644 --- a/docs/README.md +++ b/docs/README.md @@ -257,6 +257,6 @@ this.fire.hbasePutDF(hTableName2, studentDF, classOf[Student], keyNum=2) // keyN **入群请备注:公司名称-岗位-昵称,否则不予理会**
- - + +
-- Gitee From d21062004655c584ed99ae2cfc34e7d528c1adcb Mon Sep 17 00:00:00 2001 From: huanwei Date: Wed, 1 Mar 2023 17:44:49 +0800 Subject: [PATCH 3/4] =?UTF-8?q?[docs]=20=E4=BF=AE=E5=A4=8D=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E4=B8=8D=E6=98=BE=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 75ac642..c1ede05 100644 --- a/docs/README.md +++ b/docs/README.md @@ -213,7 +213,7 @@ this.fire.hbasePutDF(hTableName2, studentDF, classOf[Student], keyNum=2) // keyN   深度集成Arthas,可对运行中的任务动态进行性能诊断。fire为arthas诊断提供rest接口,可通过接口调用的方式选择为driver、jobmanager或executor、taskmanager动态开启与关闭arthas诊断线程,然后向统一的arthas tunnel服务注册,即可在网页端输入arthas命令进行性能诊断。 -![arthas-shell](docs/img/arthas-shell.png) +![arthas-shell](img/arthas-shell.png) ### **3.10 sql在线调试** -- Gitee From ea4508654d0742c3aef5a69f5a7d962b6ab2de42 Mon Sep 17 00:00:00 2001 From: huanwei Date: Wed, 1 Mar 2023 20:14:48 +0800 Subject: [PATCH 4/4] =?UTF-8?q?[fire][docs][optimize]=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E6=B8=B2=E6=9F=93=E5=92=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=B8=BB=E9=A1=B5=E7=9A=84=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 58 +++++++++++++++++++++++++++++++++++++++++-------- docs/index.html | 6 ++++- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/docs/README.md b/docs/README.md index c1ede05..55ad291 100644 --- a/docs/README.md +++ b/docs/README.md @@ -32,6 +32,36 @@ under the License.   Fire框架是由**中通大数据**自主研发并开源的、专门用于进行**Spark**和**Flink**任务开发的大数据框架。该框架屏蔽技术细节,提供大量简易API帮助开发者更快的构建实时计算任务。同时Fire框架也内置了平台化的功能,用于与实时平台集成。基于Fire框架的任务在中通每天处理的数据量高达**几千亿以上**,覆盖了**Spark计算**(离线&实时)、**Flink计算**等众多计算场景。 +--- + +## 摘要 + +!> 开发手册请看侧边栏提供的详情哦! + +* [一、就这么简单!](#一就这么简单) + * [1\.1 Flink开发示例](#11-flink开发示例) + * [1\.2 Spark开发示例](#12-spark开发示例) +* [二、开发文档](#二开发文档) +* [三、亮点多多!](#三亮点多多) + * [3\.1 兼容主流版本](#31-兼容主流版本) + * [3\.2 简单好用](#32-简单好用) + * [3\.3 灵活的配置方式](#33-灵活的配置方式) + * [3\.4 多集群支持](#34-多集群支持) + * [3\.5 常用connector支持](#35-常用connector支持) + * [3\.6 checkpoint热修改](#36-checkpoint热修改) + * [3\.7 streaming热重启](#37-streaming热重启) + * [3\.8 配置热更新](#38-配置热更新) + * [3\.9 在线性能诊断](#39-在线性能诊断) + * [3\.10 sql在线调试](#310-sql在线调试) + * [3\.11 实时血缘](#311-实时血缘) + * [3\.12 定时调度](#312-定时调度) + * [3\.13 平台无缝集成](#313-平台无缝集成) + * [3\.14 fire\-shell](#314-fire-shell) +* [四、升级日志](#四升级日志) +* [五、期待你的加入](#五期待你的加入) + +--- + ## 一、就这么简单! ### 1.1 Flink开发示例 @@ -77,17 +107,23 @@ object SparkDemo extends SparkStreaming { } ``` -***说明:structured streaming、spark core、flink sql、flink批任务均支持,代码结构与上述示例一致。*** +!> 说明:structured streaming、spark core、flink sql、flink批任务均支持,代码结构与上述示例一致。 + +--- + +## *[二、开发文档](./index.md)* -## *[二、开发文档](./docs/index.md)* +!> 开发手册请看侧边栏提供的详情哦! + +--- ## 三、亮点多多! ### 3.1 兼容主流版本 -  fire框架适配了不同的spark与flink版本,支持spark2.x及以上所有版本,flink1.10及以上所有版本,支持基于scala2.11或scala2.12进行编译。 + fire框架适配了不同的spark与flink版本,支持spark2.x及以上所有版本,flink1.10及以上所有版本,支持基于scala2.11或scala2.12进行编译。 -```shell +```bash # 可根据实际需要选择不同的引擎版本进行fire框架的构建 mvn clean install -DskipTests -Pspark-3.0 -Pflink-1.14 -Pscala-2.12 ``` @@ -197,11 +233,11 @@ this.fire.hbasePutDF(hTableName2, studentDF, classOf[Student], keyNum=2) // keyN   支持kafka、rocketmq、redis、HBase、Jdbc、clickhouse、Hive、hudi、tidb、adb等常见的connector。 -### **3.6 [checkpoint热修改](./docs/highlight/checkpoint.md)** +### **3.6 [checkpoint热修改](highlight/checkpoint.md)**   支持运行时动态调整checkpoint周期、超时时间、并行checkpoint等参数,避免任务重启时由于反压带来的checkpoint压力。 -### **3.7 [streaming热重启](./docs/highlight/spark-duration.md)** +### **3.7 [streaming热重启](highlight/spark-duration.md)**   该功能是主要用于Spark Streaming任务,通过热重启技术,可以在不重启Spark Streaming的前提下,实现批次时间的热修改。比如在web端将某个任务的批次时间调整为10s,会立即生效。 @@ -248,13 +284,17 @@ this.fire.hbasePutDF(hTableName2, studentDF, classOf[Student], keyNum=2) // keyN   Fire框架整合spark shell与flink shell,支持通过REPL方式去动态调试spark和flink任务,并且支持fire框架的所有API。fire框架将shell能力通过接口方式暴露给实时平台,如此一来就可以通过web页面去调试spark和flink任务了。 -## *[四、升级日志](./docs/feature.md)* +--- + +## *[四、升级日志](feature.md)* + +--- ## 五、期待你的加入 -**社区技术交流:[*35373471(钉钉)*](https://qr.dingtalk.com/action/joingroup?code=v1,k1,yNUn3bjLGYXPHvzVapvFjI7H5LQReBVrksiECWH+WAI=&_dt_no_comment=1&origin=11)** +!> 社区技术交流:[*35373471(钉钉)*](https://qr.dingtalk.com/action/joingroup?code=v1,k1,yNUn3bjLGYXPHvzVapvFjI7H5LQReBVrksiECWH+WAI=&_dt_no_comment=1&origin=11) -**入群请备注:公司名称-岗位-昵称,否则不予理会** +!> 入群请备注:公司名称-岗位-昵称,否则不予理会
diff --git a/docs/index.html b/docs/index.html index 5d594e3..8bb21b5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -14,10 +14,14 @@ window.$docsify = { name: 'Fire Framework', repo: 'https://gitee.com/fire-framework/fire.git', - loadSidebar: true + loadSidebar: true, + logo: './img/fire-framework-logo.jpeg' } + + + -- Gitee