Real-Time Backend

Feature Flags

Новый алгоритм показал -40% трафика в staging. Через 20 минут после production-выкатки - жалобы. Один flip feature flag - проблема исчезла. Без флага: откат деплоя, ещё час downtime-риска.

  • Slack включил новый алгоритм компрессии для 5% пользователей, нашёл latency-проблему через 20 минут и выключил за 30 секунд без отката деплоя
  • Facebook деплоит 100% изменений через feature flags - разделение deploy и release позволяет делать 10+ деплоев в день без release-риска для конечных пользователей
  • Twitter (X) автоматически включает kill switch на real-time subscriptions для viral-твитов, снижая fan-out нагрузку в 50-100 раз без участия on-call инженера

Feature Flags в real-time системах

**Slack, октябрь 2022.** Новый алгоритм компрессии WebSocket-фреймов показал в staging -40% трафика. Выкатили на 5% пользователей в production. Через 20 минут - жалобы на задержки у этих 5%. Выключили флаг. Проблема исчезла. Без feature flag пришлось бы откатывать деплой - ещё час downtime-риска.

Feature flag - это runtime-переключатель без деплоя. Код содержит обе ветки (старую и новую), флаг решает какую использовать. Это разделяет **deploy** (когда код попадает на сервер) и **release** (когда функция включается для пользователей).

Facebook использует feature flags для 100% деплоев - никогда не выкатывают функцию и флаг одновременно. Сначала мёртвый код (флаг выключен), потом постепенное включение. Это позволяет делать 10+ деплоев в день без release-риска.

В чём ключевое преимущество feature flags перед обычным деплоем для управления релизами?

Kill Switch: мгновенное отключение

Kill switch - аварийный рубильник: что-то сломалось в production прямо сейчас - через 30 секунд функция выключена для всех без деплоя. Для WebSocket kill switch работает на двух уровнях: **connection-level** (новые соединения без этой функции) и **session-level** (выключить в существующих соединениях без разрыва).

Twitter (X) использует kill switches для защиты от viral moments. Когда твит набирает аномальный трафик, автоматически включается kill switch на real-time subscription - WebSocket клиенты переключаются на polling каждые 30 секунд вместо push. Это снижает нагрузку на fan-out в 50-100 раз без участия on-call инженера.

Как kill switch доставляет изменение в уже подключённые WebSocket-сессии?

Gradual Rollout: от 1% до 100%

Gradual rollout - включение функции для увеличивающегося процента пользователей: 1% -> 5% -> 20% -> 50% -> 100%. На каждом шаге - анализ метрик. Проблема обнаружена на 1% - затронуто 10K пользователей. На 100% - 1 млн.

Детерминированное распределение критично: пользователь не должен получать разный опыт при каждом соединении. `hash(userId) % 100 < rolloutPercentage` гарантирует что один пользователь всегда попадает в одну группу.

Guard rails - автоматические правила остановки rollout. Если error rate в группе с включённым флагом превысил baseline на 0.5% - автоматический rollback без участия человека. LaunchDarkly, Unleash, Growthbook поддерживают такие правила из коробки.

Почему для gradual rollout используется `hash(userId) % 100`, а не `random() % 100`?

Доставка флагов в реальном времени

Проверять флаг при каждом сообщении в Redis - дорого. Кешировать локально - задержка обновления. Стандартный подход: **local cache + Redis pub/sub**. Каждый инстанс кеширует флаги в памяти (TTL 30-60с). При изменении флага - Redis pub/sub уведомляет все инстансы об инвалидации.

LaunchDarkly обслуживает 20 млрд flag evaluations в день с p99 latency под 1мс. Секрет - streaming SDK: сервер держит SSE-соединение с LaunchDarkly, получает изменения флагов в реальном времени и обновляет локальный in-memory store. Никакого polling на горячем пути.

Все feature flags - временный код, их нужно удалять сразу после полного rollout

Постоянные kill switches и ops flags должны оставаться - это аварийные рубильники, не временный код

Флаги делятся на временные (rollout новой функции - удалить через 2-4 недели) и постоянные (kill switch для защиты от перегрузки, ops toggle для отладки). Удаление постоянных флагов убирает защитный механизм системы.

Как оптимально организовать доставку изменений feature flags в 50 инстансов сервера?

Итоги

  • Feature flags разделяют deploy и release - код на сервере, функция выключена до явного включения
  • Kill switch через Redis pub/sub доставляет аварийное отключение во все инстансы за миллисекунды
  • hash(userId) % 100 гарантирует детерминированное распределение - один пользователь всегда в одной группе
  • Local cache + Redis pub/sub: O(1) latency на hot path и мгновенная инвалидация при изменении

Связанные темы

Feature flags пересекаются с несколькими областями backend-разработки

  • A/B тестирование — Gradual rollout с метриками - это контролируемый A/B эксперимент
  • Graceful Deployment — Feature flags дают более гибкий контроль над rollout чем стратегии деплоя K8s
  • Redis Pub/Sub — Основной механизм для мгновенной доставки изменений флагов между инстансами
  • Chaos Engineering — Feature flags используются для безопасного тестирования failure scenarios в production

Вопросы для размышления

  • Что произойдёт с пользователями в группе с включённым флагом если они переподключатся во время partial rollout?
  • Как обеспечить consistency если один пользователь подключён с двух устройств, а rollout = 50%?
  • Когда стоит предпочесть feature flag над canary deployment через Kubernetes?

Связанные уроки

  • sd-10-microservices
Feature Flags

0

1

Войти