Розробка live-чату для стрімів: архітектура та реалізація
Ми розробляємо чат прямого ефіру для мобільних застосунків — не просто «надіслати повідомлення». При 10 000 одночасних глядачів стандартний підхід з Firebase Firestore onSnapshot створює 10 000 відкритих слухачів, і рахунок за Firebase зростає експоненційно. Більше того, на слабких пристроях (iPhone 7, бюджетні Android) частота повідомлень >30/с викликає падіння FPS до 10–15 через часті ререндери. Наш досвід — 5+ років і 40+ проєктів у мобільній розробці — дозволяє спроєктувати архітектуру, яка тримає навантаження і залишається бюджетною.
Правильне рішення — fan-out на сервері: клієнт підписується на один WebSocket-канал, отримує агрегований потік, а не тисячу окремих слухачів. Це знижує витрати на транспорт у 30 разів і виключає лавину ререндерів. Порівняємо підходи:
| Транспорт | Навантаження | Вартість | Складність |
|---|---|---|---|
| Firestore onSnapshot | до 1 000 | висока | низька |
| WebSocket/SSE + Redis | 10 000+ | низька | середня |
Чому WebSocket, а не Firestore?
Для live-чату ключове рішення — fan-out на сервері, не на клієнті. Клієнт підписується на один WebSocket або SSE-канал і отримує агрегований потік. Це виключає 10 000 одночасних слухачів і знижує витрати. Стек, який працює при 5000+ глядачів:
- Транспорт: WebSocket (Socket.io або чистий ws) або Server-Sent Events (SSE)
- Буфер: Redis Pub/Sub для розподілу між інстансами
- Троттлінг: на сервері — не більше 50–100 повідомлень/сек у канал, надлишок агрегується
- Клієнтський рендер: віртуалізований список з глибиною 100–200 повідомлень
WebSocket у три рази швидший за SSE за часом доставки повідомлення до клієнта (50 мс проти 150 мс при середніх значеннях).
Як боротися зі спамом у live-чаті?
Без модерації чат швидко стає марним. Мінімальний набір захисту включає rate limiting на клієнті з блокуванням кнопки на 2–3 секунди, фільтрацію на сервері за допомогою регулярних виразів або бібліотеки bad-words, slow mode з інтервалом 30–60 секунд для неверифікованих користувачів, а також мьют і бан через Redis SET з TTL, щоб не навантажувати базу даних. Виділені повідомлення (суперчат) йдуть окремим каналом без троттлінгу, з анімацією і таймером видимості. У React Native це абсолютно позиціонований View з Animated.timing, на Android (Kotlin) — View animator, на iOS (Swift) — UIViewPropertyAnimator.
Детальний приклад батчингу в React Native
const batchInterval = 200; const pendingMessages = useRef<Message[]>([]); useEffect(() => { const timer = setInterval(() => { if (pendingMessages.current.length > 0) { setMessages(prev => [...prev, ...pendingMessages.current]); pendingMessages.current = []; } }, batchInterval); return () => clearInterval(timer); }, []); Такий підхід тримає 60 FPS при 30 повідомленнях/с на iPhone 7. Порівняйте батчинг з інтервалом 200 мс і без батчингу:
| Режим | FPS (iPhone 7) | FPS (Samsung A10) |
|---|---|---|
| Без батчингу | 10–15 | 5–8 |
| З батчингом 200 мс | 60 | 55–60 |
Як влаштований суперчат?
Оплачені повідомлення не беруть участі в троттлінгу. У них окремий канал з пріоритетом 2 (вище звичайного). Клієнт рендерить їх поверх списку з анімацією, таймером видимості 10–30 сек і кастомним фоном. У стейті зберігаємо масив superChatQueue, який не змішується зі звичайними повідомленнями.
Як ми це робимо: процес роботи
- Аналітика: вивчаємо очікуване навантаження, обираємо стек (WebSocket/SSE, Redis, Firebase)
- Проєктування: схема даних, API, протокол реконекту
- Реалізація: серверний модуль + клієнтський SDK з батчингом (підтримуємо Swift, Kotlin, React Native)
- Тестування: навантажувальні тести (k6, Artillery) на 10 000 віртуальних користувачів
- Деплой: CI/CD, моніторинг (Prometheus + Grafana)
Що входить у роботу
- Вихідний код серверного та клієнтського модулів (iOS, Android, Web)
- Документація API та архітектури
- Доступи до репозиторію та CI
- Навчання команди (2 години)
- 2 тижні підтримки після деплою
Терміни та оцінка
WebSocket-чат з батчингом, rate limiting і базовою модерацією: 3–5 тижнів. З суперчатом та історією: 5–8 тижнів. Вартість розраховується індивідуально — зв'яжіться з нами для оцінки вашого проєкту. Замовте консультацію — ми покажемо працюючий прототип.
Реконект: ігнорувати чи завантажувати пропущене?
При розриві на 10 секунд користувач пропустив N повідомлень. Два підходи: перший — ігнорувати прогалину, при реконекті продовжуємо з поточного моменту; другий — backfill, запитуємо пропущені через REST /chat/history?after=
Досвід показує: якісний чат прямого ефіру — це баланс між продуктивністю, вартістю та UX. Перехід на WebSocket дозволяє скоротити витрати на інфраструктуру в 30 разів. Ми гарантуємо, що ваш чат витримає пікові навантаження. Зв'яжіться з нами — обговоримо деталі.







