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?