О насБлогКонтакты
Мобильная разработка18 июля 2012 г. 4 мин 6

GPRS-оптимизация в 2012: как мы делали мобильные API для медленного интернета

AunimedaAunimeda
📋 Содержание

GPRS-оптимизация в 2012: как мы делали мобильные API для медленного интернета

Летом 2012 года мы запускали мобильное приложение для одного из бишкекских клиентов. Первые тесты на офисном Wi-Fi выглядели отлично. Первый тест с реальным телефоном в реальных условиях — GPRS на «Мегакоме» — показал загрузку главного экрана за 14 секунд.

14 секунд. На экран с 8 элементами.

Это не было проблемой сервера. Это была проблема архитектуры, которую мы спроектировали без понимания канала доставки.


Почему GPRS убивал стандартный REST

GPRS — это не просто «медленный Wi-Fi». У него другая физическая природа:

  • Пропускная способность: 40–80 кбит/с при хорошем сигнале, реально 20–40
  • Задержка (latency): 400–800 мс на один round trip
  • Потери пакетов: 2–5% в норме, 10–15% при слабом сигнале
  • Нестабильность: соединение может прерваться в середине передачи

Наш API делал 6 последовательных запросов при загрузке главного экрана. Каждый запрос — отдельный HTTP round trip. При задержке 600 мс только на установку соединений уходило 3,6 секунды ещё до передачи данных.

Запрос 1: GET /user/profile        → 600ms latency + 200ms данные
Запрос 2: GET /feed?page=1         → 600ms latency + 800ms данные  
Запрос 3: GET /notifications/count → 600ms latency + 100ms данные
...
Итого: ~8-10 секунд только на latency

Что мы изменили

1. Агрегированный endpoint для первого экрана

Вместо шести запросов — один. Сервер собирает все данные для начального рендера и возвращает их одним ответом:

// Было: клиент делает 6 запросов
// GET /user/profile, /feed, /notifications, /banners, /categories, /stats

// Стало: один endpoint с данными для старта приложения
// GET /app/bootstrap

$response = [
    'user'          => $this->getUserProfile($userId),
    'feed'          => $this->getFeedPreview($userId, 5),  // только 5 постов
    'notifications' => $this->getUnreadCount($userId),
    'categories'    => $this->getActiveCategories(),       // кэшировалось 10 минут
    'version'       => APP_VERSION,
];

6 round trips → 1. На GPRS это экономило 3–5 секунд.

2. Агрессивное сжатие

JSON без gzip на медленном канале — преступление. Мы добавили gzip с уровнем 6 (баланс скорость/степень сжатия) и убрали лишние пробелы из ответов.

// Включить gzip на сервере (nginx)
gzip on;
gzip_types application/json text/plain text/css;
gzip_comp_level 6;
gzip_min_length 256;

// В PHP: убираем лишние пробелы из JSON
echo json_encode($data, JSON_UNESCAPED_UNICODE);
// Не JSON_PRETTY_PRINT — это добавляет сотни байт

Типичный ответ с профилем пользователя: 4,2 КБ → 1,1 КБ после сжатия. На GPRS это разница в 0,8 секунды на один запрос.

3. Минимальный payload

Мы возвращали только те поля, которые клиент реально использовал. Стандартная ошибка — отдавать всю запись из БД:

// Плохо: отдаём всё
SELECT * FROM users WHERE id = ?
// → 40 полей, 2KB JSON, половина не нужна мобильному клиенту

// Хорошо: только нужное для этого экрана
SELECT id, name, avatar_url, is_verified FROM users WHERE id = ?
// → 4 поля, 180 байт JSON

Мы ввели правило: каждый endpoint имеет документированный список возвращаемых полей, и это список пересматривается с мобильной командой при каждом изменении.

4. Дельта-синхронизация вместо полной загрузки

При повторных загрузках клиент передавал timestamp последней синхронизации. Сервер отдавал только изменения:

// Клиент передаёт: ?since=1342612345
$since = (int) $_GET['since'];

if ($since > 0) {
    // Дельта: только новые/изменённые посты
    $posts = Post::where('updated_at', '>', $since)
                 ->where('user_id', $userId)
                 ->limit(20)
                 ->get();
    $mode = 'delta';
} else {
    // Первая загрузка
    $posts = Post::latest()->limit(20)->get();
    $mode = 'full';
}

echo json_encode(['mode' => $mode, 'items' => $posts, 'ts' => time()]);

После первой загрузки обновление ленты стало передавать в среднем 3–5 новых постов вместо 20. Трафик упал в 4–6 раз на повторных запросах.

5. Таймауты и fallback

GPRS-соединение может зависнуть на 30+ секунд, не вернув ни ошибки, ни данных. Клиент без таймаутов просто висит.

// Android, 2012 (Apache HttpClient, который тогда использовали все)
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 8000);  // 8 сек на коннект
HttpConnectionParams.setSoTimeout(params, 12000);          // 12 сек на чтение

// При таймауте: показываем кэшированные данные + индикатор "нет сети"
try {
    JSONObject data = apiClient.getBootstrap();
    updateUI(data);
} catch (SocketTimeoutException e) {
    JSONObject cached = localCache.getBootstrap();
    if (cached != null) {
        updateUIFromCache(cached);
        showOfflineBanner();
    } else {
        showRetryScreen();
    }
}

Результаты после оптимизации

Метрика До После
Загрузка главного экрана (GPRS) 14 сек 3,8 сек
Количество HTTP-запросов при старте 6 1
Средний размер ответа /bootstrap 18 КБ 2,2 КБ
Трафик при обновлении ленты 42 КБ 7 КБ

3,8 секунды на GPRS — всё ещё медленно по современным меркам. По меркам 2012 года в Бишкеке — достаточно быстро, чтобы пользователи не удаляли приложение.


Принцип, который остался

Тестируй на реальном устройстве в реальных условиях сети до того, как покажешь клиенту. Не на эмуляторе. Не на офисном Wi-Fi. Выйди на улицу, включи мобильный интернет, зайди в переход или подвал — и смотри как ведёт себя приложение там.

В 2012 году это было требование выживания. Сегодня, когда значительная часть пользователей Центральной Азии всё ещё работает на нестабильном 3G в районах с плохим покрытием, это требование актуально в той же мере.

Читайте также

Разработка мобильного приложения в Бишкеке: цены и сроки в 2026 годуaunimeda
Мобильная разработка

Разработка мобильного приложения в Бишкеке: цены и сроки в 2026 году

Сколько стоит разработка мобильного приложения в Бишкеке? Разбираем цены на iOS и Android приложения, сроки, этапы работы и как выбрать студию разработки в Кыргызстане.

WAP и мобильный интернет в Кыргызстане 2010–2011: как мы делали первые мобильные сайтыaunimeda
Мобильная разработка

WAP и мобильный интернет в Кыргызстане 2010–2011: как мы делали первые мобильные сайты

До смартфонов и адаптивного дизайна был WAP. В 2010 году 80% мобильного трафика в Кыргызстане шло с кнопочных телефонов через GPRS на WAP-сайты. Делать 'мобильную версию' означало делать отдельный WAP-сайт с HTML размером не больше 15 КБ и без JavaScript.

Flutter vs React Native в 2026 году: что выбрать для разработки мобильного приложенияaunimeda
Мобильная разработка

Flutter vs React Native в 2026 году: что выбрать для разработки мобильного приложения

Сравниваем Flutter и React Native в 2026: производительность, экосистема пакетов, стоимость разработки в Бишкеке и рекомендации по выбору стека для разных типов проектов.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Кыргызстане. Бесплатная консультация.

Получить консультацию Все статьи