Как обеспечить стабильность веб-сокетов при высокой нагрузке
Что проверяют
Понимаете ли вы, что на стороне браузера стабильность это не «пул соединений», а переподключение, обнаружение мёртвого соединения, догрузка пропущенного и защита интерфейса от потока сообщений. Следом обычно спрашивают, что будет, если сервер перезапустится и все клиенты полезут обратно разом.
Как отвечать
- переподключение: экспоненциальная задержка с потолком и случайным разбросом (jitter). Без разброса после рестарта сервера все клиенты приходят в одну секунду и кладут его снова. Решайте по коду закрытия: после
1006пробуем, после отказа в авторизации сначала обновляем токен; - heartbeat: браузерный
WebSocketне умеет слать протокольный ping, поэтому делают свой ping сообщением и ждут ответа по таймеру. Так ловится полуоткрытое соединение, у которогоreadyStateвсё ещёOPEN. Интервал берут меньше таймаута простоя прокси: у nginxproxy_read_timeoutпо умолчанию 60 секунд; - восстановление: сообщения нумеруются, после переподключения клиент называет последний номер, и сервер досылает пропущенное, либо клиент берёт снимок через REST;
- входящий поток: не вызывайте
setStateна каждое сообщение. Копите обновления в буфере и применяйте раз в кадр черезrequestAnimationFrame, тяжёлый разбор уносите в Web Worker; - исходящие: перед отправкой смотрите на
bufferedAmount, иначе на медленной сети буфер растёт без предела; - число соединений: одно соединение на приложение, а не на компонент. Несколько вкладок сводят к одному через
SharedWorkerили выбор лидера на Web Locks иBroadcastChannel; - жизненный цикл: на
offlineне тратьте попытки, наonlineпереподключайтесь сразу.
Про сервер хватит фразы: pub/sub между узлами и компактный формат вроде MessagePack.
Где спотыкаются
Переподключаются с фиксированным интервалом в секунду. При массовом разрыве это превращается в DDoS собственного бэкенда.
Считают соединение живым, пока не пришло событие close. При обрыве сети его можно ждать минутами, глядя на замершие данные.
Рендерят каждое сообщение отдельно. При сотне сообщений в секунду интерфейс тормозит, хотя сокет работает идеально.