Сокеты балансировки нагрузки на горизонтально масштабируемом сервере WebSocket?
каждые несколько месяцев, когда я думаю о личном проекте, который включает сокеты, у меня возникает вопрос " Как бы вы правильно загрузили сокеты баланса на динамическом горизонтально масштабируемом сервере WebSocket?"
Я понимаю теорию горизонтального масштабирования WebSockets и использования моделей pub/sub для получения данных на правильный сервер, который содержит соединение сокета для конкретного пользователя. Я думаю, что понимаю способы эффективной идентификации сервера с наименьшим количеством текущих соединений сокета, которые я хотел бы направить новое соединение сокета тоже. чего я не понимаю, так это как эффективно маршрутизировать новые соединения сокетов на сервер, который вы выбрали с низким количеством сокетов.
Я не думаю, что этот ответ будет привязан к конкретной реализации сервера, а может быть применено к большинству серверов. Я мог легко представить себе, как реализую это с vert.х, узел.js, или даже идеально.
2 ответов
во-первых, вам нужно определить границы проблемы, о которой вы спрашиваете. Если вы действительно говорите о динамическом горизонтальном масштабировании, где вы вращаете вверх и вниз серверы на основе общей нагрузки, то это еще более сложная проблема, чем просто выяснить, куда направить последнее входящее новое соединение сокета.
чтобы решить эту проблему, вы должны иметь способ "перемещения" сокета с одного хоста на другой, чтобы вы могли очистить соединения от хоста, который вы хотите вращать (я предполагаю, что истинное динамическое масштабирование идет как вверх, так и вниз). Обычно я видел, как это делается, привлекая сотрудничающего клиента, где вы говорите клиенту повторно подключиться, и когда он снова подключается, он балансирует нагрузку на другой сервер, чтобы вы могли очистить тот, который вы хотели развернуть. Если у вашего клиента уже есть логика автоматического повторного подключения (например, сокет.io делает), вы можете просто закрыть соединение на сервере, и клиент автоматически повторно подключится.
как для балансировка нагрузки входящие клиентские подключения, вы должны решить, какую метрику нагрузки вы хотите использовать. В конечном счете, вам нужен балл для каждого серверного процесса, который говорит вам, насколько "занят" вы думаете, что это, чтобы вы могли установить новые соединения на наименее занятом сервере. Рудиментарная оценка будет просто количеством текущих соединений. Если у вас есть большое количество подключений на серверный процесс (десятки тысяч), и в вашем приложении нет особой причины, по которой некоторые из них могут быть намного более заняты, чем другие, то закон больших чисел, вероятно, усредняет нагрузку, поэтому вы можете уйти от того, сколько соединений имеет каждый сервер. Если использование соединений не так справедливо или даже, то вам, возможно, придется также учитывать какое-то скользящее среднее времени загрузки процессора вместе с общим количеством соединений.
Если вы собираетесь балансировать нагрузку на нескольких физических серверах, Вам понадобится балансировщик нагрузки или прокси-служба, к которой все подключаются изначально, и этот прокси-сервер может посмотрите на показатели для всех запущенных серверов в пуле и назначьте соединение тому, у которого самый низкий текущий балл. Это можно сделать либо с помощью прокси-схемы, либо (более масштабируемой) через перенаправление, чтобы прокси-сервер не мешал после первоначального назначения.
у вас также может быть процесс, который регулярно проверяет ваш счет загрузки (однако вы решили его рассчитать) на всех серверах в кластере и решает, когда вращать новый сервер или когда спин один вниз или когда вещи слишком далеки от баланса на данном сервере, и этот сервер должен быть сказано, чтобы запустить несколько соединений, заставляя их перебалансировать.
чего я не понимаю, так это как эффективно маршрутизировать новые соединения сокетов на сервер, который вы выбрали с низким количеством сокетов.
как описано выше, вы либо используете прокси-схему, либо схему перенаправления. При немного более высокой стоимости во время подключения я предпочитаю схему перенаправления потому что он более масштабируемый при запуске и создает меньше точек сбоя для существующего соединения. Все клиенты подключаются к серверу шлюза входящего соединения, который отвечает за знание текущего балла загрузки для каждого из серверов в ферме, и на основе этого он назначает входящее соединение хосту с самым низким баллом, и это новое соединение затем перенаправляется для повторного подключения к одному из конкретных серверов в ферме.
Я также видел нагрузки балансировка выполняется исключительно пользовательской реализацией DNS. Клиент запрашивает IP-адрес farm.somedomain.com
и этот пользовательский DNS-сервер дает им IP-адрес хоста, которому он хочет их назначить. Каждый клиент, который ищет IP-адрес farm.somedomain.com
может получить другой IP-адрес. Вы вращаете хосты вверх или вниз, добавляя или удаляя их с пользовательского DNS-сервера, и именно этот пользовательский DNS-сервер должен содержать логику для знания логики балансировки нагрузки и текущих оценок нагрузки всех запуск хостов.
Маршрутизируйте запросы websocket к балансировщику нагрузки, который принимает решение о том, куда отправлять соединения.
например, HAProxy есть leastconn
метод для длинных соединений, который выбирает наименее недавно используемый сервер с наименьшим количеством соединений.
бэкэнд HAProxy серверные веса также могут быть изменены внешними входами, @jfriend00 подробно технические детали взвешивание в ответ.