- 使用checkpoint管理消费者offset(spark1.6和spark2.3都行)
如果业务逻辑不变,可以使用checkpoint来管理消费者offset.使用streamingContext.getOrCreate(check目录,streamingContext);首先从checkpoint目录中回复streaming配置信息,逻辑,offset。如果业务逻辑变了,使用这种方式不会执行新的业务逻辑,回复offset的同时,把旧的逻辑也恢复过来了。
如果业务逻辑不变,使用checkpoint维护offset,存在重复消费数据问题,自己要保证后面处理数据的幂等性。
- 手动维护消费者offset
借用第三方组件(zk,hbase,mysql)等维护offset
- 依赖与kafka自己维护消费者offset(spark2.3仅)
spark2.3只有direct模式,丢弃了receive模式
1.设置enable.auto.commit=false
2.在保证业务完全处理完成后,手动异步的向kafka中提交
public static void main(String[] args) throws InterruptedException {
SparkSession spark = SparkSession.builder().appName("streaming").master("local[2]").getOrCreate();
JavaSparkContext sc = new JavaSparkContext(spark.sparkContext());
JavaStreamingContext jsc = new JavaStreamingContext(sc, Durations.seconds(10));
List<String> topics = Arrays.asList("test_topic");
JavaInputDStream<ConsumerRecord<Object, Object>> stream = KafkaUtils.createDirectStream(
jsc,
LocationStrategies.PreferConsistent(),//均匀分发到executor
ConsumerStrategies.Subscribe(topics, getKafkaParams()));
stream.foreachRDD(rdd -> {
//获取当前offset的数据
OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();
rdd.foreachPartition(consumerRecords -> {
OffsetRange offset = offsetRanges[TaskContext.get().partitionId()];
System.out.println(offset.topic() + " " + offset.partition() + " " + offset.untilOffset());
while (consumerRecords.hasNext()) {
System.out.println("value:" + consumerRecords.next().value());
}
});
//业务,确保该事务完成后提交
//kafka自身维护提交,必须用源头的stream
((CanCommitOffsets) stream.inputDStream()).commitAsync(offsetRanges);
});
jsc.start();
jsc.awaitTermination();
}
public static Map<String, Object> getKafkaParams() {
Map<String, Object> kafkaParams = new HashMap<>();
kafkaParams.put("bootstrap.servers", "hdp01:6667,hdp02:6667,hdp03:6667");
kafkaParams.put("key.deserializer", StringDeserializer.class);
kafkaParams.put("value.deserializer", StringDeserializer.class);
kafkaParams.put("group.id", "huge_leaf_group");
kafkaParams.put("auto.offset.reset", "latest");
kafkaParams.put("enable.auto.commit", false);//true时五秒提交一次
return kafkaParams;
}