English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

гость
1 / ?
назад к урокам

Два способа нести больше нагрузки

Добро пожаловать

Когда сервис начинает сжиматься под нагрузкой, оператор сталкивается с выбором. Увеличить существующий компьютер (больше ЦП, больше ОЗУ, быстрее диски). Или добавить больше компьютеров, которые каждый делают ту же работу.

Первый путь проходит через вертикальное масштабирование (увеличить). Второй проходит через горизонтальное масштабирование (увеличить количество).

Этот урок учит, почему почти вся современная веб-архитектура выбирает горизонтальное и что свойство нагрузки делает этот выбор возможным. Ответ скрывается в одной слове: состояние.

К концу вы поймете:

- Кривые стоимости вертикального и горизонтального масштабирования и где каждое имеет смысл

- Что означают 'состоявший' и 'без состояния' на практике и почему один из них удваивается дешево

- Математика, которая размерует флот реплик под ожидаемую и пиковую нагрузку

- Правило головного пространства, которое предотвращает слой от сжатия за пределы коленя очереди

- Где состояние должно находиться (оно никогда не исчезает) и как вынести его из слоев, которые нужно масштабировать

Почему горизонтальное выигрывает за порогом

Вертикальное масштабирование: один большой ящик

За: простое. Никаких изменений кода. Никакой координации. То же процесс теперь имеет больше ЦП

Против: потолок. Самая большая коммерчески доступная ВМ имеет конечное ОЗУ и ядра. Выше этого, ни один доллар не покупает больше места для головы. Расходы идут сверхлинейно за порогом лучшего предложения поставщика. Сбои в одной машине уничтожают весь сервис

Горизонтальное масштабирование: много маленьких ящиков

За: нет потолка (до вашей готовности платить за & координировать машины). Мощность добавляется линейно с репликами, предсказуемо. Один сбои в реплике убирает 1/N мощности, а не 100%

Против: требует, чтобы нагрузка поддерживала это. Некоторые работы (одна большая база данных, состояние игрового сервера, держащего живые сессии) сопротивляются горизонтальному масштабированию. Координация & распределение нагрузки становятся операционными заботами.

Кроссовер: любое производительное служебное дело, которое должно выжить при потере работы какой-либо единицы, должно работать на два устройства. Когда вы принимаете два, вы уже выбрали горизонтальное масштабирование. Оттуда вопрос не в 'должны ли мы?' а в 'сколько дешево мы можем добавить следующую копию?'

Ключевой фактор: нагрузка, которая не хранит состояния на машине. Тогда любая копия может ответить на любое запрос, & добавление копии добавляет емкость без координации.

Вертикальное и горизонтальное масштабирование: кривая затрат и потолок

Команда выполняет сервис на одном ВМ с 8 ЦП, обрабатывающем 800 запросов в секунду на 60% ЦП. Они ожидают рост трафика в 4 раза за следующий год. Они спорят: арендовать 32-ЦП ВМ (вертикально), или запустить четыре идентичных 8-ЦП ВМ позади балансировщика нагрузки (горизонтально). Какой вариант вы рекомендуете, и назовите два причины, идущие за пределами чистой мощности

Состояние против состояний в практике

Состояние никогда не исчезает, оно просто перемещается

Состоятельный компонент: хранит информацию, потеря которой изменит поведение. База данных, хранящая учетные данные пользователей. Кэш, хранящий токены сессии. Рабочий, фиксирующий долгосрочное потоковое подключение пользователя.

Бесполостный компонент: не хранит информации, потеря которой не будет иметь значения. Веб-уровень, который читает запрос, запрашивает базу данных, и пишет ответ. Каждый запрос живет сам; уровень не помнит ничего между запросами.

Ключевой разум: состояние никогда не исчезает из системы. Оно перемещается в слой, предназначенный для его хранения (база данных, кластер Redis, объектное хранилище). Уровни, которые сталкиваются с трафиком, могут стать бесполостными, и бесполостные уровни масштабируются горизонтально, потому что любая копия может ответить на любой запрос.

Практический тест: если вы случайно убили один процесс в этом уровне и снова запустили его, пользователь столкнулся бы с неправильным ответом или потерей сессии? Если да, он хранит состояние. Если нет, он не хранит.

Примеры

- Python веб-процесс, который читает запросы, запрашивает Postgres, возвращает JSON: бесполостный. Состояние живет в Postgres.

- Python веб-процесс, который хранит корзины покупок пользователей в локальной памяти: состоятельный. Потеря процесса приводит к потере корзин. Часто эти могут масштабироваться горизонтально с осторожностью (смазанные сессии, постоянный хэш)

