Наверх ▲

Высокая нагрузка на erlang-приложения: erlyvideo на гигабитном канале

Максим Лапшин Максим Лапшин Автор проекта Erlyvideo.ru, до этого — веб-разработчик.

Макс Лапшин: Добрый день, меня зовут Макс Лапшин. Я занимаюсь проектами видеостримингового сервера Эрливидео. Это серверное ПО, которое устанавливается на "железо" и занимается раздачей потокового видео на все современные клиенты: Flash, iPhone, Android и прочие. 

Я хочу рассказать о том, как мы адаптировали Эрливидео к большим нагрузкам, когда мы с ними столкнулись. А также о том, что собой представляет Эрливидео в том контексте, в котором мы сейчас будем говорить. 

Сейчас будем говорить только о потоковом видео. Например, видео с этой конференции раздается пользователям в виде прямого эфира. Приходится обрабатывать очень много разных протоколов: MREG-TS, RTMP. Огромное количество протоколов. Некоторые из этих протоколов порождают очень высокие нагрузки на сервер. Поэтому нам приходится с ними работать.

Какими бывают профили нагрузки на потоковый сервер? Один профиль нагрузки, с которым сталкивались ребята из Badoo, когда пытались запустить Эрливидео, – это видеочат. Он характеризуется тем, что у вас много пар соединений. Один источник, один клиент. Это одна история.

Сейчас мы будем говорить о несколько иной ситуации, в которой у вас один источник, и у него есть тысячи и тысячи клиентов. Условно говоря, когда мы говорим про интернет-телевидение.

Что представляет собой видео в контексте нашего доклада? В целом в хорошем видеопотоке 25 кадров в секунду, примерно столько же аудиокадров. Итого мы имеем 50 кадров в секунду примерно на один аудио- и видеопоток. 

Когда подключено 2 тысячи клиентов, мы получаем около 100 тысяч событий, кадров в секунду, которые надо обработать. Вся беда в том, что этот гигабит видео, который формирует около 100 тысяч событий, обрабатывать проблемно.

В чем проблема? Ведь MREG-TS даже применяя Python можно гигабитами раздавать. RTMP – это протокол, по которому подключается Adobe Flash Player. 95-99 % обычных пользовательских компьютеров поддерживают RTMP. Вы можете отдать туда видео. 

RTMP отличается тем, что для каждого клиента формируется свой собственный поток. К сожалению, вы не можете обойтись простым копированием данных. Необходимо под каждого подключенного клиента делать свои данные. Я думаю, можно догадаться, какие с этим возникают проблемы. Вы не можете сделать одну большую очередь и раздавать всем данные из нее. Под две тысячи клиентов генерируются две тысячи разных буферов.

Однако кое-какие облегчения есть. Можно при некоторых условиях, при некоторых допущениях добиться того, чтобы данные между клиентами были общими, а заголовки разными. Это создает большие сложности при программировании.

Чем еще характеризуется RTMP? К сожалению, Flash Player – это не VLC. Он написан в Adobe индусами. Без комментариев. Написан он сложно. Работать с ним действительно очень сложно. Самое главное: при работе с RTMP-клиентами огромная сложность заключается в мониторинге того, что у вас происходит.

Например, если клиенту немного не хватает скорости, он начинает "залипать" и "недовыгребать" данные. Это еще можно как-то контролировать. Но есть и другие "прелести". 

Например, у вас произошел скачок времени в потоке. Допустим, камеру подключили – выключили обратно, у вас произошел скачок времени, потому что кодирующая программа начала считать его по-другому. Всё, все клиенты, которые были, "залипли". Они перестали делать чтение с сокета. 

Эти проблемы очень сложно мониторятся. Со стороны сервера их можно отмониторить только по росту очереди исходящего/входящего соединения у клиента. Надо что-то делать, если вы понимаете, что клиенты не "выгребают" данные. 

Сервер может понять только одну вещь: клиент перестал читать данные по сети. Необходимо каким-то образом догадаться, что с же этим делать, чтобы правильно это обработать. Так у вас подключено две тысячи клиентов (две, четыре, больше). 

Делать можно разные вещи. Например, можно отключать видеопоток. Можно отключать аудиопоток. Как правило, это не имеет смысла. Если у клиента канал "провалился", и он не может "выгребать" ваше видео, ему вообще нечего делать здесь. Его надо отправить на другой поток с меньшей скоростью либо просто отказать ему в обслуживании.

 

Мы столкнулись со всеми проблемами, которые есть у Flash Player, когда начали "выкатывать" Эрливидео на все более и более массовые сайты. Они начались у нас после рубежа в 800 клиентов. Эрливидео при версии 1.0 мог держать около 800 клиентов, и все. 

Дальше начинались проблемы, он просто не справлялся. Люди отключались, не получая видео равномерно. Нам пришлось профилировать, выяснять, мониторить и учиться профилировать приложения на Erlang. Для нас это было в новинку, потому что об этом было очень мало информации.

 

Какие проблемы возникают при профилировании сервера, который обслуживает один гигабит данных (один, два гигабита и больше)? Проблема в том, что вы не можете воспроизвести это на локальной машине. Более того, это сложно воспроизвести у себя в офисе. Это действительно очень сложно. Даже если вы сделаете большой отдел нагрузочного тестирования, который будет что-то имитировать, проверяться все равно будет то, что творится у вас в офисе. 

Когда вы ставите это на продакшн, запускаете пользователей, начинается нечто совершенно другое. Это разнообразные версии Flash Player, Windows и другие ситуации, с которыми очень сложно бороться.

В целом, конечно, все чаще всего упирается в нюансы с каналами и разными версиями клиентов. Скажем, в одной версии Flash Player надо писать одни данные, в другой – другие. Это все очень сложно учесть. Безусловно, финальная стадия профилирования всегда на продакшне. А это большие проблемы.

С чем же бывают проблемы? Это не профилирование HTTP-сервера, когда запрос длится 30, 100, 200, 500 миллисекунд. У вас идет подключение, которое может длиться, например, 10 часов, 20 часов или даже неделю. Вам необходимо использовать методики профилирования, которые позволяют не отключать клиентов, во-первых. Во-вторых, обходиться без деградации системы.

Если вы хотите понять, что творится при двух тысячах клиентов, когда загрузка на полную, заходите… Чаще всего это делается сервером. Если это приводит к деградации, вы теряете клиентов. Остается 200 клиентов на сервер, и все. Вы своими измерениями разрушите измеряемую систему.

Когда я делал все то же самое на платформе Objective-C, Valgrind, профилировщики, gdb были лучшими друзьями. Как без них можно работать с "Си", я не знаю. Но с ними проблемы.

Например, тот же Valgrind позволяет вам разобраться с ошибками. Конечно, он не решить проблемы со скоростью. Но подключить пять клиентов с помощью Valgrind уже бывает невозможно. Он вносит чудовищные искажения. 

Если вам нужно gdb, с ним та же самая история. Вы делаете отладочную сборку, которая во много раз медленнее и совершенно по-другому себя ведет.

То же самое с профилировщиками. Все инструменты, которые есть для C++, вносят искажения. С ними проблемы. Что с Java – я, честно говоря, не знаю. Думаю, что тоже не сахар.

С чем же я столкнулся, когда мы начали работать с Эрливидео? Выяснилось, что в Erlang другие подходы к профилированию в принципе. Таких инструментов для профилирования, которые есть для C++, в нем просто нет. Но, как выяснилось, они просто особо и не нужны. В них нет такой жесткой необходимости.

Для начала немного про сам Erlang, чтобы вам не было страшно. Что собой представляет Erlang? 

В Erlang принята концепция, очень похожая на операционную систему, на сам Unix. Данные и потоки пополнения "склеены" вместе в одну сущность, очень похожую на процессы операционной системы. Они так и называются – процессы. Коммуникация между ними происходит не прямым вызовом методов в другом объекте, а посылкой сообщений из одного процесса в другой. Это очень похоже на обычную операционную систему. Это очень удобно.

У каждого процесса есть свой "message box", который может расти неограниченно.

В процессах находятся немутабельные данные. У вас даже нет операции "поправить какие-то данные".

Сам процесс – это такая рекурсивная функция, которая сама себя вызывает. Вокруг немутабельности данных и изоляции данных внутри одного процесса, который является потоком, построена вся система.

Какой подход принят в Erlang для обработки клиентов?

Под каждого клиента один, два или более процессов. Процесс и объект – это очень похожие по использованию вещи. То, что является объектом в Java, тут будет процессом. Но есть некоторые отличия. 

Например, на объекте, который существует в программе на C++ или в Java, вы можете вызвать метод из двух разных потоков одновременно. Они действительно будут выполняться одновременно. Вам нужны мьютексы, блокировки и прочие вещи. 

В Erlang такого нет. Каждый процесс обрабатывает входящее сообщение строго последовательно, потому что он не может выполнить два одновременно. Это обозначает, что на всех объектах методы строго синхронны. Они чисто семантически выполняются синхронно.

Какая в этой базовой архитектуре получается архитектура при малой нагрузке?

Под каждого клиента заводится свой процесс. Есть процессы, которые обслуживают сам поток. Это тот процесс, к которому подключается, скажем, видеокамера. Клиенты приходят к потоку, подписываются на видеокадры, получают эти видеокадры в виде сообщений и пишут их в свои сокеты.

Что мы имеем? Для начала, у нас в системе получается двухтысячекратное дублирование упаковки RTMP-протокола. Во-вторых, у нас получается 100 тысяч сообщений, которые "протекают" по системе. Несмотря на всю фантастическую эффективность, в систему рассылки сообщений Erlang вложено столько времени, что она безумно эффективна. Но даже ее не хватает на то, чтобы эффективно "прокачать" 100 тысяч сообщений по всем пяти, шести, восьми ядрам. Получается, что один процесс с одного ядра шлет 100 тысяч сообщений в секунду. 

Наверное, около 50 тысяч сообщений в секунду приближаются к пределу того, что на среднем ядре реально может выдать виртуальная машина Erlang. В этот предел мы уперлись на 800 клиентах. Выяснилось, что процесс, который является потоком, занимается только тем, что рассылает сообщения. Больше он не делает вообще ничего, не успевает даже подключить новых клиентов.

Так и получилось, что у нас начались "тормоза", "лаги" и "залипания". Клиент не мог даже подключиться к потоку, потому что поток занимался обслуживанием уже имеющихся клиентов. У клиентов начиналась плавная, мягкая деградация всего-всего.

Как мы выявили проблему, как мы нашли узкое место?

 

Мониторинг – это то, что предлагается в Erlang вместо классических систем профилирования. Мониторинг тут спасает как раз из-за других базовых концепций. 

Одна из самых эффективных мер мониторинга – это очереди сообщений. Так как все процессы обмениваются только сообщениями, по факту получается, что вызов метода – это асинхронное событие. Оно не только асинхронное: в отличие от C++, оно где-то записывается. Message box – это своего журнал обращений к объекту. 

Если пришло 10 тысяч процессов, которые от одного процесса что-то попросили, сделали одному вызов, то в очереди этого процесса будет видно 10 тысяч сообщений. Это можно мониторить. 

Очень несложным способом мы строим график. Мы смотрим, какой из процессов сейчас загружен, у какого очередь сообщений самая длинная.

Так же, по процессам, мы можем измерять отдельно загрузку ЦПУ. Фактически это означает, что мы знаем, в каком объекте у нас больше всего тратятся ресурсы процессора. Это очень необычная концепция. Вообще говоря, для C++ слова «объект тратит ресурсы ЦПУ» – это нонсенс. В Java или C++ только поток может тратить ресурсы ЦПУ. Но мы не знаем, в каком объекте он сейчас находится, что он сейчас обрабатывает, какую функцию.

Здесь по-другому. Здесь объект и поток – это одно и то же. Мы можем понимать, какой код чем занимается в данный момент. 

Что получается, когда возникают узкие места?

Начинается рост очереди сообщений. Если один процесс медленно работает, то у него растет очередь сообщений. Она может расти неограниченно. 200 тысяч сообщений, миллион сообщений бывает. Нормально, в этом нет ничего страшного, это можно разгрести. 

Следовательно, растет и потребление ресурсов ЦПУ. Отсюда вывод: точно такими же методами мы можем определять, где у нас накапливается память, потому что все изолировано.

Erlang прекрасно "раскидывает" свои процессы по ядрам. 16 ядер совершенно нормально масштабируется. Но один процесс может существовать только на одном ядре. Если ему не хватает ресурсов, у него растет очередь сообщений. Клиентские процессы, которые от него что-то хотели, встают в очередь. Они не обслуживаются. Они тоже начинают вылетать из-за истечения времени ожидания, потому что в Erlang вызов метода может вылететь и по этой причине. Так мы можем находить узкие места.

Что мы сделали в нашем конкретном случае? Мы выкинули рассылку в сотню тысяч сообщений. Передали сокеты внутрь процесса-потока, который начинает обрабатывать. Он пишет с сокета напрямую в RTMP-протокол. Этот нехитрый трюк позволил нам обслуживать до двух – двух с половиной тысяч клиентов.

Дальше выяснилось, что и этого не хватает. Мы решили сделать хитрее. Мы решили воспользоваться таким трюком. Процесс записи в сокеты мы опять распределили по ядрам. Получается, что есть процесс и поток – есть около восьми обработчиков по количеству ядер. Они держат свой небольшой subset клиентов. Соответственно, поток "раскидывает" по своим обработчикам, а обработчик уже пишет в сокеты. Такая несложная схема.

Наверное, многие из здесь сидящих спокойно сделали бы все то же самое на C++, на Java. Вопрос только в том, за сколько времени. У нас на все это ушло четыре дня. Причем три дня из них код писал человек, который увидел Erlang позавчера. Я просто объяснил ему, что надо сделать. Он открыл книжку, залез и все сделал, все заработало прекрасно.

В результате таких наших мониторингов, исследований и профилирования мы смогли радикально увеличить количество обслуживаемых клиентов, в принципе, сняв вообще такую головную боль, как ресурсы процессора на рассылку сокетов. Мы опять "уперлись" в канал. Понятно, что канал – это самое дорогое, что есть сегодня в Интернете. Серверы не стоят ничего относительно каналов.

К чему был весь этот доклад? Скажем, вы хотите перестроить свою систему или будете строить новую систему на Erlang, но боитесь того, что у вас могут быть проблемы со скоростью, с задержками, с чем-то еще. Могу сказать: нет, этого бояться не надо. 

Есть некоторые рекомендации, которые мы можем дать. 

Во-первых. Вам надо заранее проектировать, что будет с системой. Прикинули: в потоке 50 кадров, 2 тысячи клиентов, 100 тысяч сообщений. Это очень много.

Во-вторых, конечно, нужно уменьшать работу внутри одного клиента. Например, ситуация с потоком. Клиент может прийти и запросить данные о потоке. Скажем, сколько сейчас клиентов подключено к этому потоку. Могут понадобится какие-то еще данные, статистика. Если все эти данные "пропихивать" через штатный механизм с помощью сообщений, будет проблемно. Это не будет работать, система будет "подвисать".

Гораздо эффективнее, чтобы поток сам писал данные про себя куда-то наружу, откуда вы можете читать. Но это совершенно обычные вещи. Если у вас есть какая-то "живая" система, постарайтесь отказаться от исследования ее в режиме реального времени, от сбора статистики.

В Erlang "расползание" по ядрам дается абсолютно даром, без каких-либо проблем. Чем больше процессов вы создадите, чем более гранулярно ваш код разбит по процессам, тем больше шансов, что у вас все будет "расползаться" по ядрам самостоятельно, соответственно, с увеличением суммарной производительности.

В реальности на Эрливидео виртуальная машина Erlang показывает абсолютно линейный рост количества обслуживаемых клиентов относительно ядер. Очень ровный рост, это прямая. У нас нет никаких искажений, нет никаких проблем из-за того, что машина использует 3-4 потока между четырьмя ядрами.

Что самое главное мы получили от Erlang?

Когда я делал подобную задачу на Objective-C, это был просто кошмар. Отладить подобной сложности сервер с обильной коммуникацией между подключенными клиентами, с тайм-аутами, с утечками памяти, без деградации качества, без деградации скорости, без деградации качества обслуживания, без отключения клиентов безумно сложно.

Erlang предлагает нам совершенно другую вещь. Мы можем обновлять код "на ходу", на "живом" сервере, прямо под подключенными клиентами. Если у вас есть какой-то код, который обслуживает клиентов, вы выкатываете новые исходники, они "подцепляются", и все работает.

Нам пришлось немного поменять свой привычный набор инструментов, которым мы пользуемся для профилирования, отладки и прочего. Старые инструменты оказались просто нерабочими. Их просто не существует для Erlang. Есть другие инструменты, которые при должном использовании оказались гораздо проще и эффективнее, чем те, которыми я пользовался раньше.

Вот, собственно, и все.

Вопросы? 

Вопросы и ответы

Вопрос из зала: Вопрос первый. Я так понимаю, пришлось в некотором смысле пожертвовать модульностью и изоляцией соединений между клиентами. Если раньше RTMP-процесс давал "сырые" данные всем процессам клиентов, и они занимались упаковкой и "подсовыванием" нужных конкретному клиенту заголовков, то теперь всем этим сразу занимается один процесс. Правильно?

Макс Лапшин: Совершенно верно.

Вопрос из зала: Не было способа обойтись без этого?

Макс Лапшин: Erlang позволяет "воткнуть" собственный код обработки "сырых" сокетов. Можно добраться непосредственно до сокетов в обход той инфраструктуры, которую предлагает Erlang. Можно было бы сделать так. Но, я говорю, мы потратили неделю, оно у нас заработало и перестало "болеть и чесаться". Все стало хорошо. Наверное, можно было бы и так сделать. Если у нас будет проблема с 10-ю или с 20-ю гигабитами, если такое случится, значит, будем решать эти проблемы. Пока у нас их нет.

Вопрос из зала: Понятно. Второй вопрос. Казалось бы, еще один общеизвестный способ поиска проблемы с производительностью: если не получается воткнуть профайлер "наживую", надо, например, что-то логировать. Логирование тоже тормозит?

Макс Лапшин: Конечно.

Вопрос из зала: Настолько сильно?

Макс Лапшин: Что будем логировать? Если будем логировать фреймы, то 100 тысяч записей в секунду не могут не нанести никакого искажения. Если мы будем логировать подключения, это мало что даст. Важнее всего мониторить длинные очереди сообщений в процессах, чтобы понимать, кто что сейчас "выгребает". Второе – это статус записи в TCP-буфер ядра. Если он перестал записываться, то случилась беда. На практике это означает, что клиента надо отключить и больше не общаться с ним. Значит, скорее всего, у него модем или другой медленный канал.

Вопрос из зала: Можно было бы включить логирование для какого-то процента одновременных клиентов, не для всех.

Макс Лапшин: Что логировать-то?

Вопрос из зала: Я не знаю. Тебе видней.

Макс Лапшин: Собственно говоря, нам хватило банальной интроспекции. Я, может быть, не очень внятно это объяснил. Виртуальная машина Erlang позволяет вам зайти в консоль запущенного сервера. Вы можете со своей машины попасть внутрь работающего процесса и исследовать все те данные, которые там есть. При этом наличие имеющихся механизмов позволяет вам залезать даже внутрь рабочих процессов и исследовать их состояние. 

Конечно, гораздо интереснее и эффективнее оказалось не добавлять логирование. Оно, конечно, полезно, когда ты знаешь, что ищешь. Допустим, ты не знаешь, что ищешь, просто тупо все "тормозит", происходят какие-то непонятные "отваливания". Клиенты жалуются: «Ничего не работает». Все пропало. Соответственно, заходим и начинаем смотреть. Если бы нам не хватило недели, мы бы, наверное, уперлись в какое-нибудь логирование, журналирование, переписывание каких-то еще вещей. Самое главное – мы смогли обойтись без профилировщика и без попыток понять, что же он нам говорит такое странное. 

Вопрос из зала: Логировать ошибки не пробовал?

Макс Лапшин: Нет, ошибки, конечно, логируются. Но что именно в них?

Вопрос из зала: По ним и определяешь. 

Макс Лапшин: Какие ошибки?

Вопрос из зала: Истекшее время ожидания, таймаут.

Макс Лапшин: Из-за чего он происходит? У тебя же не будет написано, что истечение времени ожидания произошло из-за того, что ты неправильно написал такой-то код. Конечно, таймауты отслеживаются. Тем более, в Erlang есть такая концепция: когда один объект вызывает метод на другом, этот вызов может "обвалиться" по таймауту. Если второй очень долго отвечает, первый отпускает. Ему говорят: «Твой вызывающий процесс не отвечает». Конечно, этими таймаутами лог забит по полной. 

Такое логирование не дает тебе ответа, куда смотреть, что тормозит. Такая интроспекция, к которой мы прибегли, позволила очень эффективно найти причину. Узкое место выходит сразу. У кого больше всех истрачено памяти, тот и плохой. После чего мы смотрим, в какой функции сейчас находится процесс, чем именно он сейчас занимается. Такой поиск может занимать день. 

Вопрос из зала: Какое примерно количество нод используется?

