Kafka 数据源

一、API使用

使用fire框架可以很方便的消费kafka中的数据,并且支持在同一任务中消费多个kafka集群的多个topic。核心代码仅一行:

// Spark Streaming任务
val dstream = this.fire.createKafkaDirectStream()
// structured streaming任务
val kafkaDataset = this.fire.loadKafkaParseJson()
// flink 任务
val dstream = this.fire.createKafkaDirectStream()


以上的api均支持kafka相关参数的传入,但fire推荐将这些集群信息放到配置文件中,增强代码可读性,提高代码简洁性与灵活性。

二、kafka配置

你可能会疑惑,kafka的broker与topic信息并没有在代码中指定,程序是如何消费的呢?其实,这些信息都放到了任务同名的配置文件中。当然,你可以选择将这些kafka信息放到代码中指定。如果代码中指定了集群信息,同时配置文件中也有指定,则配置文件的优先级更高。

2.1 定义别名

建议将kafka集群url信息定义成别名,别名定义放到名为common.properties的配置文件中。别名的好处是一处维护到处生效,方便共用,便于记忆。

# 以下定义了两个kafka集群的别名,分别叫mq和test,别名与定义的url对应
fire.kafka.cluster.map.mq					=				kafka01:9092,kafka02:9092,kafka03:9092
fire.kafka.cluster.map.test				=				kafka-test01:9092,kafka-test02:9092,kafka-test03:9092


2.2 基于注解配置

定义好别名以后,就可以使用注解的方式去配置kafka集群信息了,fire框架支持一个任务读写多个kafka:

@Kafka(brokers = "mq", topics = "fire", groupId = "fire")
@Kafka2(brokers = "test", topics = "fire", groupId = "fire", sessionTimeout = 600000, autoCommit = false)


2.3 基于配置文件配置

spark.kafka.brokers.name           =       mq
# 必须配置项:kafka的topic列表,以逗号分隔
spark.kafka.topics                 =       fire
# 用于指定groupId,如果不指定,则默认为当前类名
spark.kafka.group.id               =       fire

# 配置消费明为test的kafka机器,注意key的后缀统一添加2,用于标识不同的kafka集群
spark.kafka.brokers.name2          =       test
# 必须配置项:kafka的topic列表,以逗号分隔
spark.kafka.topics2                =       fire
# 用于指定groupId,如果不指定,则默认为当前类名
spark.kafka.group.id2              =       fire


三、多kafka多topic消费

代码中是如何关联带有数字后缀的key的呢?答案是通过keyNum参数来指定:

// 对应spark.kafka.brokers.name=mq 或 @Kafka这个kafka("mq")集群,如果不知道keyNum,默认为1
val dstream = this.fire.createKafkaDirectStream()
// 对应spark.kafka.brokers.name2=test 或 @Kafka2("test")这个kafka集群
val dstream2 = this.fire.createKafkaDirectStream(keyNum=2)


三、offset提交

3.1 主动提交

dstream.kafkaCommitOffsets()


3.2 自动提交

spark streaming在处理数据过程中,由于offset提交与数据处理可能不再一个算子中,就会出现stage失败,数据丢失,但offset却提交了。为了解决这个问题,fire框架提供了foreachRDDAtLeastOnce算子,来保证计算的数据不丢,失败重试(默认3次),成功自动提交等特性。

@Streaming(20) // spark streaming的批次时间
@Kafka(brokers = "bigdata_test", topics = "fire", groupId = "fire")
// 以上注解支持别名或url两种方式如:@Hive(thrift://hive:9083),别名映射需配置到cluster.properties中
object AtLeastOnceTest extends BaseSparkStreaming {