- Сервер WebSocket, который поддерживает открытые подключения для чата: состоятельный по смыслу подключения. Потеря процесса приводит к потере подключений; клиентам нужно перезапросить. Часто эти могут масштабироваться горизонтально с осторожностью (смазанные сессии, постоянный хэш)

- Кэш Redis перед рекомендательным Postgres: состоящий в состоянии кэша, но приемлемый, если недоступность кэша допустима. Падение реплики означает недоступность кэша, а не потери данных.

Проектирование для горизонтального масштабирования = перенос состояния из слоя, который нуждается в масштабировании.

Аудит подозрительного уровня

Команда работает с API рекомендаций на 6 задних VM за помощью обратного прокси. Приложение: читает идентификатор пользователя из запроса, извлекает последние действия пользователя из Postgres, выполняет алгоритм оценки, возвращает список рекомендуемых товаров. Два нестандартных поведения:

- Приложение хранит 'последние действия пользователя' в кэше процессорной памяти, заполняется на первом запросе для пользователя, используется при последующих запросах.

- Приложение использует 'связанные сессии': если пользователь случайно попадет на VM #3, все последующие запросы будут направлены на VM #3 (прокси настроен для маршрутизации с 'связанными сессиями' на основе cookie).

Определите, какой из этих двух поведений делает уровень состоятельным и объясните, что бы сломалось, если команда попытается масштабировать с 6 виртуальных машин (VM) до 12. Затем предложите перерисовку, которая позволяет уровню масштабироваться горизонтально без потери пользовательского кэша.

Формула реплики

Самая простая формула мощности

Когда уровень становится без состояния, его размер становится арифметикой. Вам нужно достаточно реплик, чтобы постоянная нагрузка приходила и убыла с той же скоростью, с запасом для пиков.

Формула:

реплики = ⌈ (peak_load × surge_factor) / per_replica_capacity ⌉ + headroom

Где:

- peak_load: максимальное устойчивое запросов/секунду, которые вы ожидаете в обычной работе

- surge_factor: множитель, покрывающий кратковременные всплески выше peak (обычно от 1,5x до 2x для предсказуемого трафика, от 3x и более для вирусного / непредсказуемого)

- per_replica_capacity: запросы/секунду, которые одна реплика обрабатывает с признательной задержкой и использованием (обычно измеряется при 70% CPU, а не при насыщении)

- headroom: дополнительные реплики, чтобы несколько реплик не разрушили уровень (обычно 1-2 реплики для небольших флотов, 10-20% для более крупных)

Рабочий пример: backend обрабатывает 100 req/s с 70% CPU на реплику. Пиковая загрузка составляет 600 req/s. Вы ожидаете случайные всплески до 2x. Вы хотите выжить при 2 параллельных отказах реплик.

реплики = ⌈ (600 × 2) / 100 ⌉ + 2 = 12 + 2 = 14 реплик

Правило 80%

Вместимость реплики не является точкой насыщения. Измеряйте вместимость на 70-80% CPU, а не на 100%.

После 80% использования очереди, кривые поднимутся резко: очередь, которая выполнялась за 10 мс при 60% использования, выполняется за 80 мс при 90% использования. Пропускная способность не выдерживает первая. (Помощный урок geometry_of_stateless_horizontal_scaling математически определяет эту кривую.)

Автоматическое масштабирование против статического выделения ресурсов

Статическое: выделите для пика × резерв места для всплеска и принимайте высокую стоимость работы при низкой загрузке вне пиковых часов.

Автоматическое масштабирование: контроллер добавляет и удаляет реплики на основе наблюдаемого использования, целевой задержки или глубины очереди.

Примечание к автоматическому масштабированию: время запуска холодное имеет значение. Если новая реплика требуется 2 минуты для запуска, автоматическое масштабирование не может быстро реагировать на всплеск длительностью 30 секунд. Зрелое автоматическое масштабирование поддерживает теплую пул предвзятых реплик ниже порога увеличения.

Формула размера реплики с примером

Определите размер флота для нового сервиса

Your team plans to launch a video metadata API. Benchmarks show a single replica handles 250 req/s at 70% CPU & 50 ms p99 latency. Marketing forecasts peak load at 4,000 req/s during prime-time hours. A planned promotional event could surge to 3x peak briefly. You want the service to survive 3 simultaneous replica failures without exceeding 80% utilization on the survivors.

Примените формулу реплики для определения размера запускаемого флота. Показывайте все шаги работы и затем объясните одну из причин, по которой ваше число может быть неправильным (холодное запускание, прогрев кэша, задержка зависимостей или любая другая причина, которую вы можете защитить).

