Проблемы надежности с Checkpointing/WAL в Spark Streaming 1.6.0

описание

у нас есть приложение Spark Streaming 1.5.2 в Scala, которое считывает события JSON из потока Kinesis, выполняет некоторые преобразования/агрегации и записывает результаты в разные префиксы S3. Текущий интервал между пакетами составляет 60 секунд. Мы имеем 3000-7000 событий / сек. Мы используем checkpointing, чтобы защитить нас от потери агрегаций.

он работает хорошо некоторое время, восстанавливаясь от исключений и даже перезапусков кластера. Мы недавно пересобрал код для Spark Streaming 1.6.0, изменяющий только зависимости библиотеки в построить.sbt. После запуска кода в кластере Spark 1.6.0 в течение нескольких часов мы заметили следующее:

  1. "скорость ввода" и "время обработки" волатильность существенно возросла (см. скриншоты ниже) в 1.6.0.
  2. каждые несколько часов появляется " исключение при записи записи: BlockAdditionEvent ... в WriteAheadLog. Ява.утиль.параллельный.TimeoutException: фьючерсы истекли после исключения [5000 миллисекунд]" (см. полную трассировку стека ниже), совпадающего с падением до 0 событий/сек для определенных пакетов (минут).

после некоторого рытья, я думаю, что вторая проблема выглядит связанной с этим Pull-Запрос. Первоначальная цель PR: "при использовании S3 в качестве каталога для WALs записи занимают слишком много времени. Водитель получает очень легко собралась, когда несколько отправка События AddBlock в ReceiverTracker. Этот PR добавляет пакетирование событий в ReceivedBlockTracker, чтобы получатели не блокировались драйвером слишком долго."

мы проверяем в S3 в Spark 1.5.2, и нет проблем с производительностью/надежностью. Мы протестировали checkpointing в Spark 1.6.0 в S3 и локальном NAS, и в обоих случаях мы получаем это исключение. Похоже, когда для проверки пакета требуется более 5 секунд, возникает это исключение, и мы проверили что события для этой партии потеряны навсегда.

вопросы

  • ожидается ли увеличение волатильности "скорости ввода" и "времени обработки" в Spark Streaming 1.6.0 и есть ли какой-либо известный способ ее улучшения?

  • знаете ли вы о каком-либо обходном пути, кроме этих 2?:

    1) гарантировать что оно принимает меньш чем 5 секунд для checkpointing раковины для того чтобы написать все файлы. По моему опыту, вы не можете гарантировать, что с S3, даже для небольших партий. Для локального NAS это зависит от того, кто отвечает за инфраструктуру (сложно с облачными провайдерами).

    2) Увеличение искры.струящийся.водитель.writeAheadLog.значение свойства batchingTimeout.

  • ожидаете ли вы потерять какие-либо события в описанном сценарии? Я бы подумал, что если пакетный checkpointing терпит неудачу, порядковые номера осколка / приемника не будут увеличены, и он будет повторен позже время.

Spark 1.5.2 Статистика-Скриншот

enter image description here

Spark 1.6.0 Статистика-Скриншот

enter image description here

Полная Трассировка Стека