Макс Лапшин: Одна. Что касается кластеризации Erlang... Я этим никогда не пользовался, не пользуюсь. Мне это не нужно. В Erlang есть такая вещь, как кластеризация. Можете поставить рядом два компьютера, запустить на них две виртуальных машины, объединить их вместе. Между ними будет прозрачное сетевое взаимодействие. Это очень похоже на CORBA, только это работает.

Вопрос из зала: На самом деле, я думал задать вопрос на тему сохранения соединений при использовании философии "let it crash"...

Макс Лапшин: В реальности этого не нужно делать. Если вы программируете, например, видеостриминговый сервер и делаете к нему клиент на Flash, вы должны очень аккуратно и обстоятельно обрабатывать ситуацию разорванного соединения. Соединение обрывается часто. 

Вы сидите и смотрите видео. Рядом его начал смотреть сосед – все, у вас обоих оборвалось соединение. Сосед закрыл, вы смотрите дальше. В реальности нет смысла так переживать за одно соединение, как это нужно, скажем, при обслуживании телефонного звонка. Тут – оборвалось, и ладно. Подключимся повторно, и все. Тем более сейчас и Flash Player, и iPhone умеют обрабатывать разрыв и не обрывать визуально просмотр.

Реплика из зала: Спасибо.

Макс Лапшин: Оборвалось – и ладно.

Вопрос из зала: Был слайд про ошибки в плеере, в Adobe. Вы с ними столкнулись, начали решать, в итоге пришли к Erlang. Не пытались сообщать об ошибках Adobe? Может, это все проще можно было решить?

Макс Лапшин: Конечно, можно. Но в среднем ошибку в Adobe устраняют 2-3 года.

Вопрос из зала: Вы сообщили или нет?

Макс Лапшин: Я не успею. Так я только к старости денег заработаю. Суть в том, что Adobe очень плохо исправляет ошибки. Я сам сообщал о неполадках году так в 2007-2008. Сейчас на них начали обращать внимание. Нереально. Просто нет смысла. Либо ты работаешь с Flash Player, либо не работаешь с ним вообще. Если работаешь, то помнишь, какие нюансы есть у каждой версии Flash Player. 

Вопрос из зала: Мне любопытно, как вы пришли к Erlang? Все-таки экзотика. Был Objective-C. Однажды пришли и сказали: «А давайте перейдем на Erlang!» 

Макс Лапшин: Объясню. Я человек ленивый, невнимательный, пишу плохо. Мне хотелось, чтобы как-то сами собой решались все инфраструктурные проблемы, связанные с таймаутами, утечками памяти, сборкой мусора и прочим. Java с этим не справлялась. Я видел, как это работает. У нас есть конкуренты, которые написаны на Java. У них классическая проблема – это утечка ресурсов вообще как явление. В Erlang реализован подход, который очень похож на сам Unix. Он практически ставит крест на всем классе проблем утекания ресурсов. Эрливидео умеет стоять месяцами без утечек памяти. Не то что людей нет. Люди ходят, смотрят, работают. Память как влитая. 

Я посмотрел. Сперва подумал, что это какая-то экзотика типа Huskey, на который у меня ума не хватает. Оказалось, это очень простой язык. Платформа, которая сделана на нем, чуть-чуть посложнее. Если я беру человека в команду, у меня уходит неделя, чтобы его полностью вовлечь в работу. Как сам изучал: утром взял книжку и уже к обеду написал рабочий код. Я понял, что это прекрасная вещь. Вся фишка в том, что его делали не академики. Его делали инженеры, которым просто хотелось спать по ночам, а не подниматься и что-то чинить.

Вопрос из зала: Еще один вопрос. Вы пишете, что была система, неизвестно где была проблема, вы переписали ее на Erlang, и замечательные средства профайлинга Erlang показали, что узкое место – это архитектурная особенность Erlang. У вас большая очередь сообщений. Вы убрали главную архитектурную особенность Erlang, и все пошло хорошо.

Макс Лапшин: Это не совсем верно. Есть инструмент. Здесь находится Роберт, который делал дизайн Erlang. Когда мы ему рассказали про то, как применяем Erlang, он был слегка удивлен. Они не думали, что он будет так работать, какие-то гигабиты держать. Такое вообще не планировалось. Это не то что бы главная архитектурная особенность.

