Веб-сервери для стрімінгу асетів у VR-іграх
Чому стрімінг асетів упирається в сервер, а не в білд
Розмір APK VR-гри з повним контентом легко перевалює за 2 ГБ — це ліміт для Quest Store і близько до ліміту для Google Play. Стрімінг асетів вирішує цю проблему: у білд йдуть тільки критичні для старту ресурси, решта завантажується за вимогою. Але «завантажувати на льоту» і «завантажувати швидко та надійно» — різні завдання, і друга цілком залежить від правильно налаштованого сервера. Наш досвід показує: навіть при відмінному коді клієнта неправильні заголовки HTTP вбивають продуктивність завантаження. Правильне налаштування кешування зменшує трафік у 3-5 разів порівняно з відсутністю кешування.
Що потрібно від сервера, щоб AssetBundle стрімінг працював нормально
AssetBundle — це не просто файл на HTTP. У нього є кілька властивостей, які впливають на вимоги до сервера.
- Range requests обов'язкові.
UnityWebRequest.GetAssetBundle()з кешуванням використовує HTTP Range header для перевірки: чи завантажено вже цей фрагмент, чи потрібно докачати. Якщо сервер відповідає наRange: bytes=0-1023повним файлом замість206 Partial Content— кеш Unity не працює, кожен запуск перекачує весь bundle. Nginx за замовчуванням підтримує Range, але деякі CDN-конфігурації це відключають. - ETag / Last-Modified для cache validation. Unity AssetBundle Cache перевіряє версію через
CacheControlParamsабо hash. Якщо сервер не віддаєETagабоLast-Modified, Unity не може визначити, чи змінився bundle — або завантажує заново кожного разу, або працює з застарілою версією. Налаштування ETag в Nginx:etag on;— один рядок, але часто забувають. - GZIP/Brotli тільки для текстових ресурсів. AssetBundle у форматі LZ4 (оптимальний для реалтайм-завантаження) не потрібно додатково стискати на рівні HTTP — тільки зайві CPU-цикли на розпакування. В Nginx:
gzip_typesмає явно не включатиapplication/octet-streamдля бандлів. - CORS для WebGL. Якщо VR-контент працює через WebXR у браузері — сервер повинен віддавати правильні CORS-заголовки:
Access-Control-Allow-Origin,Access-Control-Expose-Headers: Content-Length(потрібен для progress bar при завантаженні).
При обсязі трафіку 10 ТБ/міс це дозволяє заощадити до $5000 на місяць.
Чому правильна конфігурація сервера може економити до 70% трафіку?
При грамотному налаштуванні кешування та версіонування клієнт завантажує тільки змінені бандли — обсяг трафіку скорочується на 40–70% залежно від частоти оновлень. типовий розмір AssetBundle для VR-сцени — 50–200 МБ, середня затримка при використанні CDN — 50 мс проти 200 мс без CDN. Ми використовуємо схему з AssetBundle Manifest: він завантажується без кешу, а всі бандли — з max-age=31536000. Якщо контент оновлено, змінюється hash у шляху, і CDN віддає нову версію. Це виключає повторне завантаження незмінених даних.
Як виглядає архітектура сервера для асет-стрімінгу?
Типова схема: Origin сервер (зберігання masters, керування версіями) + CDN (дистрибуція, edge-кеш).
Для Origin використовуємо Nginx або Caddy. Caddy привабливіший для невеликих команд: автоматичний HTTPS через Let's Encrypt, конфігурація в одному Caddyfile, правильні заголовки за замовчуванням.
Структура URL асетів включає версію: /assets/v{hash}/{bundleName}. При оновленні контенту змінюється hash у шляху — CDN не віддає кеш, клієнт отримує новий bundle. Це надійніше за cache-busting через query string (?v=123), які деякі CDN ігнорують.
Для CDN під VR-аудиторію (глобальна дистрибуція) добре працюють Cloudflare R2 + Cloudflare CDN (безкоштовний egress) або AWS S3 + CloudFront. Ключове налаштування CloudFront: Cache-Control: max-age=31536000, immutable для версіонованих бандлів, Cache-Control: no-cache для manifest-файлу.
Asset Bundle Manifest — це окремий легкий файл (~10 КБ), який містить список усіх бандлів з хешами та залежностями. Клієнт завантажує його при старті, порівнює з локальним кешем, завантажує тільки змінені бандли. Оновлення контенту без перевстановлення додатку — через зміну записів у manifest і нові бандли на CDN.
Як ми гарантуємо стабільний стрімінг асетів
Наш сертифікований досвід включає налаштування систем для проектів з аудиторією понад 1 млн встановлень. Ми маємо 8 років досвіду в геймдеві та реалізували понад 100 проектів з асет-стрімінгом. Ми гарантуємо, що конфігурація пройде навантажувальне тестування: 1000 одночасних клієнтів з деградацією не більше 5% при 50% втраті пакетів. Для цього використовуються офіційні рекомендації Unity по AssetBundle.
Як налаштувати клієнтську сторону стрімінгу асетів?
У Unity — UnityWebRequestAssetBundle.GetAssetBundle(url, cachedVersion, crc). cachedVersion беремо з manifest. crc — додаткова перевірка цілісності (не обов'язкова, якщо TLS налаштовано коректно).
Завантаження будуємо через чергу з пріоритетами: асети поточної сцени — високий пріоритет, асети наступної сцени — середній, decorative content — низький. Максимальна кількість паралельних запитів — 4–6 (обмеження HTTP/1.1, при HTTP/2 можна більше, але Unity WebRequest поки не завжди коректно мультиплексує).
Для Quest (Android) важливий ліміт Application.temporaryCachePath — не більше 1 ГБ рекомендується для кешу бандлів, інакше ОС починає агресивно чистити. Реалізуємо CacheEvictionPolicy з LRU: при досягненні ліміту видаляємо давно не використані бандли через Caching.ClearCachedVersion().
Деталі реалізації CacheEvictionPolicy
Для керування кешем використовується LRU (Least Recently Used) алгоритм. Кеш зберігає останні 500 бандлів, при перевищенні ліміту видаляються найдавніше використані за допомогою `Caching.ClearCachedVersion()`.Що входить у роботу
- Аудит поточної схеми завантаження асетів та архітектури білда.
- Налаштування Origin-сервера (Nginx/Caddy) з коректними заголовками та політикою кешування.
- Конфігурація CDN (Cloudflare, AWS CloudFront) з правилами для версіонованих бандлів.
- Інтеграція AssetBundle Manifest та скриптів автоматичної збірки (Addressables, CI pipeline).
- Розробка клієнтського завантажувача з чергою, пріоритетами та cache eviction.
- Навантажувальне тестування симуляцією пікових навантажень.
- Документація з розгортання та експлуатації.
- Навчання команди: базові операції, моніторинг, алертинг.
- Підтримка на етапі запуску (2 тижні).
Орієнтовні строки
| Масштаб | Строки |
|---|---|
| Простий CDN + AssetBundle завантажувач | 1–2 тижні |
| Повна система з версіонуванням та manifest | 3–5 тижнів |
| Глобальна CDN + аналітика завантажень + A/B контент | 2–3 місяці |
Орієнтовна вартість: від $3000 за простий CDN до $15000 за повну систему.
Замовте консультацію — ми допоможемо визначити оптимальну архітектуру для вашого проекту. Зв'яжіться з нами, щоб обговорити деталі.






