SlideShare a Scribd company logo
Mining large datasets with
Apache Spark
VyacheslavBaranov,SeniorSoftwareEngineer,OK.RU
Spark на низком уровне
DAG (Directed Acyclic Graph) sheduler
val txt = """The quick brown fox
|jumps over the lazy dog""".stripMargin.toLowerCase
val rdd = sc.parallelize(txt.split("""n"""), 2)
val res = {
rdd
.flatMap(_.split("""s"""))
.filter(_.length > 0)
.map(_ -> 1)
.reduceByKey(_ + _)
.collect()
}
res.foreach { case (word, cnt) => println(s"$word -> $cnt")}
3/24
Narrow dependency (Process)
Для вычисления каждой партиции требуются 1 или несколько родительских
партиций, которые вычисляются локально на каждом из Worker'ов
Примеры операций:
map
sample
coalesce
foreach
·
·
·
·
4/24
Shuffle dependency (Shuffle)
Для вычисления каждой партиции требуются все партиции родительских RDD,
которые вычисляются распределенно и передаются по сети при необходимости.
Примеры операций:
groupByKey
join
repartition
·
·
·
5/24
Collect
Данные собираются с Worker'ов на Master
Примеры операций:
collect
take
·
·
6/24
Итого (1)
Все операции над RDD можно рассматривать, как последовательность
чередующихся операций Transform & Shuffle (возможно, с последующим
Collect), например:
reduce - вычисляются частичные агрегаты для каждой партиции/collect/
окончательная агрегация на Master'е
countByValue - локальная агрегация/при необходимости shuffle с
последующей агрегацией/collect
·
·
7/24
Итого (2)
Минимальная единица вычисления - партиция. То есть, при выполнении любой
операции будет вычислена хотя бы одна партиция:
rdd.take(n) - Примерно эквивалентно rdd.mapPartitions(_.take(n)) с
последующим вычислением одной или нескольких (при необходимости)
партиций.
·
8/24
Итого (3)
До начала вычислением любой партиции вычисляются все партиции, от
которых она зависит. Есть следующие типы зависимостей:
OneToOneDependency/RangeDependency - Каждая партиция зависит ровно от
одной партиции родительского RDD
NarrowDependency - Каждая партиция зависит от нескольких партиций
родительских RDD (используется в coalesce)
ShuffleDependency - Каждая партиция зависит от всех партиций
родительских RDD
·
·
·
9/24
Оптимизация Shuffle
Пример Shuffle
val rdd = sc.parallelize(0 until 1000, 4)
val partitioner = new Partitioner {
override def numPartitions: Int = 6
override def getPartition(key: Any): Int = key.asInstanceOf[Int] % 6
}
val res = {
rdd
.map(_ -> 1)
.partitionBy(partitioner)
.mapPartitionsWithIndex { case (idx, iter) =>
Iterator(idx -> iter.map(_._2).sum)
}
.collect()
}
res.sortBy(_._1).foreach { case (idx, cnt) => println(s"$idx -> $cnt") }
11/24
Как работает Shuffle
Перед shuffle'ом вычисляются все партиции родительского RDD
Каждая партиция разбивается на сегменты, соответствующие партициям
результата
Если сегменты не помещаются в память, они сериализуются и сбрасываются
на диск (spill)
Партиция считается вычисленной, когда все нужные сегменты собраны по
сети
Если до вычисления были потеряны Executor'ы, содержащие нужные
сегменты, соответствующие партиции родительского RDD вычисляются
повторно.
·
·
·
·
·
12/24
Способы оптимизации
Правило №1 Требуется отфильтровывать ненужные данные как можно
раньше
Отказ от полиморфизма (особенно, мелких объектов)
Регистрация сериализаторов
Использование массивов примитивов
Предварительное партиционирование
·
·
·
·
·
13/24
Регистрация сериализаторов
val sparkConf = new SparkConf(...)
...
.set("spark.kryo.classesToRegister",
"mlds.serializer.SerialSeq1,mlds.serializer.SerialBean")
Все, что требуется - до создания SparkContext'а прописать свойство
конфигурации, содержащее все нужные классы (через запятую)
·
14/24
Использование массивов примитивов
case class SerialBean
(
key: Int,
value: Long
)
case class SerialSeq1
(
id: Int,
items: Iterable[SerialBean]
) extends SerialSeq
case class SerialSeq2
(
id: Int,
itemKeys: Array[Int],
itemValues: Array[Long]
) extends SerialSeq {
override def items =
(0 until itemKeys.length).map { i =>
SerialBean(itemKeys(i), itemValues(i))
}
}
Сериализация каждого объекта влечет накладные расходы. Сокращение
количества сериализуемых объектов уменьшает эти накладные расходы.
·
15/24
Размер shuffle
16/24
Время выполнения
17/24
Предварительное партиционирование
Позволяет совсем избежать shuffle
На практике, позволяет ускорить вычисления в десятки/сотни раз
Как этого добиться?
Проблема: Spark не позволяет явным образом загрузить с диска
партиционированные данные
·
·
·
persist/cache
checkpoint
-
-
·
18/24
PrepartitionedRDD
class PrepartitionedRDD[T: ClassTag]
(
prev: RDD[T],
part: Partitioner
) extends RDD[T](prev) {
override val partitioner = Some(part)
override def getPartitions: Array[Partition] = firstParent[T].partitions
override def compute(split: Partition, context: TaskContext): Iterator[T] =
firstParent[T].iterator(split, context)
override protected def getPreferredLocations(split: Partition): Seq[String] =
firstParent[T].getPreferredLocations(split)
}
19/24
Использование PrepartitionedRDD
Внимание: Если партиционирование данных не соответствует объявленному,
результат непредсказуем
Возможные причины:
val src = sc.objectFile[(Int, Long)]("...")
val rdd = new PrepartitionedRDD[(Int, Long)](src,
new HashPartitioner(src.partitions.length))
val res = rdd.groupByKey().mapValues(_.sum).take(10) //No shuffle here
Что-то перепутали (функцию партиционирования и т.п.)
Размер файла больше блока HDFS
InputFormat портит порядок партиций (например, это делает
ParquetInputFormat)
·
·
·
20/24
Оптимизация Transform
Эффективные коллекции
Классы из org.apache.spark.util.collection:
GNU Trove (http://trove.starlight-systems.com/)
·
OpenHashMap
OpenHashSet
PrimitiveVector
CompactBuffer
-
-
-
-
·
22/24
И еще…
Оптимизированная библиотека BLAS на worker'ах
Функции от итераторов, оптимизирующие распределение памяти:
·
·
top(n)/bottom(n)
groupBy/groupByKey
toSortedIterator
-
-
-
23/24
Q & A
Vyacheslav Baranov
Senior Software Engineer
vyacheslav.baranov@corp.mail.ru
https://github.com/SlavikBaranov/mlds
http://stackoverflow.com/users/941206/wildfire
24/24

More Related Content

PDF
Apache spark
PDF
Лекция 12. Spark
PDF
Spark: нетипичные примеры использования
PDF
Опыт использования Spark, Основано на реальных событиях
PDF
13 - Hadoop. Парадигма Spark
PDF
08 - Hadoop. Алгоритмы на графах в MapReduce
PDF
06 - Hadoop. Java API и Hadoop Streaming
PDF
14 - Hadoop. Фреймворк Spark
Apache spark
Лекция 12. Spark
Spark: нетипичные примеры использования
Опыт использования Spark, Основано на реальных событиях
13 - Hadoop. Парадигма Spark
08 - Hadoop. Алгоритмы на графах в MapReduce
06 - Hadoop. Java API и Hadoop Streaming
14 - Hadoop. Фреймворк Spark

What's hot (20)

PDF
Лекция 13. YARN
PDF
Лекция 10. Apache Mahout
PDF
09 - Hadoop. Pig
PPTX
Dennis Anikin - Tarantool Case Studies in Mail.Ru Group
PDF
Дмитрий Новиков - Tarantool в Badoo
PDF
nginx.CHANGES.2015 / Игорь Сысоев, Валентин Бартенев (Nginx)
PDF
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
ODP
Константин Осипов (Mail.Ru)
PDF
Выступление Александра Крота из "Вымпелком" на Hadoop Meetup в рамках RIT++
PPTX
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...
PDF
Лекция 2. Основы Hadoop
PDF
05 - Hadoop. Парадигма MapReduce и фреймворк MapReduce
PDF
Принципы и приёмы обработки очередей / Константин Осипов (Mail.ru)
PDF
Реализация восстановления после аварий / Сергей Бурладян (Avito)
PDF
15 - Hadoop. YARN. MapReduce 2.0
PDF
PostgreSQL: практические примеры оптимизации SQL-запросов / Иван Фролков (Po...
PDF
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
PDF
Осваиваем Tarantool 1.6 / Евгений Шадрин (Sberbank Digital Ventures)
PDF
Современная операционная система: что надо знать разработчику / Александр Кри...
PDF
Apache Spark — Егор Пахомов
Лекция 13. YARN
Лекция 10. Apache Mahout
09 - Hadoop. Pig
Dennis Anikin - Tarantool Case Studies in Mail.Ru Group
Дмитрий Новиков - Tarantool в Badoo
nginx.CHANGES.2015 / Игорь Сысоев, Валентин Бартенев (Nginx)
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
Константин Осипов (Mail.Ru)
Выступление Александра Крота из "Вымпелком" на Hadoop Meetup в рамках RIT++
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...
Лекция 2. Основы Hadoop
05 - Hadoop. Парадигма MapReduce и фреймворк MapReduce
Принципы и приёмы обработки очередей / Константин Осипов (Mail.ru)
Реализация восстановления после аварий / Сергей Бурладян (Avito)
15 - Hadoop. YARN. MapReduce 2.0
PostgreSQL: практические примеры оптимизации SQL-запросов / Иван Фролков (Po...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Осваиваем Tarantool 1.6 / Евгений Шадрин (Sberbank Digital Ventures)
Современная операционная система: что надо знать разработчику / Александр Кри...
Apache Spark — Егор Пахомов
Ad

Viewers also liked (18)

PPTX
20161023 srws第五回補足新しいrob評価 紹介
PDF
Promise me an Image... Антон Корзунов, Яндекс, MoscowJs 33
PPTX
Srws 161124062752
PPTX
20160727 srws第七回@滋賀医大統合、層別・感度分析、欠測への対処
PDF
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
PPTX
Секретные техники продаж корпоративным клиентам / Александр Зиза (Алетейя Биз...
PPTX
6診断精度のメタアナリシス
PPTX
コクランタイトル登録セミナー事後課題Proposal formの作り方
PPTX
20160319コクランタイトル登録WSその2タイトル登録のやり方
PPTX
2. 2016 top 10 md vendors
PPTX
20161106予測指標の作り方セミナー事前学習
PDF
Выход на новые рынки, так ли это сложно организовать / Павел Шинкаренко (Sola...
PPTX
Bullet train in india
PDF
診断研究におけるGRADEアプローチ
PPTX
Letterの書き方
PPTX
8. diy rating
PPTX
Мастер-класс "Микросервисы: удобно, надежно, серебрянопульно" / Евгений Павло...
PDF
Как понять, что происходит на сервере? / Александр Крижановский (NatSys Lab.,...
20161023 srws第五回補足新しいrob評価 紹介
Promise me an Image... Антон Корзунов, Яндекс, MoscowJs 33
Srws 161124062752
20160727 srws第七回@滋賀医大統合、層別・感度分析、欠測への対処
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
Секретные техники продаж корпоративным клиентам / Александр Зиза (Алетейя Биз...
6診断精度のメタアナリシス
コクランタイトル登録セミナー事後課題Proposal formの作り方
20160319コクランタイトル登録WSその2タイトル登録のやり方
2. 2016 top 10 md vendors
20161106予測指標の作り方セミナー事前学習
Выход на новые рынки, так ли это сложно организовать / Павел Шинкаренко (Sola...
Bullet train in india
診断研究におけるGRADEアプローチ
Letterの書き方
8. diy rating
Мастер-класс "Микросервисы: удобно, надежно, серебрянопульно" / Евгений Павло...
Как понять, что происходит на сервере? / Александр Крижановский (NatSys Lab.,...
Ad

More from MoscowDataFest (7)

PPTX
DF1 - R - Natekin - Improving Daily Analysis with data.table
PDF
DF1 - Py - Kalaidin - Introduction to Word Embeddings with Python
PDF
DF1 - Py - Ovcharenko - Theano Tutorial
PPTX
DF1 - ML - Petukhov - Azure Ml Machine Learning as a Service
PDF
DF1 - ML - Vorontsov - BigARTM Topic Modelling of Large Text Collections
PPTX
DF1 - DL - Lempitsky - Compact and Very Compact Image Descriptors
PDF
DF1 - BD - Degtiarev - Practical Aspects of Big Data in Pharmaceutical
DF1 - R - Natekin - Improving Daily Analysis with data.table
DF1 - Py - Kalaidin - Introduction to Word Embeddings with Python
DF1 - Py - Ovcharenko - Theano Tutorial
DF1 - ML - Petukhov - Azure Ml Machine Learning as a Service
DF1 - ML - Vorontsov - BigARTM Topic Modelling of Large Text Collections
DF1 - DL - Lempitsky - Compact and Very Compact Image Descriptors
DF1 - BD - Degtiarev - Practical Aspects of Big Data in Pharmaceutical

DF1 - BD - Baranov - Mining Large Datasets with Apache Spark

  • 1. Mining large datasets with Apache Spark VyacheslavBaranov,SeniorSoftwareEngineer,OK.RU
  • 2. Spark на низком уровне
  • 3. DAG (Directed Acyclic Graph) sheduler val txt = """The quick brown fox |jumps over the lazy dog""".stripMargin.toLowerCase val rdd = sc.parallelize(txt.split("""n"""), 2) val res = { rdd .flatMap(_.split("""s""")) .filter(_.length > 0) .map(_ -> 1) .reduceByKey(_ + _) .collect() } res.foreach { case (word, cnt) => println(s"$word -> $cnt")} 3/24
  • 4. Narrow dependency (Process) Для вычисления каждой партиции требуются 1 или несколько родительских партиций, которые вычисляются локально на каждом из Worker'ов Примеры операций: map sample coalesce foreach · · · · 4/24
  • 5. Shuffle dependency (Shuffle) Для вычисления каждой партиции требуются все партиции родительских RDD, которые вычисляются распределенно и передаются по сети при необходимости. Примеры операций: groupByKey join repartition · · · 5/24
  • 6. Collect Данные собираются с Worker'ов на Master Примеры операций: collect take · · 6/24
  • 7. Итого (1) Все операции над RDD можно рассматривать, как последовательность чередующихся операций Transform & Shuffle (возможно, с последующим Collect), например: reduce - вычисляются частичные агрегаты для каждой партиции/collect/ окончательная агрегация на Master'е countByValue - локальная агрегация/при необходимости shuffle с последующей агрегацией/collect · · 7/24
  • 8. Итого (2) Минимальная единица вычисления - партиция. То есть, при выполнении любой операции будет вычислена хотя бы одна партиция: rdd.take(n) - Примерно эквивалентно rdd.mapPartitions(_.take(n)) с последующим вычислением одной или нескольких (при необходимости) партиций. · 8/24
  • 9. Итого (3) До начала вычислением любой партиции вычисляются все партиции, от которых она зависит. Есть следующие типы зависимостей: OneToOneDependency/RangeDependency - Каждая партиция зависит ровно от одной партиции родительского RDD NarrowDependency - Каждая партиция зависит от нескольких партиций родительских RDD (используется в coalesce) ShuffleDependency - Каждая партиция зависит от всех партиций родительских RDD · · · 9/24
  • 11. Пример Shuffle val rdd = sc.parallelize(0 until 1000, 4) val partitioner = new Partitioner { override def numPartitions: Int = 6 override def getPartition(key: Any): Int = key.asInstanceOf[Int] % 6 } val res = { rdd .map(_ -> 1) .partitionBy(partitioner) .mapPartitionsWithIndex { case (idx, iter) => Iterator(idx -> iter.map(_._2).sum) } .collect() } res.sortBy(_._1).foreach { case (idx, cnt) => println(s"$idx -> $cnt") } 11/24
  • 12. Как работает Shuffle Перед shuffle'ом вычисляются все партиции родительского RDD Каждая партиция разбивается на сегменты, соответствующие партициям результата Если сегменты не помещаются в память, они сериализуются и сбрасываются на диск (spill) Партиция считается вычисленной, когда все нужные сегменты собраны по сети Если до вычисления были потеряны Executor'ы, содержащие нужные сегменты, соответствующие партиции родительского RDD вычисляются повторно. · · · · · 12/24
  • 13. Способы оптимизации Правило №1 Требуется отфильтровывать ненужные данные как можно раньше Отказ от полиморфизма (особенно, мелких объектов) Регистрация сериализаторов Использование массивов примитивов Предварительное партиционирование · · · · · 13/24
  • 14. Регистрация сериализаторов val sparkConf = new SparkConf(...) ... .set("spark.kryo.classesToRegister", "mlds.serializer.SerialSeq1,mlds.serializer.SerialBean") Все, что требуется - до создания SparkContext'а прописать свойство конфигурации, содержащее все нужные классы (через запятую) · 14/24
  • 15. Использование массивов примитивов case class SerialBean ( key: Int, value: Long ) case class SerialSeq1 ( id: Int, items: Iterable[SerialBean] ) extends SerialSeq case class SerialSeq2 ( id: Int, itemKeys: Array[Int], itemValues: Array[Long] ) extends SerialSeq { override def items = (0 until itemKeys.length).map { i => SerialBean(itemKeys(i), itemValues(i)) } } Сериализация каждого объекта влечет накладные расходы. Сокращение количества сериализуемых объектов уменьшает эти накладные расходы. · 15/24
  • 18. Предварительное партиционирование Позволяет совсем избежать shuffle На практике, позволяет ускорить вычисления в десятки/сотни раз Как этого добиться? Проблема: Spark не позволяет явным образом загрузить с диска партиционированные данные · · · persist/cache checkpoint - - · 18/24
  • 19. PrepartitionedRDD class PrepartitionedRDD[T: ClassTag] ( prev: RDD[T], part: Partitioner ) extends RDD[T](prev) { override val partitioner = Some(part) override def getPartitions: Array[Partition] = firstParent[T].partitions override def compute(split: Partition, context: TaskContext): Iterator[T] = firstParent[T].iterator(split, context) override protected def getPreferredLocations(split: Partition): Seq[String] = firstParent[T].getPreferredLocations(split) } 19/24
  • 20. Использование PrepartitionedRDD Внимание: Если партиционирование данных не соответствует объявленному, результат непредсказуем Возможные причины: val src = sc.objectFile[(Int, Long)]("...") val rdd = new PrepartitionedRDD[(Int, Long)](src, new HashPartitioner(src.partitions.length)) val res = rdd.groupByKey().mapValues(_.sum).take(10) //No shuffle here Что-то перепутали (функцию партиционирования и т.п.) Размер файла больше блока HDFS InputFormat портит порядок партиций (например, это делает ParquetInputFormat) · · · 20/24
  • 22. Эффективные коллекции Классы из org.apache.spark.util.collection: GNU Trove (http://trove.starlight-systems.com/) · OpenHashMap OpenHashSet PrimitiveVector CompactBuffer - - - - · 22/24
  • 23. И еще… Оптимизированная библиотека BLAS на worker'ах Функции от итераторов, оптимизирующие распределение памяти: · · top(n)/bottom(n) groupBy/groupByKey toSortedIterator - - - 23/24
  • 24. Q & A Vyacheslav Baranov Senior Software Engineer vyacheslav.baranov@corp.mail.ru https://github.com/SlavikBaranov/mlds http://stackoverflow.com/users/941206/wildfire 24/24