На прошлой неделе упомянула балансировку нагрузки. Давайте посмотрим на пару алгоритмов из этой области.
Что это вообще такое и зачем? У вас уже крупный сервис и целый кластер машин. Приходит очередной клиентский запрос. Какие вопросы возникают:
⬛ На какую из машин его отправить?
⬛ Как распределить обращения так, чтобы одна тачка не простаивала, а другая не перегревалась?
⬛ Если один сервер уходит на обслуживание или мы добавляем новый — что будет с запросами? Не потеряем ли часть запросов и начнёт ли новый сервер вообще что-то получать?
С ответами помогают алгоритмы балансировки нагрузки. Сегодня разберём два достаточно известных. Конечно, их сильно больше.
Самый простой и самый известный — Round Robin.
Все серверы объединяются «в кольцо». Первый запрос уходит на первый сервер, второй — на второй и так далее. Дошли до конца — пошли по кругу заново. Если у вас 10 серверов, то 11-й запрос снова попадёт на первую тачку.
Очень просто.
Где это работает хорошо? Там, где:
⬛все серверы одинаковые
⬛все запросы примерно одинаковые
То есть почти нигде 😂
Есть вариации. Например, взвешенный Round Robin. Если вы знаете, что сервер №2 в два раза мощнее остальных, то он будет получать в два раза больше запросов. Алгоритм тот же, просто с «весами».
Следующий на очереди IP Hash.
У каждого клиента есть стабильный идентификатор (IP-адрес). Пропускаем его через хеш-функцию и получаем сервер:
hash(client_ip) → serverЧто важно:
⬛ идентификатор пользователя должен быть стабильным
⬛ хеш-функция должна быть стабильной (один и тот же вход → один и тот же результат)
⬛ распределение должно быть равномерным (мы же не хотим, чтобы из 100 серверов работали только 2)
Где это полезно?
Когда нужно «приклеить» пользователя к серверу. Например: есть тяжёлое вычисление, результат которого будет релевантным для пользователя какое-то время → можно закешировать локально. Но чтобы кеш работал, пользователь должен стабильно попадать на один и тот же сервер. Тут IP Hash отлично заходит.
Пару слов про «стабильность» хеша. Пусть client_id — просто число. Очень хочется сделать так:
client_id % server_count = serverВроде красиво:
⬛просто
⬛равномерно
⬛детерминированно
Но есть проблема.
Если добавляется или удаляется сервер → меняется server_count → полностью ломается распределение → весь кеш можно выбрасывать. Особенно больно, если у вас сотни машин, которые постоянно приходят и уходят.
В реальности, конечно, так не делают. Нормальные хеш-функции стараются:
⬛стабильно мапить клиента на конкретный сервер
⬛при падении одного сервера перераспределяется только его нагрузка
⬛при добавлении нового — со "старичков" уходит лишь часть трафика.
Какие ещё алгоритмы балансировки нагрузки знаете? Может, хотите разобрать что-то подробнее? Пишите!
P.S. Саша отлично умеет балансировать нагрузку. Поэтому иногда мы прямо в середине недели идём в баню.
#бабанюра_программирует
