Как привязать клиента к серверу при балансировке нагрузки без хранения состояния в базе данных
Что проверяют
Различаете ли вы две разные задачи: привязать клиента к конкретному серверу (session affinity) и сделать так, чтобы привязка стала не нужна. Следом обычно спрашивают, что станет с пользователем, когда его сервер упадёт, и зачем фронтенду вообще липкие сессии.
Как отвечать
Если хранить состояние в базе нельзя, привязку делает сам балансировщик:
- по IP клиента: в nginx директива
ip_hash. Просто, но за NAT, корпоративным прокси или CDN сотни пользователей приходят с одного адреса, а мобильный клиент меняет IP при смене сети; - по cookie балансировщика: при первом ответе балансировщик ставит cookie с идентификатором сервера и дальше маршрутизирует по ней. В HAProxy это
cookie SRV insert indirect nocache, в открытой версии nginx похожего добиваются черезhash $cookie_route consistent; - по ключу из запроса: консистентное хеширование по id пользователя или заголовку. При добавлении сервера перераспределяется только часть ключей, а не все.
Потом покажите вторую сторону: часто правильный ответ в том, чтобы привязка стала лишней. Состояние уезжает к клиенту в подписанную cookie или JWT, и любой сервер обработает любой запрос. Липкость остаётся там, где без неё не обойтись: WebSocket-соединения, Socket.IO с транспортом long polling (его документация прямо требует sticky sessions при нескольких узлах), локальный кеш SSR-сервера, загрузка файла по частям.
Цена привязки: нагрузка распределяется неравномерно, а при падении или выкатке узла его клиенты теряют состояние. Поэтому клиентский код должен уметь переподключиться и восстановиться, а не показывать белый экран.
Где спотыкаются
Отвечают «используем JWT» как способ привязки. JWT решает обратную задачу: убирает серверное состояние, и привязка становится ненужной.
Предлагают ip_hash без оговорок про NAT и прокси. Если перед балансировщиком стоит ещё один прокси, все запросы придут с его адреса и уйдут на один сервер.
Забывают про отказ узла. Липкая сессия без плана на падение сервера означает, что часть пользователей внезапно разлогинит или оборвёт им соединение.