Эластичность и управляемые сервисы

Что это такое

Эластичность — способность платформы добавлять и убирать экземпляры по мере изменения нагрузки; управляемые сервисы — это базы данных, очереди, кэши и хранилища, которые держат то, что экземпляры держать не должны. Одно идёт вместе с другим, потому что приложение без состояния можно свободно масштабировать, только если его состояние живёт там, где для него спроектировано место. Облачно-нативный дизайн во многом и есть дисциплина решать для каждой части состояния, какой управляемый сервис ею владеет.

Почему это важно

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

Ключевые идеи

Отсутствие состояния — свойство развёртывания, а не кода

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

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

Масштабируйте по сигналу, который опережает спрос

Масштабирование по CPU реагирует после того, как работа пришла; масштабирование по глубине очереди, частоте запросов или своей метрике может действовать заранее. Какой бы сигнал ни был выбран, правило роста должно быть охотнее правила сокращения, потому что позднее добавление ёмкости заметно пользователям, а раннее её удаление — нет. Система, которая мигает между размерами, обычно настроена симметрично, а не должна быть такой.

Плавное завершение — часть масштабирования

Когда экземпляры убирают, им дают сигнал и период, чтобы закончить. Процесс, игнорирующий сигнал, теряет запросы в обработке; тот, что перестаёт принимать новую работу, доводит текущую до конца и завершается чисто, не теряет ничего. Плавные развёртывания зависят от того же поведения, поэтому правильная реализация окупается дважды.

Каждый переход к управляемому сервису — домен отказа

Управляемая база данных надёжнее той, что вы запускаете сами, но это всё ещё сетевая зависимость с задержкой, лимитами соединений и собственными сбоями. Пул соединений, тайм-ауты и повторные попытки с задержкой — не необязательные дополнения; без них кратко замедлившаяся база превращается в неограниченную груду ожидающих соединений. Проектирование под частичный отказ — постоянный налог на распределённую систему.

У эластичности есть экономическое измерение

Масштабирование вширь и обратно — то, что заставляет потребление следовать за спросом, а это и есть ценовое преимущество облака. Кластер, постоянно выставленный под годовой пик, его отбрасывает. Здесь работает та же логика, что и при подборе размера, только единица измерения — экземпляры, а не размер экземпляра.

Управляемый не значит оставленный без внимания

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

Практика

Вынесите одну часть состояния из экземпляра

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

Готово, когда: два экземпляра за балансировщиком могут оба отдать скачивание одного и того же файла.

Доводите работу до конца при завершении

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

Готово, когда: нагрузочный тест не сообщает ни об одном неудачном запросе во время плавной замены.

Частые ошибки

  • Держать сессии в памяти экземпляра — пользователя выбрасывает из системы, как только он попадает на другой экземпляр; исправить: перенесите сессии в общее хранилище.
  • Хранить загрузки на локальном диске — файл существует ровно на одном экземпляре; исправить: используйте объектное хранилище, а в базе держите ссылки.
  • Масштабировать только по CPU для системы на очереди — очередь растёт раньше, чем реагирует CPU; исправить: масштабируйте по глубине очереди или по темпу поступления.
  • Игнорировать сигнал завершения — плавные развёртывания теряют запросы в обработке; исправить: доводите работу до конца и завершайтесь осознанно.
  • Вызывать управляемый сервис без тайм-аутов и пула — краткое замедление исчерпывает соединения и распространяет отказ; исправить: ограничьте вызовы и объедините соединения в пул.

Что читать дальше