Масштабирование и балансировка нагрузки
Вертикальное против горизонтального масштабирования, законы масштабируемости Амдала, Густафсона и USL, алгоритмы балансировки нагрузки, привязка сессий и обнаружение сервисов.
8 вопросов
JuniorТеорияОчень частоВ чём разница между вертикальным и горизонтальным масштабированием и к чему обращаться первым?
В чём разница между вертикальным и горизонтальным масштабированием и к чему обращаться первым?
Вертикальное масштабирование — это машина побольше: просто, но с жёстким потолком и единой точкой отказа. Горизонтальное — больше инстансов за балансировщиком: нужны stateless-инстансы и сложнее согласованность. Сначала вертикальное, потом горизонтальное, когда машина не тянет.
Типичные ошибки
- ✗Путать определения — называть «больше машин» вертикальным, а «машину побольше» горизонтальным
- ✗Забывать, что у вертикального есть жёсткий потолок и оно остаётся единой точкой отказа
- ✗Идти в горизонтальное первым, пока инстансы держат локальное состояние, и запросы рушатся при failover
Уточняющие вопросы
- →Что должно быть верно про инстанс, прежде чем его можно масштабировать горизонтально?
- →Почему горизонтальное масштабирование усложняет согласованность сильнее, чем одна машина?
JuniorТеорияЧастоКакие есть распространённые алгоритмы балансировки нагрузки и когда подходит каждый из них?
Какие есть распространённые алгоритмы балансировки нагрузки и когда подходит каждый из них?
Round-robin раскладывает запросы по кругу поровну; weighted round-robin учитывает мощность; least-connections шлёт на реплику с наименьшим числом открытых соединений; response-time-based выбирает реплику с наименьшей латентностью; consistent hashing закрепляет запрос за репликой по ключу. L4 балансирует по транспорту, L7 понимает HTTP.
Типичные ошибки
- ✗Называют round-robin единственным алгоритмом и игнорируют выбор по мощности или латентности — weighted или least-connections.
- ✗Путают уровни — считают L4 понимающим HTTP, хотя L4 балансирует по транспорту, а HTTP читает только L7.
- ✗Думают, что consistent hashing просто равномерно раскидывает нагрузку, упуская, что его смысл — липкая привязка ключа к одной реплике.
Уточняющие вопросы
- →Когда вы выберете алгоритм балансировки consistent hashing вместо least-connections?
- →Зачем response-time-based маршрутизации нужны проверки здоровья и латентности?
JuniorТеорияЧастоПочему при горизонтальном масштабировании сервиса предпочитают stateless-сессии, а не sticky-сессии?
Почему при горизонтальном масштабировании сервиса предпочитают stateless-сессии, а не sticky-сессии?
Stateless-сессии держат состояние в JWT или общем хранилище Redis, поэтому любой инстанс обслуживает любого пользователя и балансировщик ровно раскладывает нагрузку. Sticky-сессии привязывают пользователя к одному инстансу, перекашивая нагрузку и ломаясь при отказе.
Типичные ошибки
- ✗Считают, что sticky-сессии нужны для логина — общее хранилище сессий или
JWTдержит пользователя залогиненным на любом инстансе. - ✗Думают, что привязка по ip балансирует нагрузку; несколько крупных клиентов за одним NAT прибивают почти весь трафик к одному инстансу.
Уточняющие вопросы
- →Как формат токена
JWTпозволяет любому инстансу аутентифицировать запрос без общего хранилища? - →Когда вы всё же примете sticky-сессии, несмотря на перекос нагрузки?
MiddleТеорияЧастоЧто закон Амдала, закон Густафсона и универсальный закон масштабируемости (USL) говорят про добавление узлов?
Что закон Амдала, закон Густафсона и универсальный закон масштабируемости (USL) говорят про добавление узлов?
Закон Амдала ограничивает ускорение последовательной долей, поэтому лишние ядра дают убывающую отдачу. Закон Густафсона: ускорение остаётся почти линейным, если растить задачу вместе с ресурсами. Закон масштабируемости USL добавляет штраф за когерентность — пропускная способность растёт, выходит на плато, затем падает.
Типичные ошибки
- ✗Путать закон Амдала с законом Густафсона — считать последовательную долю фиксированной, когда сама задача растёт
- ✗Считать, что больше узлов всегда повышает пропускную, игнорируя штраф когерентности USL, который ведёт к плато и спаду
- ✗Принимать почти линейное ускорение за обещание бесплатного масштабирования, забывая про стоимость координации узлов
Уточняющие вопросы
- →Когда применим закон Густафсона, но не пессимистичная граница Амдала?
- →Какая координация раздувает штраф когерентности USL в сервисе?
MiddleТеорияЧастоКак обнаружение сервисов направляет трафик на живые инстансы и чем различаются client-side и server-side?
Как обнаружение сервисов направляет трафик на живые инстансы и чем различаются client-side и server-side?
Реестр — Consul, etcd, Kubernetes DNS — сопоставляет имя сервиса здоровым инстансам, а health-aware discovery выкидывает мёртвые, чтобы балансировщик их не выбирал. При client-side вызывающий опрашивает реестр, а server-side прячет его за балансировщиком.
Типичные ошибки
- ✗Считать реестр статическим списком адресов и забывать, что health-проверки убирают падающие инстансы
- ✗Путать направления — называть client-side discovery серверным или класть балансировку не в то место
- ✗Думать, что упавший инстанс продолжает получать трафик, игнорируя, что health-aware discovery убирает его из выдачи
Уточняющие вопросы
- →Как реестр решает, что инстанс достаточно здоров для приёма трафика?
- →Что ломается, если сам реестр становится единой точкой отказа?
MiddleДизайнИногдаНужно выкатить новую версию read-heavy Go API в прод со stateless-сессиями, сначала малой долей трафика, с мониторингом error rate и латентности и быстрым откатом — как сделать релиз?
Нужно выкатить новую версию read-heavy Go API в прод со stateless-сессиями, сначала малой долей трафика, с мониторингом error rate и латентности и быстрым откатом — как сделать релиз?
Сделай canary: направь маленький процент трафика на новую версию через split на feature flag, держи инстансы stateless (JWT или общий Redis), чтобы любая версия обслуживала любого, следи за error rate и латентностью, потом катись вперёд или назад. Sticky sessions запинят пользователей и сломают split.
Типичные ошибки
- ✗Считать sticky sessions совместимыми с canary — affinity пинит пользователей к одной версии и ломает процентный split.
- ✗Катить всё разом big-bang без доли трафика и без быстрого пути отката.
- ✗Забыть следить за error rate и латентностью на canary — и продвинуть плохую версию вслепую.
Уточняющие вопросы
- →Чем паттерн выката blue-green отличается от canary-выкатки?
- →Где живёт переключатель feature flag, чтобы split применялся мгновенно?
SeniorДизайнИногдаОдноузловой read-heavy Go API должен впитать примерно 10x текущего read-трафика. Ограничения: минимальный простой, заменяемые инстансы, справедливая балансировка нагрузки по репликам и постепенный выкат, чтобы плохой релиз отловить рано. Как масштабировать сервис горизонтально, распределить трафик по новым репликам и безопасно вводить добавленную ёмкость?
Одноузловой read-heavy Go API должен впитать примерно 10x текущего read-трафика. Ограничения: минимальный простой, заменяемые инстансы, справедливая балансировка нагрузки по репликам и постепенный выкат, чтобы плохой релиз отловить рано. Как масштабировать сервис горизонтально, распределить трафик по новым репликам и безопасно вводить добавленную ёмкость?
Сделай инстансы stateless и масштабируйся горизонтально за L7-балансировщиком с least-connections или latency-aware маршрутизацией. Регистрируй реплики в service discovery с health-проверками, чтобы мёртвые выпадали, затем вводи ёмкость через canary traffic split до переключения.
Типичные ошибки
- ✗Идти только в вертикальное и упереться в жёсткий потолок, оставив одну машину единой точкой отказа под нагрузкой 10x
- ✗Держать состояние сессии на инстансе, из-за чего навязывается sticky-маршрутизация и реплики нельзя свободно заменять
- ✗Переключить весь трафик на новый флот разом без canary, и плохой релиз кладёт каждый read-запрос
Уточняющие вопросы
- →Какой алгоритм балансировки подходит репликам с неравной латентностью и почему не round-robin?
- →Какие сигналы решают, расширять канареечный выкат или откатить traffic split назад?
SeniorТеорияРедкоПочему добавление инстансов за реестром service discovery может замедлить систему, и как это диагностировать?
Почему добавление инстансов за реестром service discovery может замедлить систему, и как это диагностировать?
Коэффициент когерентности USL: инстансы, которым нужно координироваться (общий кэш, lock, болтовня с registry), платят за crosstalk сверхлинейно, поэтому throughput выходит на плато и падает. Диагностируй графиком throughput от числа узлов — падающая кривая значит, что доминирует координация. Лечи срезанием координации (шардируй состояние), а не добавлением узлов.
Типичные ошибки
- ✗Считать масштабирование вширь бесплатным — полагать, что N узлов дают N× throughput, игнорируя штраф когерентности в кривой USL.
- ✗В ответ на плато добавлять ещё инстансы, что усиливает crosstalk вместо того, чтобы его снять.
- ✗Забывать, что service discovery и health checks сами по себе координационный трафик, растущий с числом узлов.
Уточняющие вопросы
- →Где находится пик кривой когерентности универсального закона масштабируемости (USL) при заданной доле координации?
- →Как шардирование общего состояния отодвигает плато throughput?