中通又一个承载千亿级流量平台开源啦!!!

WilliamGates
发布于 2023-2-14 11:38
浏览
0收藏

从JDK5开始,Java提供了注解新特性,随后,注解如雨后春笋般被大量应用到各种开发框架中,其中,最具代表的是Spring。

在注解出现以前,Spring的配置通常需要写到xml中。基于xml配置,有着十分繁琐,难以记忆,容易出错等弊端。Spring开发者也意识到了这个问题,于是开始引入大量的注解,让注解替代传统的xml配置。

到了大数据时代,以Hadoop、Spark、Flink为代表的分布式计算引擎先后横空出世。相信很多从事过Java Web开发工作的人一开始都不太习惯这几款开发框架提供的API,这几款框架也不约而同的放弃注解特性。可能很多大数据开发者都或多或少的设想,将Spring集成到Spark或者Flink的代码工程中,但这么做实际是有很多问题的,因为Spring并不适用于大数据分布式计算场景。

那么,实时开发的Spring(春天)在哪里呢?就在Fire框架中!为了最大化降低实时计算开发门槛,节约代码量,提高配置的便捷性,中通快递大数据团队自研了Fire框架。

Fire框架在中通内部深耕多年,目前线上数千个任务均是基于Fire框架开发的。基于Fire框架的任务每天处理的数据量高达几千亿规模,顺利通过一年又一年的双十一大考。

Fire框架开源免费,同时支持Spark与Flink两大主流引擎,有着简洁方便极易入门等优点,只需几分钟,即可学会。

1、快速入门案例

1.1 Flink开发示例

示例代码如下:

@Streaming(interval = 100, unaligned = true, parallelism = 4) // 100s做一次checkpoint,开启非对齐checkpoint
@Kafka(brokers = "localhost:9092", topics = "fire", groupId = "fire")
object FlinkDemo extends FlinkStreaming {

  @Process
  def kafkaSource: Unit = {
    val dstream = this.fire.createKafkaDirectStream()   // 使用api的方式消费kafka
    sql("""create table statement ...""")
    sql("""insert into statement ...""")
  }
}

1.2 Spark开发示例

