Как сделать вычислительную инфраструктуру для большого кластера


The Presentation inside:

Slide 0

Как сделать вычислительную инфраструктуру для большого кластера Евгений Кирпичёв Станислав Лагун Mirantis Inc. www.mirantis.com


Slide 1

Введение и Архитектура Доставка задач/результатов Отладка и анализ Обобщение опыта: корректность, надежность, производительность


Slide 2

О нас Mirantis делает проекты на заказ: Высокотехнологичные, иногда долгосрочные, для «топовых» заказчиков (Cisco, Mentor Graphics, Cadence, GE, …) В основном – масштабируемые системы, клауды, research


Slide 3

Что мы строим Очень тяжелые вычисления (но очень параллельные) Простой API – задача = поток подзадач: CreateJob, SubmitTask, OnResult Много одновременных задач разной важности Очень разнородные вычисления: От секунд (нужна интерактивность) до дней (но не мешать чужой интерактивности) Задействовать кластер целиком Устойчивость к временным падениям компонент (и к перманентным падениям вычислительных узлов)


Slide 4

Обычно (на суперкомпьютерах) используют: Это называется «batch scheduler»


Slide 5

Нам не подходит Они предполагают: Планировщик ничего не знает про задачу Просто выделяет ядра Задачи монолитны «Мне надо 100 ядер» Как появится 100 ядер – запустят На 99 не запустят Есть куча сложных правил и квот Акцент на фичи, а не на эффективность Без этих предположений можно сделать эффективнее.


Slide 6

Терминология Задача = поток задачек


Slide 7

Становятся возможными некоторые трюки для повышения утилизации. But this margin is too small…


Slide 8

Пример неудачной архитектуры Очевидно, single bottleneck – не масштабируется +балансировка нагрузки очень математически нестабильна Клиент 1 Клиент 2 Клиент 3 брокер


Slide 9

Более удачная архитектура Планировщик Слушает команды о запуске-останове задач Приказывает демонам обслуживать задачи Трубы (как очереди, только шире) Доставляют задачки и ответики Вычислительные демоны на узлах Слушаются планировщика Тянут из очереди задачки, считают, публикуют ответики +клиенты +статистика +логгирование +мониторинг


Slide 10

Пример Клиент – Планировщику: Создай задачу A, важность 30% Планировщик (выбирает несколько демонов) – демонам: Ты, ты и ты – бросайте всё и подключайтесь к трубе А. Клиент бросает задачки в трубу А Демоны считают, бросают ответики Клиент собирает ответики, бросает новые задачки и т.п.


Slide 11

Введение и Архитектура Доставка задач/результатов Отладка и анализ Обобщение опыта: корректность, надежность, производительность


Slide 12

Трубы Как очереди Только шире, быстрее и неупорядоченные На основе RabbitMQ Лучший продукт в своем классе (надежная доставка) Но «из коробки» сам по себе не масштабируется


Slide 13

Надежная доставка Цикл жизни демона: Получить задачку Посчитать Отослать ответик Подтвердить получение задачки Если помрет, RabbitMQ заметит и перешлет задачку другому.


Slide 14

Масштабирование Из коробки RabbitMQ совсем не подходит Одна очередь плохо тянет 10000 клиентов Встроенная кластеризация делает не то От нее вообще лучше отказаться (одни проблемы) Очевидное решение: несколько очередей + load balancing


Slide 15

Масштабирование Голова задачи (подбираются демонами) задачки Голова задачи ответики (отсылаются демонами) Демон выбирает случайного кролика и всю жизнь работает с ним


Slide 16

Трудности Маленький лимит соединений у RabbitMQ под Windows (не потянет 500-1000 машин) Решено: каждая машина подключается к кому-нибудь одному Не терять данные при крахах демонов Решено: подтверждения тасков Переустанавливать соединение при случайных разрывах связи Не терять данные при крахах RabbitMQ RabbitMQ не гарантирует безопасность данных вне транзакции! Не перегружать RabbitMQ Иначе начинаются ужасы (тормоза, разрывы связи, крахи) Поддерживать асинхронные прерывания (немедленное переключение) без потери данных Самая сложная часть Переключаться на другой RabbitMQ, если в этом кончились задачки (иначе starvation)


Slide 17

Сохранность данных при крахах RabbitMQ Client RabbitMQ Disk fsync fsync fsync 0..3 Publish confirmations Клиент буферизует сообщения, про которые еще не известно, на диске ли они. При разрыве связи повторить «возможно-утерянные» сообщения. 4..5 6..7


Slide 18