Холодное запускание, медленное истечение и другие реальные грани

Реальные флоты имеют реальные грани

Формула предполагает, что реплики появляются мгновенно, принимают трафик мгновенно и отбрасывают трафик мгновенно. Никто из них не соблюдается в производстве.

Cold start: новая реплика должна запустить ОС, запустить процесс, загрузить конфигурацию, прогреть кэш и пройти проверку работоспособности. Время от 5 секунд (перезапуск контейнера) до 5 минут (полное запуск ВМ + загрузка образа). Автомасштабирование не может ответить на всплески, короче этого интервала.

Slow drain: реплика, которая удаляется из пула, нуждается в времени для завершения в-flight запросов перед тем, как завершить работу. В противном случае пользователи видят обрезанные ответы. Реквизиты обратного прокси поддерживают режим тормозки (остановка принятия новых запросов, завершение активных) но это занимает секунды до минут.

Warm pool: производственные флиты поддерживают пуол предварительно зарезервированных, но бездействующих реплик, готовых принять нагрузку по сигналу. Торгуют малым постоянным затратом за быстрый ответ на всплески нагрузки.

Connection draining vs immediate kill: плавный выход важен. SIGTERM, который инициирует тормоз, занимает больше времени, чем SIGKILL, но не нарушает запросы пользователей.

Health check window: реплика, только что запущенная, может пройти первую проверку работоспособности перед тем, как ее базовый соединение будет прогрет; прокси затем отправляет реальный трафик и первые двенадцать запросов будут медленными. Тюнинг проверок работоспособности должен проверять реальный путь, а не только живость процесса.

Stickiness creep: даже номинально без состояния слои приобретают признаки stickiness (CDN кэш, кэш разрешителей DNS). Будьте насторожены относительно 'идентичных реплик', которые тем не менее ведут себя по-разному.

Warm Pool or Reactive Autoscaling?

API вашего метаданных видео (тот же, что и в предыдущем вопросе, размером в 51 реплику для постоянного пика + всплеска) испытывает 30-секундный всплеск в 5 раз выше нормы при загрузке каждого нового вирусного видео. Нынешнее масштабирование занимает 90 секунд для добавления новой реплики из холодного состояния (загрузка образа + прогрев). В течение 90-секундного интервала задерживается обработка запросов и некоторые запросы терпят неудачу.

Предложите решение. Выберите: (а) оставить реактивное масштабирование, но настроить его по-другому, (b) зарезервировать теплый пуол бездействующих реплик, или (c) статически зарезервировать для постоянного 5x пика. Обосновайте свой выбор и назовите одну из двух других опций, которую ваш выбор накладывает.

Проектирование без состояния слоя с ограничениями

Синтез

Вы узнали, почему горизонтальное масштабирование выигрывает после небольшого порога, что состояние означает на практике, как размеровать флот под ожидаемые & пиковые нагрузки, & где горизонтальное масштабирование ломается на границах.

Примените все четыре.

Создайте задний план (feed.example.com), API социальной ленты. Ограничения: емкость каждой реплики 200 req/s при 70% CPU; ожидаемая пиковая нагрузка 1500 req/s; коэффициент пиковой нагрузки 2,5x (редкие трендовые истории); выдерживать 2 одновременные сбои реплик; время холодного старта 60 секунд; всплески могут длиться 45 секунд; бюджет позволяет некоторой свободной емкости, но не 2,5x постоянному предпринимательству.

Размерите флот (показать математические вычисления), выберите стратегию обработки пиковых нагрузок (теплое池 / реагирующий автомасштабирование / оба варианта) & определите одну часть пользовательского состояния, которую вероятно хранит приложение, и где оно должно переместиться, чтобы сохранить состояние без тирования.

Где Этот Курс Продолжится

Где Этот Курс Продолжится

Теперь у вас есть работающий образец заднего плана без состояния: почему он масштабируется, как его размерить, что ломается на его границах & где состояние должно переместиться, когда вы выталкиваете его из слоя, который нужно расширить.

В следующем уроке этого курса (cs_distsys_ingress_egress_separation) рассматривается более тонкая проблема: даже идеально размеренный задний план без состояния может неожиданно провалить, когда входящий & исходящий трафик используют ту же сеть.

Сопутствующий урок: geometry_of_stateless_horizontal_scaling выводит кривую очереди, закон Литтла, примененный к флоту реплик & геометрическое значение колонки 80% использования колбы.

Хорошая работа. Дальше.