Обновлено: 21 апреля 2026 г. в 16:55

Notification System

средний

Классический кейс про систему уведомлений: push, email и SMS, управление токенами устройств, гарантии доставки и повторные попытки при сбоях.

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

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

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

Бюджет задержек

Для каждого канала нужно заранее определить допустимое время доставки и поведение системы, если канал перестаёт в него укладываться.

Распределение по каналам

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

Состояние пользователя

Нужно явно учитывать подключённые устройства, quiet hours, порядок доставки и актуальные пользовательские настройки.

Мягкая деградация

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

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

Chapter 7

Acing SDI: Notification

Разбор кейса в книге Zhiyong Tan

Читать обзор

Типы уведомлений

Push на мобильных устройствах

APNs для iOS и FCM для Android. Доставка возможна даже когда приложение закрыто.

Email

Транзакционные и маркетинговые письма. SendGrid, SES, Mailgun.

SMS

Twilio, Vonage. 2FA и критические оповещения.

Уведомления в приложении

Доставка внутри приложения и через WebSocket, пока пользователь онлайн.

Требования

Функциональные

  • FR1
    Отправка push-уведомлений, email, SMS и уведомлений внутри приложения
  • FR2
    Поддержка шаблонов с персонализацией
  • FR3
    Настройки предпочтений пользователя
  • FR4
    Отложенная отправка по расписанию
  • FR5
    Ограничение частоты и пакетирование похожих уведомлений

Нефункциональные

  • NFR1
    10 млн+ уведомлений в день
  • NFR2
    Доставка в пределах нескольких секунд
  • NFR3
    Доставка по модели at-least-once с дедупликацией
  • NFR4
    Доступность 99,9%

Архитектура верхнего уровня

Архитектура верхнего уровня

Цветом выделены каналы доставки: Push (синий), Email (зелёный), SMS (янтарный)

Push-каналEmail-каналSMS-каналОбщий путь обработки

Бизнес-сервисы

Общий контур

Создают события

Сервис уведомлений

Общий контур

Маршрутизация и шаблоны

Очередь сообщений

Общий контур

Kafka / SQS

Разделение по каналам доставки: Push / Email / SMS

Push-воркеры

Push

APNs + FCM

Email-воркеры

Email

SendGrid / SES

SMS-воркеры

SMS

Twilio / Vonage

APNs

Push

Apple

FCM

Push

Google

SendGrid / SES

Email

Почтовые провайдеры

Twilio

SMS

SMS-провайдер

Доставка в пределах секунд
At-least-once и дедупликация
Горизонтальное масштабирование

Apple Push Notification Service (APNs)

Архитектура APNs

APNs работает поверх постоянного HTTP/2-соединения и поддерживает аутентификацию по сертификату или токену.

Провайдер → APNs → устройство

POST /3/device/<device_token>

Ключевые особенности

  • Device Token — уникальный токен устройства, который может меняться
  • Payload — JSON-пакет до 4 KB с полями alert, badge и sound
  • Priority — 10 для немедленной доставки или 5 для режима энергосбережения
  • Expiration — TTL для устройств, которые сейчас не в сети
  • Collapse ID — позволяет заменить предыдущее уведомление той же группы

Пример payload для APNs

{
  "aps": {
    "alert": {
      "title": "New Message",
      "body": "You have a new message from John"
    },
    "badge": 5,
    "sound": "default",
    "mutable-content": 1  // для Notification Service Extension
  },
  "custom_data": {
    "conversation_id": "abc123"
  }
}

Firebase Cloud Messaging (FCM)

Архитектура FCM

FCM поддерживает Android, iOS и web-клиенты. Для отправки используется HTTP v1 API с аутентификацией через OAuth 2.0.

POST /v1/projects/<project_id>/messages:send

Типы сообщений

  • Notification — сообщение, которое FCM показывает автоматически
  • Data — сообщение, которое приложение обрабатывает самостоятельно
  • Hybrid — оба типа в одном сообщении
💡 Сообщения типа Data дают полный контроль над отображением

Пример запроса FCM HTTP v1

{
  "message": {
    "token": "device_registration_token",
    "notification": {
      "title": "New Order",
      "body": "Your order #1234 has been shipped"
    },
    "data": {
      "order_id": "1234",
      "click_action": "OPEN_ORDER_DETAIL"
    },
    "android": {
      "priority": "high",
      "ttl": "86400s"
    },
    "apns": {
      "headers": {
        "apns-priority": "10"
      }
    }
  }
}

WebSocket

Chat System

Доставка в реальном времени через WebSocket

Читать обзор

Управление токенами устройств

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

Таблица реестра устройств

КолонкаТипОписание
user_idBIGINTСсылка на пользователя
device_tokenVARCHAR(255)Токен APNs или FCM
platformENUMios, android, web
app_versionVARCHAR(20)Версия приложения для совместимости и поэтапного запуска функций
last_active_atTIMESTAMPПомогает очищать неактуальные токены
created_atTIMESTAMPДата регистрации

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

Настройки пользователя