Не перегружать RabbitMQ Если слишком яро слать сообщения, RabbitMQ захлебнется (не успевая писать на диск) Тормоза, крахи, потеря соединения Белое – «ждем задачи» доставка тормозит, или реконнектимся


Slide 19

Не перегружать RabbitMQ Оказывается, отличная метрика загрузки – число/размер неподтвержденных сообщений 4 задачи, 4 разноцветных кролика Один кролик не поспевает.


Slide 20

Не перегружать RabbitMQ Ограничить число сообщений «в полете» На каждого кролика? Нет, тогда один медленный будет всех тормозить А как тогда? Давать очередное сообщение случайному неперегруженному.


Slide 21

Около 5000 ядер, 4 RabbitMQ Нет перегрузок – нет проблем


Slide 22

Поддерживать асинхронные прерывания Иногда надо всё бросить и заняться другой задачей Прервать запущенную задачку и кинуть обратно в трубу Или прервать ожидание задачки Порвать соединения с трубами предыдущей задачи Убедиться, что все ответики и отклоненные задачки точно сохранены на диск Об этом мы узнаем из другого потока Многопоточность – это всегда ад К счастью, это почти единственное использование многопоточности Но все равно ад.


Slide 23

Переключаться между кроликами Задаче досталось несколько демонов. 3 подключены к rmq1, 1 к rmq2 Дисбаланс Голодание Нет задачек в нашем – переключимся на другой А если он отвалился? А если в нем тоже нет? А если нигде нет? (избегать бури реконнектов) Нельзя надолго создавать дисбаланс нагрузки на кроликов Нужно найти того, где есть, как можно быстрее Решение есть, немножко хитрое, нет времени рассказать ?


Slide 24

Как это закодировать Можно сделать лапшу, делающую все сразу Реконнекты, подтверждения доставки, переключение, балансировка, асинхронные прерывания…


Slide 25

Как не сойти с ума Разумеется, слои*. *Паттерны Adapter, Composite etc, они же Combinator Library


Slide 26

Слои API проще некуда: Отсыльщик: Отослать Получить/сбросить список неподтвержденных Уничтожиться (возможно, асинхронно) Слушатель: Достать сейчас (blocking + timeout) Достать потом (callback) Уничтожиться (возможно, асинхронно)


Slide 27

Слои «При ошибке переоткрыться» «При ошибке попробовать еще раз» «При ошибке сделать то-то и то-то» «Преобразовать тип сообщения» «Слушать сразу несколько» «Балансировать отправку между несколькими» «Игнорировать неподтвержденные при закрытии»


Slide 28

Например По числу кроликов задачки ответики


Slide 29

Введение и Архитектура Доставка задач/результатов Отладка и анализ Обобщение опыта: корректность, надежность, производительность


Slide 30

Отладка и анализ Дебаггер – не вариант (только для локальных тестов) Где и когда произойдет ошибка – заранее неизвестно Post mortem отладка по логам And you have to be pretty damn good at it Это не логи вебсервера, где все реквесты независимы Несколько взаимодействующих, иногда многопоточных подсистем Проблемы с корректностью – недетерминированы Проблемы с производительностью – не локальны Логов, по нашим меркам, дофига (тысячи важных сообщений в сек.)


Slide 31

Пара фокусов в рукаве Мощный логгер Глобальная ось времени (точнее, чем NTP) Тянет сотни тысяч сообщений в секунду от тысяч клиентов http://code.google.com/p/greg – опенсорс-версия Ставим 1шт. на кластер, получаем точную глобальную картину (без мучений со специальным сбором-слиянием логов) GNU textutils + awk (пока хватает, MapReduce не юзаем) timeplotters – две специальных рисовалки http://jkff.info/software/timeplotters/


Slide 32

Мы рисуем http://jkff.info/software/timeplotters/


Slide 33

http://jkff.info/software/timeplotters/


Slide 34

Что для этого нужно? Очень подробные логи. Еще об этом – позже.


Slide 35

Введение и Архитектура Доставка задач/результатов Отладка и анализ Обобщение опыта: корректность, надежность, производительность


Slide 36

Корректность: Главный принцип Как писать правильный код?


Slide 37

Корректность: Главный принцип Код точно неправильный. Как быть?


Slide 38

Как быть? Быть скромнее Дать себе шанс найти ошибку Минимизировать «ядро корректности» Минимизировать распространение ошибки Избегать опасных приемов


Slide 39

Быть скромнее Не думать «ничего, отладим» Это будет стоить вам увеличения времени разработки в разы Не лепить все фичи сразу: Каждый раз приходится разломать и отлаживать по отдельности Безжалостно уничтожать некритичные фичи Единственный их эффект – усложнение отладки


Slide 40

