Top Banner
Опыт использования spark Основано на реальных событиях
21

Опыт использования Spark, Основано на реальных событиях

Jul 15, 2015

Download

Technology

Vasil Remeniuk
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Опыт использования Spark, Основано на реальных событиях

Опыт использования spark

Основано на реальных событиях

Page 2: Опыт использования Spark, Основано на реальных событиях

Чтение бинарных логов• задача - по логам найти тех, кто подбирает пароли• одна запись лога раскидана на несколько бинарных файлов• часть бинарных файлов = справочники• остальные файлы читаются последовательно• такую задачу можно решать на hadoop• также можно решать переводом бинарных данных в текстовый формат, но это потери

времени и ресурсов кластера

Page 3: Опыт использования Spark, Основано на реальных событиях

Чтение в hadoop

InputFormat

split

split

split

RecordReader

RecordReader

RecordReader

Record

Record

Record

Page 4: Опыт использования Spark, Основано на реальных событиях

Использование в спарк• этапы решения

• работа с бинарными файлами в одном потоке• упаковка логики в inputformat, record reader• написание mr джоба

• как это всё засунуть в спаркval fileRDDs = filesToProcess.toArray.map{ file => sc.newAPIHadoopFile[IntWritable, Text, BWLogsInputFormat[IntWritable, Text]](file)}val rdd = new UnionRDD(sc, fileRDDs)

Page 5: Опыт использования Spark, Основано на реальных событиях

Оптимизация ETL

конвертировать бинлоги в текстовое представление,не всегда это можно сделать даже используя fuseи это приведёт к потери времени и ресурсов кластера

бинарные данные

текстовые данные

обработка

Page 6: Опыт использования Spark, Основано на реальных событиях

Запись с группировкой по директориям

• проблема: rdd.saveAsTextFile(“/var/blob/result”) сохраняет всё в директорию path/var/blob/result/part-00000/var/blob/result/part-00001

• чего хотелось бы: разбить данные по директориям - партицировать по значениям полей

/var/blob/result/type1/part-00000/var/blob/result/type1/part-00001/var/blob/result/type2/part-00000/var/blob/result/type2/part-00001/var/blob/result/type3/part-00000/var/blob/result/type3/part-00001/var/blob/result/type4/part-00000/var/blob/result/type4/part-00001

Page 7: Опыт использования Spark, Основано на реальных событиях

N+1 чтение resultRdd.map {

x => x._1 //partition value }.distinct().collect()/* first read*/.foreach {

part => resultRdd.filter(part.equals(_._1))/* N reads*/.saveAsTextFile("path/" + part) }

Page 8: Опыт использования Spark, Основано на реальных событиях

1 чтение и много кода resultRdd.foreachPartition {

p =>

val hdfs = HdfsUtils.setupHdfs(hdfsConf)

val pathToOut = collection.mutable.Map[String, FSDataOutputStream]()

try {

//save to dirs by value

p.foreach(csv => {

val fileName = "%1$s/%2$s/%3$s".format(sortByDateDir, dateValue, exeDirName)

val output = getFileOutput(fileName, pathToOut, hdfs)

output.write(csv._2.toString.getBytes("utf8"))

output.writeBytes(CSV_DELIMITER)

})

} catch {

case t: Throwable => {

log.error("" + t, t)

}

}

pathToOut.foreach(out => {

tryToCloseNTimes(out._2, 5, 2000)

})

}

def getFileOutput(fileName: String, files: collection.mutable.Map[String, FSDataOutputStream], fs: FileSystem): FSDataOutputStream = {

//20 lines of code

}

Page 9: Опыт использования Spark, Основано на реальных событиях

1 чтение + мало кодироватьclass KeyPartitionedMultipleTextOutputFormat extends MultipleTextOutputFormat[NullWritable, String] { override def generateFileNameForKeyValue(key: NullWritable, value: String, name: String): String = {

val elements = value.toString.split(",")"key%1$s/%2$s".format(elements(1), name)

}}

val pairRdd = new PairRDDFunctions[NullWritable, String](pairBlob)pairRdd.saveAsHadoopFile(fs.getUri + config.dstDir, classOf[NullWritable], classOf[String], classOf[KeyPartitionedMultipleTextOutputFormat], conf = new JobConf(appConf))

Page 10: Опыт использования Spark, Основано на реальных событиях

Скорость и надёжность кафки• чем хороша кафка

• легко масштабировать• хорошая скорость чтения записи

• недостатки• для предсказуемого поведения с оффсетами и равномерностью чтения партиций

лучше использовать низкоуровневый simpleconsumer• документация - лучше сразу смотреть исходники

• важно не путать её с jms очередями

топик

партиция 1

партиция 2

партиция 3

реплика 1

реплика 2

Page 11: Опыт использования Spark, Основано на реальных событиях

Актуальный сценарий интеграции

серверное приложение (C++ python)

логика отправки данных в кафку кафка

спарк batch & streaming

Page 12: Опыт использования Spark, Основано на реальных событиях

Сценарий с tungsten (POC)

mysql master

tungsten

spark batch & streamkafka

mysql master

tungsten

binlog

binlog

серверное приложение (С++ python)

Page 13: Опыт использования Spark, Основано на реальных событиях

Типичный ETL сценарий

mysql

dump csv + tgz HDFS spark

тут напрягаем периодически mysql сервер дампами, невозможно сделать журнал

тут скорость будет хуже чем у кафка,удобнее писать читать кафку чем hdfs

Page 14: Опыт использования Spark, Основано на реальных событиях

Чтение из Кафки

• создан inputformat для чтение топиков из кафки (по мотивам camus)• алгоритм работы

• для каждого осчетания топик+партиция создать сплит• в рамках обработки сплита посмотреть текущие оффсеты записи и поднять

последние оффсеты чтения с hdfs• выполнить чтение и сохранить новые оффсеты чтения на hdfs

• недостатки• хранение оффсетов чтения на hdfs• неравномерная загрузка кластера в случае малого числа партиций или

неравномерной загрузки партиций• проблема отсутствия лидера партиции на момент старта выгрузки

Page 15: Опыт использования Spark, Основано на реальных событиях

Спарк Стриминг• приницип работы - создавать рдд на основе принятых данных и обрабатывать их• позволяет партицировать поток (получать данные на нескольких нодах одновременно)

val allInputs = (0 to numberOfNodes - 1).map {x =>SparkUtils.createStreamPartition(ssc, ...)}

• позволяет работать с окнами = запоминает набор рдд для окна• для отказоустойчивости есть механизм сохранения снимков рдд• позволяет сделать ограничитель скорости приёма данных

Page 16: Опыт использования Spark, Основано на реальных событиях

Недостатки Стриминга• трудно организовать обработку данных без потерь (но для стриминга это не всегда нужно)

• проблема в блок генераторе• получили данные из потока• закинули данные в блок генератор на создание рдд• данные попадают в буффер (для асинхронности и скорости)• с задержкой по времени данные попадают в рдд

• т.е. при падении есть вероятность потерять содержимое буфера• есть возможности это обойти при условии возможности перечитать данные из потока

• надо играть настройками генератора рдд чтобы избежать OOMspark.streaming.blockInterval=100 (в миллисекундах)

канал сообщений

Генератор РДДОкно РДД (память + диск)

РДД РДД РДДБуфер

Page 17: Опыт использования Spark, Основано на реальных событиях

Работа с потоком из кафки• в поставке спарка есть реализация кафка стрима, но она не устроила

• основана на высокоуровневом апи кафка ридера с его проблемами сохранения офсетов и равномерностью нагрузки на чтение

• задача где используется• вычислять качество соединения в 5ти минутных окнах и отображать на карте мира

Page 18: Опыт использования Spark, Основано на реальных событиях

Своя реализация стримера• оффсеты сохраняются после каждого чтения в hbase• чтение партиций равномерное в рамках пула потоков• поддержка партицирования чтения потока• поддержка механизма метрик в спарке (основан на codahale metrics)

• скорость приёма данных• отставание

Page 19: Опыт использования Spark, Основано на реальных событиях

Недостатки реализации• завязан на hbase - надо вынести на уровень апи возможность подсунуть свою реализацию

хранилища• не реализовано восстановление после падения с учётом потери буфера генератора рдд -

нет необходимости это делать, но возможность есть

Page 20: Опыт использования Spark, Основано на реальных событиях

Проблемы внедрения• как и во что собрать? как запускать?

• 3 опции• uberjar + java -jar• spark-submit --deploy-mode client• spark-submit --deploy-mode cluster

• как передать конфиги?• актуально для spark-submit --deploy-mode cluster• решается через --files /path/to/config.xml

• что делать с ошибками сериализации?• понять как работает спарк приложение + рефакторинг кода

val rdd = sc.textFile("") val a = ... val resultRdd = rdd.map {

x => (x, a) }

Page 21: Опыт использования Spark, Основано на реальных событиях

Всё