Пост, на этот раз про распределённые системы. Я не хочу делать вид, что занимаюсь только низкоуровневыми вещами, тем более на работе я занимаюсь распределёнными системами full time, а вот это всё мои хобби сверху (почти :-)).
В MapReduce/Spark часто возникают проблемы stragglers. Когда какая-то машина тупит, и дальше становится непонятно, что происходит:
1. Попался кусок данных, который невозможно долго процессится? Банальный пример: обрабатываете youtube id и встретилось 10 часовое видео
2. Это Shuffle/Reduce операция, где есть так называемые hot keys? То есть есть ключ, у которого большая порция всего, когда вы делаете Group By операции?
3. А может быть просто машина тупит?
4. А может быть данные перекошены и хоть и нет никакой записи, которая долго выполняется, а шард долго работает?
В общем, практика показывает, что самые частые проблемы возникают в пунктах 2 и 3. Пункт 2 можно детектить алгоритмически, а вот понять пункт 3 уже становится очень сложно, потому что неясно, имеет ли это что-то общее с п 1 или 4.
Придумали решение с так называемыми backups, или по-другому их называют, speculative execution: давайте если какой-то кусок работы тупит, мы сделаем копию и запроцессим два одинаковых куска данных, посмотрим, кто первый закончит.
Обычно это помогает с п.3 и достаточно хорошо работает.
Какие бывают стратегии?
Quantile backup или End-game-backup
Дана квантиль X, мы сделаем две реплики всех после процессинга всех X шардов. Скажем, если X=0.75 (дефолт у Spark), то после 75% всех выполненных шардов, мы оставшихся 25% всех самых медленных задуплицируем.
Skewed backup
Дано число X > 1, мы запускаем backup у тех, кто работает в X раз дольше медианного времени. Дефолт у Spark 1.5.
Min threshold
Чтобы применить что-то выше, нужно подождать ещё какое-то время и убедиться, что действительно надо запускать. Скажем, одну минуту подождать, чтобы запустить skewed backup или end-game backup. В spark этого нет вообще.
Тут вот LinkedIn в своём докладе про Speculative Execution в Spark написал, что правильная policy включения backups принесла им 13-40% меньше времени выполнения и даже сэкономила ресурсы. То, что они поняли:
* Дефолтные значения агрессивны. End-game backup решили включать на 90%, а не на 75% (если честно, моя интуиция тоже так говорит)
* Skewed backup. X = 1.5 тоже было агрессивным. Они поставили 4. По мне многовато, мой опыт говорит в районе 2.5-3 обычно бывает оптимально. Зависит от пайплайна и достаточно легко выучивается по истории.
* Min threshold важен. Мелкие джобы слишком много плодили различных workers и кластер превращался в мусор. Заимплементировали в spark, чтобы подождать 30 секунд для включения skewed/end-game backups
* Сильно улучшили variance, spark/mapreduce всегда страдал от погоды на кластере, тут получше получается, понятно почему, утилизируется кластер намного лучше.
* Даже RAM+CPU уменьшилось (хотя казалось бы, мы включаем доп работу), скорее всего из-за простоя
В общем, backup execution, hedged requests, также как и power of two choices балансировка сильно экономит вам перформанса, если правильно сварить. По мне, некоторые вещи можно выучивать исторически, смотреть как кластер себя ведёт и тд, но то, как обучать перформанс повторяющихся джобов, мы поговорим отдельно.
Распределенные системы такие, да. Speculative execution очень приятно писать в коде, кстати, по себе знаю :) И очень тяжело дебагать, если что-то пошло не так (true story, зафакапили десяток пайплайнов).
В MapReduce/Spark часто возникают проблемы stragglers. Когда какая-то машина тупит, и дальше становится непонятно, что происходит:
1. Попался кусок данных, который невозможно долго процессится? Банальный пример: обрабатываете youtube id и встретилось 10 часовое видео
2. Это Shuffle/Reduce операция, где есть так называемые hot keys? То есть есть ключ, у которого большая порция всего, когда вы делаете Group By операции?
3. А может быть просто машина тупит?
4. А может быть данные перекошены и хоть и нет никакой записи, которая долго выполняется, а шард долго работает?
В общем, практика показывает, что самые частые проблемы возникают в пунктах 2 и 3. Пункт 2 можно детектить алгоритмически, а вот понять пункт 3 уже становится очень сложно, потому что неясно, имеет ли это что-то общее с п 1 или 4.
Придумали решение с так называемыми backups, или по-другому их называют, speculative execution: давайте если какой-то кусок работы тупит, мы сделаем копию и запроцессим два одинаковых куска данных, посмотрим, кто первый закончит.
Обычно это помогает с п.3 и достаточно хорошо работает.
Какие бывают стратегии?
Quantile backup или End-game-backup
Дана квантиль X, мы сделаем две реплики всех после процессинга всех X шардов. Скажем, если X=0.75 (дефолт у Spark), то после 75% всех выполненных шардов, мы оставшихся 25% всех самых медленных задуплицируем.
Skewed backup
Дано число X > 1, мы запускаем backup у тех, кто работает в X раз дольше медианного времени. Дефолт у Spark 1.5.
Min threshold
Чтобы применить что-то выше, нужно подождать ещё какое-то время и убедиться, что действительно надо запускать. Скажем, одну минуту подождать, чтобы запустить skewed backup или end-game backup. В spark этого нет вообще.
Тут вот LinkedIn в своём докладе про Speculative Execution в Spark написал, что правильная policy включения backups принесла им 13-40% меньше времени выполнения и даже сэкономила ресурсы. То, что они поняли:
* Дефолтные значения агрессивны. End-game backup решили включать на 90%, а не на 75% (если честно, моя интуиция тоже так говорит)
* Skewed backup. X = 1.5 тоже было агрессивным. Они поставили 4. По мне многовато, мой опыт говорит в районе 2.5-3 обычно бывает оптимально. Зависит от пайплайна и достаточно легко выучивается по истории.
* Min threshold важен. Мелкие джобы слишком много плодили различных workers и кластер превращался в мусор. Заимплементировали в spark, чтобы подождать 30 секунд для включения skewed/end-game backups
* Сильно улучшили variance, spark/mapreduce всегда страдал от погоды на кластере, тут получше получается, понятно почему, утилизируется кластер намного лучше.
* Даже RAM+CPU уменьшилось (хотя казалось бы, мы включаем доп работу), скорее всего из-за простоя
В общем, backup execution, hedged requests, также как и power of two choices балансировка сильно экономит вам перформанса, если правильно сварить. По мне, некоторые вещи можно выучивать исторически, смотреть как кластер себя ведёт и тд, но то, как обучать перформанс повторяющихся джобов, мы поговорим отдельно.
Распределенные системы такие, да. Speculative execution очень приятно писать в коде, кстати, по себе знаю :) И очень тяжело дебагать, если что-то пошло не так (true story, зафакапили десяток пайплайнов).