Уровни настроек

  • Global — включить или выключить все уведомления
  • Channel — управлять push, email и SMS по отдельности
  • Category — разделять маркетинговые, транзакционные и социальные уведомления
  • Quiet Hours — задавать тихие часы и временные ограничения

Ограничение частоты

  • Лимит N уведомлений в час или день
  • Объединение похожих уведомлений в один пакет
  • Отдельная приоритетная очередь для критических оповещений

Архитектура очередей сообщений

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

Топики:
├── notifications.push.ios      → Воркеры push-канала (APNs)
├── notifications.push.android  → Воркеры push-канала (FCM)
├── notifications.email         → Email-воркеры
├── notifications.sms           → SMS-воркеры
├── notifications.websocket     → Воркеры WebSocket
└── notifications.dlq           → Dead Letter Queue

Партиционирование: по user_id для порядка в рамках одного пользователя
Хранение: 7 дней (для повторных попыток и разбора инцидентов)

Rate Limiting

Rate Limiter

Защита внешних провайдеров от перегрузки

Читать обзор

Гарантии доставки

At-Most-Once

Отправили и забыли. Самый простой подход.

⚠️ Сообщения могут теряться

At-Least-Once

Повторные попытки с подтверждением. Требует дедупликации.

✓ Подходит для большинства практических случаев

Exactly-Once

Идемпотентный ключ плюс паттерн transactional outbox.

Сложно, дорого и нужно нечасто

Стратегия дедупликации

// Идемпотентный ключ = hash(user_id + notification_type + content_hash + date)

Redis SET with TTL:
  SETNX notification:dedupe:{idempotency_key} 1 EX 86400

Если ключ уже существует → отправку пропускаем

Повторные попытки и обработка ошибок

Стратегия повторных попыток

  • Exponential Backoff: 1s → 2s → 4s → 8s...
  • Max Retries: 3-5 попыток
  • Jitter: случайное смещение, чтобы размазать нагрузку
  • Circuit Breaker: при массовых ошибках у провайдера

Классификация ошибок

  • Повторяемые: 429, 503, таймаут сети
  • Неповторяемые: 400, 401, недействительный токен
  • DLQ: после исчерпания повторных попыток

Patterns

Release It!

Circuit Breaker и другие паттерны устойчивости

Читать обзор

Масштабирование

Горизонтальное масштабирование

• Stateless-воркеры — автомасштабирование по глубине очереди

• Разбиение по user_id для сохранения порядка доставки одному пользователю

• Отдельные пулы воркеров для каждого канала

Ограничения провайдеров

• APNs: HTTP/2-мультиплексирование, около 4000 запросов в секунду на соединение

• FCM: до 600 тыс. сообщений в минуту на платных планах

• Используйте пул соединений

Массовые уведомления: для рассылки на миллионы пользователей используйте FCM Topics или раскладывайте отправку через Kafka с пакетной обработкой.

Наблюдаемость

Метрики

  • Отправленные и неуспешные уведомления по каждому каналу
  • Задержка доставки (p50, p99)
  • Глубина очереди и отставание потребителей
  • Доля ошибок у внешних провайдеров

Логи

  • Структурированные логи с корреляционным идентификатором
  • Коды ответов провайдеров
  • Применённые пользовательские настройки

Оповещения

  • Всплеск ошибок
  • Рост очереди
  • Деградация внешнего провайдера

Что важно проговорить на интервью

Что показать в ответе

• Чем отличаются APNs и FCM

• Как устроен жизненный цикл device token

• Когда достаточно at-least-once и зачем нужна дедупликация

• Как защищать внешних провайдеров лимитами запросов

• Где применять пользовательские настройки и quiet hours

Типичные дополнительные вопросы

• Как сохранить порядок уведомлений для одного пользователя?

• Как обработать массовую рассылку на 10 млн пользователей?

• Как избежать дублирующихся уведомлений?

• Как приоритизировать критические оповещения?

Связанные главы

  • Chat System - даёт прикладной сценарий доставки в реальном времени, где уведомления внутри приложения и WebSocket становятся частью основного пользовательского потока.
  • Событийно-ориентированная архитектура: Event Sourcing, CQRS, Saga - объясняет асинхронную модель обработки событий, на которой обычно строят конвейер доставки уведомлений.
  • Distributed Message Queue - углубляет устройство очередей, партиционирование и гарантии доставки для масштабной рассылки уведомлений.
  • Rate Limiter - нужен для защиты внешних провайдеров, таких как APNs, FCM, SMS- и email-шлюзы, от всплесков нагрузки и злоупотреблений.
  • Паттерны устойчивости: Circuit Breaker, Bulkhead, Retry - дополняет подходы к повторным попыткам, DLQ и мягкой деградации при сбоях каналов доставки.
  • Протокол WebSocket - покрывает канал доставки внутри приложения через постоянное соединение и обновления с низкой задержкой.
  • Release It! (short summary) - даёт практики инженерной устойчивости для надёжной доставки уведомлений в рабочей системе.

Чтобы отмечать прохождение, включи трекинг в Настройки