Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

От SocialCalc к EtherCalc

Глава 2 из книги "Производительность приложений с открытым исходным кодом".

Оригинал: From SocialCalc to EtherCalc
Автор: Audrey Tang
Перевод: А.Панин

Масштабирование на многоядерных системах

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

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

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

В описанном сценарии эксплуатации платформы на сервере с множеством владельцев учетных записей верхний предел частоты осуществления вызовов API делится между всеми клиентами, осуществляющими вызовы REST API. Это обстоятельство делает действующие в отношении каждого пользователя ограничения гораздо более жесткими - допустимо около 5 запросов в секунду. Как было сказано в предыдущем разделе, это ограничение возникает из-за того, что фреймворк Node.js использует только один центральный процессор для всех вычислений.

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

Существует ли способ задействования всех доступных центральных процессоров на сервере с множеством владельцев учетных записей?

Для других служб на основе Node.js, функционирующих на многопроцессорных узлах, мы использовали сервер для кластера с предварительным разделением процессов (pre-forking cluster server), который создает по процессу для каждого центрального процессора.

Сервер обработки событий для кластера (с использованием многоядерной системы)
Рисунок 2.8 - Сервер обработки событий для кластера (с использованием многоядерной системы)

Однако, хотя EtherCalc и имеет поддержку масштабирования при использовании множества серверов благодаря Redis, объединение кластерной версии компонента Socket.io с хранилищем RedisStore на одном сервере приводило к значительному запутыванию логики и значительному усложнению процесса отладки.

Более того, в том случае, если все процессы кластера ограничены производительностью одного центрального процессора, последующие соединения будут оставаться в заблокированном состоянии.

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

Многопоточный сервер обработки событий (с использованием многоядерной системы)
Рисунок 2.9 - Многопоточный сервер обработки событий (с использованием многоядерной системы)

Стандарт W3C Web Worker API идеально подходит для наших целей. Изначально предназначенный для браузеров, он описывает способ независимого выполнения сценариев в фоновом режиме. Это позволяет выполнять длительную работу в течение продолжительного времени, не блокируя главный поток.

Поэтому мы создали программный компонент webworker-thread, являющийся кроссплптформенной реализацией API Web Worker для Node.js.

При использовании webworker-threads создание нового потока SocialCalc и взаимодействие с ним осуществляются достаточно просто:
{ Worker } = require \webworker-threads
w = new Worker \packed-SocialCalc.js
w.onmessage = (event) -< ...
w.postMessage command

Это решение предоставило в наше распоряжение лучшие возможности двух рассмотренных реализаций: оно позволяет резервировать большее количество центральных процессоров для работы EtherCalc при необходимости и затраты ресурсов на создание фоновых процессов остаются незначительными при работе в однопроцессорных окружениях.


Продолжение статьи: Выученные уроки.