  override def process: Unit = {
    val dstream = this.fire.createKafkaDirectStream()

    // 至少一次的语义保证,处理成功自动提交offset,处理失败会重试指定次数,如果仍失败则任务退出
    dstream.foreachRDDAtLeastOnce(rdd => {
      val studentRDD = rdd.map(t => JSONUtils.parseObject[Student](t.value())).repartition(2)
      val insertSql = s"INSERT INTO spark_test(name, age, createTime, length, sex) VALUES (?, ?, ?, ?, ?)"
      println("kafka.brokers.name=>" + this.conf.getString("kafka.brokers.name"))
      studentRDD.toDF().jdbcBatchUpdate(insertSql, Seq("name", "age", "createTime", "length", "sex"), batch = 1)
    })

    this.fire.start
  }
}


五、kafka-client参数调优

针对与kafka-client个性化的参数,需要使用config来进行配置:

@Kafka(brokers = "kafka01:9092", config = Array[String]("session.timeout.ms=30000", "request.timeout.ms=30000"))


基于配置文件的话使用kafka.conf开头加上kafka-client参数即可:

# 以kafka.conf开头的配置支持所有kafka client的配置
kafka.conf.session.timeout.ms   =     300000
kafka.conf.request.timeout.ms   =     400000
kafka.conf.session.timeout.ms2  =     300000


六、代码示例

1. spark消费kafka demo

2. flink消费kafka demo

七、@Kafka注解

/**
 * kafka集群连接信息,同value
 */
String brokers();

/**
 * kafka topics,多个使用逗号分隔
 */
String topics();

/**
 * 消费者标识
 */
String groupId();

/**
 * 指定从何处开始消费
 */
String startingOffset() default "";

/**
 * 指定消费到何处结束
 */
String endingOffsets() default "";

/**
 * 是否开启主动提交offset
 */
boolean autoCommit() default false;

/**
 * session超时时间(ms)
 */
long sessionTimeout() default -1;

/**
 * request超时时间(ms)
 */
long requestTimeout() default -1;

/**
 * poll的周期(ms)
 */
long pollInterval() default -1;

/**
 * 从指定的时间戳开始消费
 */
long startFromTimestamp() default -1;

/**
 * 指定从kafka中保持的offset开始继续消费
 */
boolean startFromGroupOffsets() default false;

/**
 * 是否强制覆盖checkpoint中保持的offset信息,从指定位置开始消费
 */
boolean forceOverwriteStateOffset() default false;

/**
 * 是否在开启checkpoint的情况下强制周期性提交offset到kafka
 */
boolean forceAutoCommit() default false;

/**
 * 强制提交的周期(ms)
 */
long forceAutoCommitInterval() default -1;

/**
 * kafka-client参数,以key=value形式注明
 */
String[] config() default "";


八、配置参数

参数名称

引擎

含义

fire.kafka.cluster.map.

通用

用于定义kafka集群别名

kafka.conf.

通用

用于设置kafka-client参数

kafka.brokers.name

通用

指定消费的kafka集群url或别名

kafka.topics

通用

kafka的topic列表,以逗号分隔

kafka.group.id

通用

消费kafka的group id

kafka.starting.offsets

通用

kafka起始消费位点

kafka.ending.offsets

通用

kafka结束消费位点

kafka.enable.auto.commit

通用

是否自动维护offset

kafka.failOnDataLoss

通用

丢失数据是否失败

kafka.session.timeout.ms

通用

kafka session超时时间

kafka.request.timeout.ms

通用

kafka request超时时间

kafka.max.poll.interval.ms

通用

kafka的最大poll周期

kafka.CommitOffsetsOnCheckpoints

flink

当checkpoint时是否提交offset

kafka.StartFromTimestamp

flink

从指定时间戳开始消费

kafka.StartFromGroupOffsets

flink

从指定offset开始消费

kafka.force.overwrite.stateOffset.enable

flink

是否使状态中存放的offset不生效(请谨慎配置,用于kafka集群迁移等不正常状况的运维)

kafka.force.autoCommit.enable

flink

是否在开启checkpoint的情况下强制开启周期性offset提交

kafka.force.autoCommit.Interval

Flink

周期性提交offset的时间间隔(ms)