16/01/19 03:25:03 WARN ReceivedBlockTracker: Exception thrown while writing record: BlockAdditionEvent(ReceivedBlockInfo(0,Some(3521),Some(SequenceNumberRanges(SequenceNumberRange(StreamEventsPRD,shardId-000000000003,49558087746891612304997255299934807015508295035511636018,49558087746891612304997255303224294170679701088606617650), SequenceNumberRange(StreamEventsPRD,shardId-000000000004,49558087949939897337618579003482122196174788079896232002,49558087949939897337618579006984380295598368799020023874), SequenceNumberRange(StreamEventsPRD,shardId-000000000001,49558087735072217349776025034858012188384702720257294354,49558087735072217349776025038332464993957147037082320914), SequenceNumberRange(StreamEventsPRD,shardId-000000000009,49558088270111696152922722880993488801473174525649617042,49558088270111696152922722884455852348849472550727581842), SequenceNumberRange(StreamEventsPRD,shardId-000000000000,49558087841379869711171505550483827793283335010434154498,49558087841379869711171505554030816148032657077741551618), SequenceNumberRange(StreamEventsPRD,shardId-000000000002,49558087853556076589569225785774419228345486684446523426,49558087853556076589569225789389107428993227916817989666))),BlockManagerBasedStoreResult(input-0-1453142312126,Some(3521)))) to the WriteAheadLog.
java.util.concurrent.TimeoutException: Futures timed out after [5000 milliseconds]
    at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:219)
    at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223)
    at scala.concurrent.Await$$anonfun$result.apply(package.scala:107)
    at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
    at scala.concurrent.Await$.result(package.scala:107)
    at org.apache.spark.streaming.util.BatchedWriteAheadLog.write(BatchedWriteAheadLog.scala:81)
    at org.apache.spark.streaming.scheduler.ReceivedBlockTracker.writeToLog(ReceivedBlockTracker.scala:232)
    at org.apache.spark.streaming.scheduler.ReceivedBlockTracker.addBlock(ReceivedBlockTracker.scala:87)
    at org.apache.spark.streaming.scheduler.ReceiverTracker.org$apache$spark$streaming$scheduler$ReceiverTracker$$addBlock(ReceiverTracker.scala:321)
    at org.apache.spark.streaming.scheduler.ReceiverTracker$ReceiverTrackerEndpoint$$anonfun$receiveAndReply$$anon$$anonfun$run.apply$mcV$sp(ReceiverTracker.scala:500)
    at org.apache.spark.util.Utils$.tryLogNonFatalError(Utils.scala:1230)
    at org.apache.spark.streaming.scheduler.ReceiverTracker$ReceiverTrackerEndpoint$$anonfun$receiveAndReply$$anon.run(ReceiverTracker.scala:498)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Извлечение Исходного Кода

...
     // Function to create a new StreamingContext and set it up
  def setupContext(): StreamingContext = {
    ...
    // Create a StreamingContext
    val ssc = new StreamingContext(sc, Seconds(batchIntervalSeconds))

    // Create a Kinesis DStream
    val data = KinesisUtils.createStream(ssc,
      kinesisAppName, kinesisStreamName,
      kinesisEndpointUrl, RegionUtils.getRegionByEndpoint(kinesisEndpointUrl).getName(),
      InitialPositionInStream.LATEST, Seconds(kinesisCheckpointIntervalSeconds),
      StorageLevel.MEMORY_AND_DISK_SER_2, awsAccessKeyId, awsSecretKey)
...
    ssc.checkpoint(checkpointDir)

    ssc
  }


  // Get or create a streaming context.
  val ssc = StreamingContext.getActiveOrCreate(checkpointDir, setupContext)

  ssc.start()
  ssc.awaitTermination()

1 ответов


после zero323предложение о публикации моего комментария в качестве ответа:

увеличение искры.струящийся.водитель.writeAheadLog.batchingTimeout решил проблему тайм-аута проверки. Мы сделали это, убедившись, что у нас есть для этого место. Мы уже давно его тестируем. Поэтому я рекомендую увеличить его только после тщательного рассмотрения.

подробности

мы использовали эти 2 настройки в $SPARK_HOME/conf / spark-по умолчанию.conf:

Искра.струящийся.водитель.writeAheadLog.allowBatching true искра.струящийся.водитель.writeAheadLog.batchingTimeout 15000

изначально, у нас была только искра.струящийся.водитель.writeAheadLog.allowBatching имеет значение true.

до изменения мы воспроизвели вопрос, упомянутый в вопросе ("...ReceivedBlockTracker: исключение при записи записи...") в среде тестирования. Это происходило каждые несколько часов. После изменения, проблема исчезла. Мы прогнали его несколько дней, прежде чем перейти к производству.

мы обнаружили, что getBatchingTimeout() метод WriteAheadLogUtils класс имел значение по умолчанию 5000ms, как видно здесь:

def getBatchingTimeout(conf: SparkConf): Long = {
    conf.getLong(DRIVER_WAL_BATCHING_TIMEOUT_CONF_KEY, defaultValue = 5000)
}