簡體   English   中英

使用Kafka-Spark Streaming API處理流數據時出現重復

[英]Duplicates while Processing Streaming Data using Kafka-Spark Streaming API

以下代碼在數據處理后有效並提交偏移量。 但是問題是,在以下情況下它正在處理重復項:

消費者作業正在運行,並且配置單元表具有0條記錄,當前偏移量為(FORMAT- fromOffest,直到Offset,Difference):512 512 0

然后我產生了1000條記錄,到讀取34條記錄但沒有提交時,我殺死了512546 34

我看到這一次,這34個記錄已經加載到Hive表中

接下來,我重新啟動了該應用程序。

我看到它再次讀取了34條記錄(而不是讀取1000-34 = 76 recs),盡管它已經處理了它們並加載到Hive 512 1512 1000中,然后在幾秒鍾后進行了更新。 1512 1512 0蜂巢現在具有(34 + 1000 = 1034)

這將導致表中的記錄重復(額外34)。 如代碼中所述,我僅在處理/加載到Hive表之后才提交偏移量。

public void method1(SparkConf conf,String app) 
    spark = SparkSession.builder().appName(conf.get("")).enableHiveSupport().getOrCreate();
    final JavaStreamingContext javaStreamContext = new JavaStreamingContext(context,
            new Duration(<spark duration>));
    JavaInputDStream<ConsumerRecord<String, String>> messages = KafkaUtils.createDirectStream(javaStreamContext,
            LocationStrategies.PreferConsistent(),
            ConsumerStrategies.<String, String> Subscribe(<topicnames>, <kafka Params>));

            JavaDStream<String> records = messages.map(new Function<ConsumerRecord<String, String>, String>() {
                @Override
                public String call(ConsumerRecord<String, String> tuple2) throws Exception {
                    return tuple2.value();
                }
            });

            records.foreachRDD(new VoidFunction<JavaRDD<String>>() {
                @Override
                public void call(JavaRDD<String> rdd) throws Exception {
                    if(!rdd.isEmpty()) {
                        methodToSaveDataInHive(rdd, <StructTypeSchema>,<OtherParams>);
                    }
                }
             });

             messages.foreachRDD(new VoidFunction<JavaRDD<ConsumerRecord<String, String>>>() {
              @Override
              public void call(JavaRDD<ConsumerRecord<String, String>> rdd) {
                    OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();
                    ((CanCommitOffsets) messages.inputDStream()).commitAsync(offsetRanges);                     
                    for (OffsetRange offset : offsetRanges) {
                        System.out.println(offset.fromOffset() + " " + offset.untilOffset()+ "  "+offset.count());
                    }
                     }
              });             
    javaStreamContext.start();
    javaStreamContext.awaitTermination();
}

一般來說,在構建Spark Streaming作業時,您不必擔心重復項,而應在下游進行處理。 別誤會,您想要構建應用程序以防止重復,但是當災難性的事情發生時,您將獲得重復,這就是為什么最好稍后再進行管理。

我看到的第一個問題是保存偏移量的位置。 您應該在保存數據之后立即保存它們,而不是之后的方法。 當records.foreachRDD完成methodToSaveData時,它應進行調用以保存偏移量。 您可能需要重新構造映射記錄的方式,以便獲得偏移量詳細信息,但這是最佳選擇。

        records.foreachRDD(new VoidFunction<JavaRDD<String>>() {
            @Override
            public void call(JavaRDD<String> rdd) throws Exception {
                if(!rdd.isEmpty()) {
                    methodToSaveDataInHive(rdd, <StructTypeSchema>,<OtherParams>);
                    **{commit offsets here}**
                }
            }
         });

也就是說,將偏移量保存在哪里都沒有關系。 如果作業在將數據寫入配置單元之后並且在提交偏移范圍之前被殺死,那么您將重新處理記錄。 您可以通過某些方法來構建應用程序,使其具有優美的關閉掛鈎(Google掛鈎),這些掛鈎會嘗試捕獲kill命令並正常關閉它,但同樣容易受到應用程序被殺死或崩潰的影響。 如果運行執行程序的計算機在保存到配置單元之后但在提交偏移量之前失去了電源,則您有重復項。 如果該應用程序在Linux上被殺死-9(在Linux中),則它不會在乎是否正常關機,並且您會重復執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM