使用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的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
代码中是如何关联带有数字后缀的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)
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个性化的参数,需要使用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集群连接信息,同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) |