データフローの動的地の問題

Scicrazed:

私はのpubsubからデータを読み込み、時間に基づいてデータフローの仕事を持っていると、ファイル名、フォルダパスがYYYY / MM / DDに基づいてGCSに内容を書き込みます。これは、ファイルが日付に基づいてフォルダに生成されることを可能にするとApacheビームのを使用していますFileIODynamic Destinations

約2週間前、私は未確認のメッセージの異例の蓄積に気づきました。DFジョブを再起動時にエラーが消え、新しいファイルがGCSで書かれていました。

数日後、書き込み処理が立ち往生したと主張し、エラーがあった、この時間を除いて、再び停止しました。いくつかの信頼できるSO調査の後、私はこれがそうしていることが分かった原因、それはデフォルトのセキュリティ・プロバイダとしてConscryptライブラリを使用しているため、事前2.90ビームでデッドロックの問題で。だから、私はビーム2.8からのビーム2.11にアップグレード。

それがなかったまでもう一度、それは、働いていました。私は、エラーでより密接に見て、それがスレッドセーフではないのSimpleDateFormatオブジェクト、との問題を抱えていたことに気づきました。だから、私は、スレッドセーフであるJava.timeとてDateTimeFormatterを、使用することを切り替えます。それがなかったまでは働いていました。しかし、この時点では、エラーが少し違っていたし、私のコードで何を指していました:エラーが下方に設けられています。

Processing stuck in step FileIO.Write/WriteFiles/WriteShardedBundlesToTempFiles/WriteShardsIntoTempFiles for at least 05m00s without outputting or completing in state process
  at sun.misc.Unsafe.park(Native Method)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
  at org.apache.beam.vendor.guava.v20_0.com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:469)
  at org.apache.beam.vendor.guava.v20_0.com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:76)
  at org.apache.beam.runners.dataflow.worker.MetricTrackingWindmillServerStub.getStateData(MetricTrackingWindmillServerStub.java:202)
  at org.apache.beam.runners.dataflow.worker.WindmillStateReader.startBatchAndBlock(WindmillStateReader.java:409)
  at org.apache.beam.runners.dataflow.worker.WindmillStateReader$WrappedFuture.get(WindmillStateReader.java:311)
  at org.apache.beam.runners.dataflow.worker.WindmillStateReader$BagPagingIterable$1.computeNext(WindmillStateReader.java:700)
  at org.apache.beam.vendor.guava.v20_0.com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:145)
  at org.apache.beam.vendor.guava.v20_0.com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:140)
  at org.apache.beam.vendor.guava.v20_0.com.google.common.collect.MultitransformedIterator.hasNext(MultitransformedIterator.java:47)
  at org.apache.beam.sdk.io.WriteFiles$WriteShardsIntoTempFilesFn.processElement(WriteFiles.java:701)
  at org.apache.beam.sdk.io.WriteFiles$WriteShardsIntoTempFilesFn$DoFnInvoker.invokeProcessElement(Unknown Source)

このエラーは、約5時間の仕事の展開後と時間をかけて増加率で発生し始めました。書き込みは24時間以内に大幅に減速しました。私は60人の労働者を持っていると私は1つのワーカーが、最終的に仕事を殺す誤りがあるたびに、失敗したと思われます。

私の作家で、私はそれがに属しているフォルダを確認するために、特定のキーワードのためのラインを(最良の方法ではないかもしれない)を解析。私はその後、決定したファイル名でGCSにファイルを挿入するように進みます。ここで私は私のライターに使用するコードは次のとおりです。

パーティション関数は、以下のように提供されます。

@SuppressWarnings("serial")
public static class datePartition implements SerializableFunction<String, String> {     
    private String filename;

    public datePartition(String filename) {
        this.filename = filename;
    }

    @Override
    public String apply(String input) {

        String folder_name = "NaN";             
        String date_dtf    = "NaN";     
        String date_literal = "NaN";
        try {
            Matcher foldernames = Pattern.compile("\"foldername\":\"(.*?)\"").matcher(input);
            if(foldernames.find()) {
                folder_name = foldernames.group(1);
            }
            else {
                Matcher folderid = Pattern.compile("\"folderid\":\"(.*?)\"").matcher(input);
                if(folderid.find()) {
                    folder_name = folderid.group(1);
                }   
            }

            Matcher date_long = Pattern.compile("\"timestamp\":\"(.*?)\"").matcher(input);
            if(date_long.find()) {
                date_literal = date_long.group(1);
                if(Utilities.isNumeric(date_literal)) {
                    LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.valueOf(date_literal)), ZoneId.systemDefault());
                    date_dtf = date.format(dtf);                        
                }
                else {
                    date_dtf = date_literal.split(":")[0].replace("-", "/").replace("T", "/");
                }
            }
            return folder_name + "/" + date_dtf + "h/" + filename;
        }

        catch(Exception e) {
            LOG.error("ERROR with either foldername or date");
            LOG.error("Line : " + input);
            LOG.error("folder : " + folder_name);
            LOG.error("Date : " + date_dtf);

            return folder_name + "/" + date_dtf + "h/" + filename;
        }           
    }
}