Главная архитектурная особенность Erlang в том, что данные друг от друга изолированы очень жестко. Между данными стоит огромный барьер. Данные слиты воедино с потоком выполнения. В Java объект где-то вызывает какой-то метод, у вас нет никакой отправки сообщений, никто ничего не делает. На самом деле, у вас есть безмолвные объекты, которые "размазаны" по памяти, и есть потоки, которые с ними работают.

В Erlang все гораздо проще и понятнее. В Erlang, когда мы говорим: «Один объект посылает другому сообщение», один объект реально посылает другому сообщение или вызывает где-то метод. В этом и заключается вся архитектурная особенность. Да, мы сделали abuse виртуальной машины в ситуации с сообщениями. Выяснилось, что она с этим не работает. Когда вы сталкиваетесь с предельными нагрузками (критичными или запредельными), у вас часто возникают определенные нюансы, с которыми приходится иметь дело. Ничего страшного.

Вопрос из зала: Вы сказали, что поток занимался только тем, что "разгребал" сообщения...

Макс Лапшин: "Раздавал", рассылал. 100 тысяч в секунду – это действительно немало для одного пользователя. 

Вопрос из зала: Да. На Java 100 тысяч вызовов функции сами по себе не представляют никакой проблемы.

Макс Лапшин: Теперь представьте себе 100 тысяч вызовов через мьютекс, но в другой поток, которые "разгребаются" с копированием. При этом без утекания ссылок. С копированием в другую кучу.

Вопрос из зала: Если у меня 100 тысяч ядер…

Макс Лапшин: Нет, какие 100 тысяч ядер. Давайте говорить реально. Я на Марсе ничего не "выкатываю". У меня нет там дата-центров. Если у вас есть – хорошо. Я пока компьютеров со 100 тысячами ядер не видел. Обычно 2, 4, 8, если говорить про реальную жизнь. 

Вопрос из зала: Это значит, что если 100 тысяч вызовов с мьютексом занести, я что-то совсем не то сделал в архитектуре?

Макс Лапшин: О чем и речь. Я про это рассказываю. Мы ошиблись в архитектуре. Когда мы пошли искать ошибку в архитектуре (это вообще сложная задача), мы нашли ее моментально. Она была исправлена силами неквалифицированного специалиста.

Речь идет о том, искать такие ошибки в Erlang легко. А искать в Java ошибку из-за того, что код где-то реально "упирается" в количество мьютексов, я думаю, несладко. Это явно будет делаться не силами человека, который стоит вам 20 тысяч рублей в месяц.

Вопрос из зала: Каково количество служебной информации (англ. overhead) на посылку сообщений?

Макс Лапшин: Оно сначала может показаться большим, потому что "кучи" в Erlang разделены. У каждого процесса своя собственная "куча". Это ровная область памяти, непрерывная. Она есть у каждого процесса. Соответственно, в ней идет вся локация. Когда один процесс посылает другому данные, он сначала накладывает мьютекс на конец "кучи" того процесса. При этом он записывает туда данные, потом отпускает и уже под другим мьютексом его информирует, что у тебя новое сообщение. На практике это не так страшно. Это работает нормально. И это можно простить за то, что ровно загружены ядра. Это компенсируется идеальным масштабированием по ядрам.

Реплика из зала: Спасибо.

Комментарии

Нет ни одного комментария

Только пользователи могут оставлять комментарии

Возможно, вам будет интересно:

Евгения Фирсова

Евгения Фирсова

Руководитель отдела веб-интерфейсов, Яндекс.Деньги.

Я хочу рассказать или, если угодно, определиться и пожаловаться вслух (мне приятно жаловаться вслух) о том, как работать, когда работать некому.

Адам Кнапп (Adam Knapp)

Адам Кнапп (Adam Knapp)

Директор по развитию технологий облачного хранения в GoDaddy.com.

Рассказ о технологиях облачного хранения в GoDaddy.com, о проблемах, их решениях, также немного о процессах и управлении проектом.

Александр Сербул

Александр Сербул

C 2011 года курирует направление контроля качества интеграции и внедрений ООО «1С-Битрикс», активно участвует как архитектор и разработчик в проектах компании, связанных с высокой нагрузкой и отказоустойчивостью («Битрикс24»), консультирует партнеров и клиентов по вопросам архитектуры высоконагруженных...

Александр Демидов (1С-Битрикс) делится опытом использования "облачного" хранилища и рассматривает хранилище как элемент масштабируемой отказоустойчивой архитектуры.