@Config(
  """
    |# 支持Spark、Flink引擎调优参数、Fire框架参数、用户自定义参数等
    |spark.shuffle.compress=true
    |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 {

  @Process
  def kafkaSource: Unit = {
    val dstream = this.fire.createKafkaDirectStream()   // 使用api的方式消费kafka
    sql("""select * from xxx""").show()
  }
}

通过上述两个代码示例可以看出,Fire框架为Spark和Flink开发提供了统一的编程风格,使用Fire提供的注解以及对应的父类,即可完成框架的集成。

示例中的@Config注解支持多行配置,支持Spark或Flink的调优参数、Fire框架内置参数以及用户自定义参数。

当任务执行起来时,Fire框架会根据这些配置信息,去初始化SparkSession或ExecutionEnvironment等上下文信息,避免了大量冗余的任务初始化代码。

当然,@Config注解不是必须的,如果不指定,Fire框架会以默认最优的参数去初始化引擎上下文对象。

@Process注解用于标记开发者代码逻辑的入口,标记该注解的方法会被FIre框架自动调用。mian方法也不是必须的,因为它被定义在了父类当中。

@Streaming注解同时适用于Spark Streaming以及Flink两大计算引擎,interval用于设置Spark Streaming的批次时间,或者是Flink的checkpoint间隔时间。

parallelism用于指定Flink任务的全局并行度,maxRatePerPartition则是用于配置Spark Streaming的消费速率。@Streaming注解还有很多功能,包括开启checkpoint超时时间、是否开启非对齐checkpoint、Spark Streaming允许同时执行的批次数等。

@Hive注解用于指定hive metastore的url,适用于Spark和Flink。当指定了@Hive注解时,Fire框架在内部初始化时即可完成Spark与Flink创建hive catalog的动作。无需将hive-site.xml放到resources目录下,也不需要将hive相关的conf信息手动设置到SparkSession或ExecutionEnvironment中。

@Kafka和@RocketMQ注解用于配置消费消息队列相关的信息,指定好以后,在代码中即可完成一行代码接入:

val dstream = this.fire.createKafkaDirectStream()   // 使用api的方式消费kafka
val dStream = this.fire.createRocketMqPullStream()  // 使用api的方式消费rocketmq

1.3 SQL开发示例

Fire框架对纯SQL开发也提供了很简洁的API,在开发中,将SQL语句(多条以分号分割)放到sql()方法中,然后在方法上标记@Step注解,即可被顺序执行。

@Step注解中的中文描述,会被Fire框架自动打印到日志中,便于问题跟踪、异常排查等。当然,@Step注解和sql()方法一样可以应用到纯api开发的代码中,这些都是通用的。

@Streaming(interval = 60, parallelism = 2)
object JdbcDimDemo extends FlinkStreaming {

  @Step1("数据源定义")
  def ddl: Unit = {
    sql(
      """
        |CREATE TABLE t_mysql_dim (
        |  `id` BIGINT ...
        |) WITH ( ...
        |);
        |
        |CREATE TABLE t_kafka_fire (
        |  `id` BIGINT...
        |) WITH ( ...
        |)
        |""".stripMargin)
  }

  @Step2("kafka数据与mysql维表关联")
  def showJoin: Unit = {
    sql(
      """
        |select
        | xxx
        |from t_kafka_fire t1 left join t_mysql_dim  t2 on t1.id=t2.id
        |""".stripMargin).print()
  }
}

上述代码,Fire框架会根据代码中@Step注解的顺序,依次执行代码逻辑,并在日志中打印类似于下图的信息:

中通又一个承载千亿级流量平台开源啦!!!-鸿蒙开发者社区

2、注解含义(Spark与Flink通用)

接下来简单介绍一下Fire框架中的常用注解。

  • @Config:该注解支持Flink、Spark引擎相关参数、Fire框架参数以及用户自定义参数。对于引擎相关配置信息,会在构建SparkSession或Flink ExecutionEnvironment时自动设置生效,避免编写大量重复的用于构建引擎上文的代码。
  • @Streaming:该注解支持Flink的Checkpoint相关参数,包括频率、超时时间等,还可以进行任务并发度的配置。而对于Spark Streaming任务,则用于设置批次时间、是否开启反压,以及反压情况下消费速率等参数。
  • @Kafka:该注解用于配置任务中使用到的kafka集群信息,以及kafka-client相关调优参数。如果任务中消费多个kafka,可以使用@Kafka2、@Kafka3这种写法。
  • @Hive:该注解用于指定任务中所使用的hive数仓thrift server地址。支持HDFS HA,支持跨集群读写Hive。
  • @Process:该注解用于标记用户代码的入口,标记了@Process的方法会被Fire框架自动调起。
  • @HBase:用于配置HBase相关连接信息,一行代码完成HBase的读写。
  • @JDBC:用于配置jdbc相关信息,Fire框架内部封装了数据库连接池,会自动获取该注解的配置信息。
  • @Scheduled:用法类似于Sping,支持在Spark Streaming或Flink任务中执行周期性任务。
  • @Before:生命周期注解,用于在Fire框架初始化引擎上下文之前调用。
  • @After:生命周期注解,用于在Fire退出jvm之前调用,可用于Spark批任务回收数据库连接池等对象。

下面通过几个简单示例,感受一下使用注解快捷访问Hbase,Jdbc,定时调度的便利性。

@Hbase的使用示例:

// 假设基于注解配置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注解配置的集群信息

@Jdbc使用示例:

@Jdbc(url = "jdbc:derby:memory:fire;create=true", username = "fire", password = "fire")
val insertSql = s"INSERT INTO $tableName (name, age, createTime, length, sex) VALUES (?, ?, ?, ?, ?)"
this.fire.jdbcUpdate(insertSql, Seq("admin", 12, timestamp, 10.0, 1))

@Scheduled注解示范:

/**
  * 声明了@Scheduled注解的方法是定时任务方法,会周期性执行
  *
  * @scope 默认同时在driver端和executor端执行,如果指定了driver,则只在driver端定时执行
  * @initialDelay 延迟多长时间开始执行第一次定时任务
  */
@Scheduled(cron = "0/5 * * * * ?", scope = "driver", initialDelay = 60000)
def loadTable: Unit = {
  this.logger.info("更新维表动作")
}



文章转载自公众号:中间件兴趣圈

标签
已于2023-2-14 11:38:35修改
收藏
回复
举报
回复
    相关推荐