そして、パイプラインが展開され、実行される実際の場所は下に見つけることができます:

public void streamData() {

    Pipeline pipeline = Pipeline.create(options);
    pipeline.apply("Read PubSub Events", PubsubIO.readMessagesWithAttributes().fromSubscription(options.getInputSubscription()))
            .apply(options.getWindowDuration() + " Window",
                        Window.<PubsubMessage>into(FixedWindows.of(parseDuration(options.getWindowDuration())))
                                  .triggering(AfterWatermark.pastEndOfWindow()) 
                                  .discardingFiredPanes()
                                  .withAllowedLateness(parseDuration("24h")))
                .apply(new GenericFunctions.extractMsg())
                .apply(FileIO.<String, String>writeDynamic()
                                 .by(new datePartition(options.getOutputFilenamePrefix()))
                                 .via(TextIO.sink())
                                 .withNumShards(options.getNumShards())
                                 .to(options.getOutputDirectory())
                                 .withNaming(type -> FileIO.Write.defaultNaming(type, ".txt"))
                                 .withDestinationCoder(StringUtf8Coder.of()));

    pipeline.run();
}
Scicrazed:

この質問を投稿しているので、私はかわすのボトルネックと増加並列にデータフローの仕事を最適化しました。rsantiagoを説明多くのように、こだわって処理するステップは、与えられたリソースをクリアすることができないボトルネックが本質的である、他のステップよりもかなり時間がかかっていることをエラーではなく、単に道のデータフロー通信します。変更は、私はそれらに対処してきたように見える作られました。次のように新しいコードは次のとおりです。

public void streamData() {

        try {
            Pipeline pipeline = Pipeline.create(options);

            pipeline.apply("Read PubSub Events", PubsubIO.readMessagesWithAttributes().fromSubscription(options.getInputSubscription()))
            .apply(options.getWindowDuration() + " Window",
                    Window.<PubsubMessage>into(FixedWindows.of(parseDuration(options.getWindowDuration())))
                          .triggering(AfterWatermark.pastEndOfWindow()) 
                          .discardingFiredPanes()
                          .withAllowedLateness(parseDuration("24h")))
            .apply(FileIO.<String,PubsubMessage>writeDynamic()
                    .by(new datePartition(options.getOutputFilenamePrefix()))
                    .via(Contextful.fn(
                            (SerializableFunction<PubsubMessage, String>) inputMsg -> new String(inputMsg.getPayload(), StandardCharsets.UTF_8)),
                            TextIO.sink())
                    .withDestinationCoder(StringUtf8Coder.of())
                    .to(options.getOutputDirectory())
                    .withNaming(type -> new CrowdStrikeFileNaming(type))
                    .withNumShards(options.getNumShards())
                    .withTempDirectory(options.getTempLocation()));

            pipeline.run();
        }

        catch(Exception e) {

            LOG.error("Unable to deploy pipeline");
            LOG.error(e.toString(), e);
        }

    }

最大の変化は、extractMsg()関数を削除し、使用のみのメタデータへの分割を変える関与しました。これらのステップの両方は、デシリアライゼーション/メッセージのreserializationと大きく影響を受けたパフォーマンスを余儀なくされました。

私のデータセットが無制限だったのでまた、私は破片のゼロ以外の数値を設定する必要がありました。私はそれがパフォーマンスを傷つけるどのくらい知らなくても、これを1に設定して、私は、私のファイル命名ポリシーを簡素化したかったです。それ以来、私は(ほとんどが、残念ながら、推測&チェックに基づいて)私の仕事のために労働者/破片/マシンタイプの良好なバランスを見つけました。

それがボトルネックには十分な大きさのデータロードで観察されるかもしれないことは可能ですが、パイプラインは、高負荷(一日あたり3-5tb)にもかかわらず好調されています。また、大幅に改善された自動スケーリングを変更しますが、私はわからない理由です。データフローの仕事は今、多くの迅速なスパイクや谷に反応します。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=176507&siteId=1