SparkStreaming读取kafka数据(4)-更新offset到zookeeper

本文讨论了SparkStreaming使用DirectStream方式处理Kafka数据时,checkpoint机制的弊端,如程序更新导致的序列化异常或继续执行旧代码。提出了通过记录并更新offset到Zookeeper来解决这个问题的方法,确保程序恢复时能从最新的offset继续工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SparkStreaming读取kafka数据(2)-DirectStream方式

前遍讲了Spark streaming处理kafka的数据的checkpoint机制方式

checkpoint的弊端

checkpoint的最大的弊端在于,一旦你的流式程序代码或配置改变了,或者更新迭代新功能了,这个时候,你先停旧的sparkstreaming程序,然后新的程序打包编译后执行运行,会发现两种情况: (1)启动报错,反序列化异常 (2)启动正常,但是运行的代码仍然是上一次的程序的代码。

为什么会出现上面的两种情况,这是因为checkpoint第一次持久化的时候会把整个相关的jar给序列化成一个二进制文件,每次重启都会从里面恢复,但是当你新的 程序打包之后序列化加载的仍然是旧的序列化文件,这就会导致报错或者依旧执行旧代码。

实际开发中程序经常变动,所以弊端很突出!!!

弊端的解决方法

spark官网给出了2种解决办法:

(1)旧的不停机,新的程序继续启动,两个程序并存一段时间消费。 

(2)停机的时候,记录下最后一次的偏移量,然后新恢复的程序读取这个偏移量继续工作,从而达到不丢消息。 

本篇采用方式(2):记录最新消费的offset值并更新到zookeeper,程序恢复时读取最新消费的offset值继续工作。

代码原理

spark streaming 的rdd可以被转换为HasOffsetRanges类型,进而得到所有partition的offset值

运行环境

 <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-streaming-kafka-0-8_2.11</artifactId>
      <version>2.1.0</version>
</dependency>

kafka工具类

负责程序恢复时,读取最新消费的offset值和更新offset值到zookeeper


import kafka.common.TopicAndPartition;
import kafka.message.MessageAndMetadata;
import kafka.serializer.StringDecoder;
import org.apache.spark.SparkException;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.streaming.api.java.JavaInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka.HasOffsetRanges;
import org.apache.spark.streaming.kafka.KafkaCluster;
import org.apache.spark.streaming.kafka.KafkaUtils;
import org.apache.spark.streaming.kafka.OffsetRange;
import scala.Tuple2;
import scala.collection.JavaConversions;
import scala.collection.mutable.ArrayBuffer;
import scala.util.Either;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * kafka offset 管理
 */
public class JavaKafkaManager implements Serializable {
    private scala.collection.immutable.Map<String, String> kafkaParams;
    private KafkaCluster kafkaCluster;

    public JavaKafkaManager(Map<String, String> kafkaParams) {
        this.kafkaParams = toScalaImmutableMap(kafkaParams);
        kafkaCluster = new KafkaCluster(this.kafkaParams);
    }

    public JavaInputDStream<String> createDirectStream(
            JavaStreamingContext jssc,
            Map<String, String> kafkaParams,
            Set<String> topics) throws SparkException {

        String groupId = kafkaParams.get("group.id");

        // 在zookeeper上读取offsets前先根据实际情况更新offsets
        setOrUpdateOffsets(topics, groupId);

        //从zookeeper上读取offset开始消费messa
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值