Цитаты в тему «Write the simplest thing that could possibly work» Ward Cunningham «Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it» Brian Kernighan


Slide 41

Дать себе шанс найти ошибку Максимально подробные логи Не бывает «слишком много логов» Не бывает «от логгирования код некрасивый»


Slide 42

Минимизировать «ядро корректности» Часть, от корректности которой зависит работоспособность системы. Веб-сервер: Неправильное вычисление в процессе обработки запроса ? неправильный ответ Дедлок в пуле сокетов ? виснет весь сервер


Slide 43

Минимизировать распространение ошибки Расставлять «барьеры» До барьера – будь что будет После барьера верны некоторые свойства Барьер должен быть очень надежен


Slide 44

Барьеры Уничтожение процесса (выполнение действия в отдельном процессе) Защищает от утечек ресурсов внутри процесса Периодический перезапуск системы Защищает от неограниченно долгих зависаний Закрытие соединения с очередью В худшем случае (неподтвержденная)задача будет сдублирована Eventual consistency negative feedback, периодическая сверка желаемого и действительного


Slide 45

Избегать опасных приемов Изменяемое состояние Многопоточность Блокирование, синхронизация Обратная связь Редко выполняющийся код


Slide 46

Введение и Архитектура Доставка задач/результатов Отладка и анализ Обобщение опыта: корректность, надежность, производительность


Slide 47

Надежность Всё перезапускаемо и готово к перезапуску остальных Asynchronous one-way messaging (противоположность RPC) Явно формулировать переход ответственности за целостность данных Все компоненты готовы к дублям и потерям данных Eventual consistency


Slide 48

Перезапускаемость Если она есть: Можно перезапустить оборзевший процесс Можно навсегда забыть о редких крахах Можно перезапускать процесс периодически и забыть навсегда об утечках и зависаниях Если ее нет: Надо вылизывать код, пока не исчезнут самые маловероятные крахи и утечки Если крах не по вашей вине (ОС, библиотека...) – это все равно ваши проблемы.


Slide 49

Asynchronous, one-way messaging Противоположность RPC, прямое следствие из перезапускаемости. Лучше возложить ответственность за доставку сообщений на софт, который хорошо умеет это делать. Или использовать ненадежный транспорт (UDP).


Slide 50

Eventual consistency Стремление к согласованности


Slide 51

Eventual consistency Client RabbitMQ Disk fsync fsync fsync 0..3 Publish confirmations 4..5 6..7 Клиент и кролик постепенно согласуют знание о том, какие данные надежно сохранены


Slide 52

Eventual consistency Master Slave Хозяин и раб постепенно согласуют представление о том, чем рабу надо заниматься «Займись B» «Занимаюсь A» «Займись B» «Занимаюсь B»


Slide 53

Введение и Архитектура Доставка задач/результатов Отладка и анализ Обобщение опыта: корректность, надежность, производительность


Slide 54

Производительность Несколько аспектов: Стабильность под нагрузкой Пропускная способность Задержка


Slide 55

Главное Ресурсы конечны


Slide 56

Какие ресурсы конечны Вот что кончалось у нас: Соединения с RabbitMQ Erlang-процессы в RabbitMQ Cинхронные AMQP-операции / сек. (e.g. queue.declare) с RabbitMQ Установленные соединения / сек. с RabbitMQ Установленные соединения / сек. с логгером Внутренние буферы сообщений в логгере Место в пуле потоков (медленно разгребался) Одновременные RPC-вызовы Место на диске CPU и диск одной машины, куда погрузили два сервиса сразу Успешно проходящие UDP-пакеты по нагруженному каналу Транзакции RabbitMQ в секунду (чего уж там – в минуту) Терпение при анализе больших логов Память у инструментов рисования логов ...


Slide 57

Мораль Планируйте потребление ресурсов Особенно таких, потребление которых растет с масштабом Особенно централизованных Центральные одноэкземплярные сервисы Сеть Учитывайте паттерн загрузки! Его бывает трудно предсказать Наивные бенчмарки нерепрезентативны


Slide 58

Пропускная способность Избегайте обратной связи Из-за нее задержка начинает уменьшать пропускную способность Задержку оптимизировать гораздо труднее


Slide 59

Задержка Прогнозируйте и измеряйте Уменьшайте длину цепи задержки Избегайте компонентов с непредсказуемой задержкой Избегайте централизованных компонентов на пути запроса Не делите ресурсы между throughput-sensitive и latency-sensitive компонентами Плохая идея использовать один и тот же RabbitMQ и для команд, и для задач Рано или поздно придется управлять приоритетами запросов/действий вручную Понадобятся не просто очереди, а приоритетные очереди


×

HTML:





Ссылка: