Стратегии кэширования

Кэширование в Mapbox GL JS строится как многоуровневая система, в которой одновременно участвуют браузерный HTTP-кэш, внутренний кэш тайлового рендерера, кэш ресурсов (glyphs, sprites), а также прикладные стратегии предварительной загрузки и офлайн-хранения. Эффективная работа карты напрямую зависит от согласованности этих уровней и корректной настройки источников данных.

Архитектура кэширования в Mapbox GL JS можно рассматривать как цепочку:

  • HTTP-кэш браузера (уровень сети)
  • Кэш ресурсов WebGL-рендерера
  • Кэш тайлов (vector/raster tiles)
  • Кэш стилей и метаданных источников
  • Дополнительные прикладные механизмы (Service Worker, IndexedDB)

Каждый слой решает собственный класс задач и имеет собственную стратегию инвалидирования.

HTTP-кэширование тайлов и ресурсов

На уровне сети ключевую роль играют HTTP-заголовки:

  • Cache-Control
  • ETag
  • Last-Modified

Тайлы, загружаемые картой, обычно представляют собой:

  • vector tiles (.pbf)
  • raster tiles (.png, .jpg)
  • glyph ranges (.pbf)
  • sprite sheets (.png + .json)

Браузер кэширует эти ресурсы автоматически при корректной настройке заголовков. Наиболее эффективная стратегия — immutable-кэширование с долгим TTL:

Cache-Control: public, max-age=31536000, immutable

При этом обновление данных достигается через версионирование URL (например, добавление версии стиля или tileset id).

Внутренний кэш тайлового движка

В Mapbox GL JS существует отдельный in-memory кэш тайлов. Он управляется через LRU-алгоритм (Least Recently Used), где:

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

Ключ кэша формируется из:

  • координат (z/x/y)
  • источника данных
  • параметров запроса (например, tileSize, bounds)

Это означает, что даже при одинаковом URL тайл может не совпадать логически, если отличается стиль или параметры слоя.

Кэширование векторных тайлов

Vector tiles являются наиболее эффективным форматом с точки зрения кэширования, поскольку:

  • поддерживают повторное использование на разных стилях
  • позволяют рендеринг на клиенте
  • имеют предсказуемую структуру запросов

Стратегия кэширования:

  • агрессивный HTTP-кэш
  • долгоживущий in-memory cache
  • переиспользование геометрии между слоями

Особенность: один и тот же тайл может использоваться несколькими слоями стиля одновременно, что снижает количество запросов.

Кэширование растровых тайлов

Raster tiles менее гибкие, поскольку содержат уже отрендеренные изображения. Это приводит к:

  • увеличению объема HTTP-кэша
  • отсутствию переиспользования геометрии
  • более высокой зависимости от zoom-level

Оптимизация достигается через:

  • правильное выравнивание zoom-уровней источника
  • использование CDN с edge-кэшированием
  • минимизацию числа уникальных tile URL

Glyphs и кэширование шрифтов

Glyphs в Mapbox GL JS загружаются пакетами диапазонов символов. Каждый диапазон:

  • запрашивается отдельно
  • кэшируется в памяти
  • может переиспользоваться между стилями

Типичный URL:

/fonts/{fontstack}/{range}.pbf

Стратегия кэширования:

  • долгий HTTP TTL
  • повторное использование glyph atlas в памяти
  • загрузка только необходимых диапазонов (lazy loading)

При смене языка или стиля часть кэша становится неактуальной, но сохраняется до вытеснения LRU.

Кэширование спрайтов

Спрайты состоят из:

  • изображения (sprite.png)
  • метаданных (sprite.json)

Особенности:

  • загружаются один раз на стиль
  • полностью кэшируются браузером
  • декомпозируются в WebGL текстуры

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

Кэш стилей

Style JSON также участвует в кэшировании. Однако он:

  • загружается при инициализации карты
  • не обновляется автоматически без смены URL
  • может быть закэширован браузером или Service Worker

Ключевой принцип: изменение стиля должно сопровождаться изменением его URL, иначе возможны устаревшие конфигурации слоев.

Service Worker как слой кэширования

Использование Service Worker позволяет внедрить собственную стратегию:

  • Cache First для тайлов
  • Network First для стилей
  • Stale-While-Revalidate для метаданных

Пример стратегии:

self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);

  if (url.pathname.includes('/tiles/')) {
    event.respondWith(
      caches.match(event.request).then(cached => {
        return cached || fetch(event.request);
      })
    );
  }
});

Service Worker позволяет реализовать офлайн-карты, но требует строгого контроля версионирования данных.

Офлайн-кэширование и предварительная загрузка

Офлайн-режим требует явного сохранения:

  • тайлов определенного региона
  • glyph ranges
  • sprite sheets
  • style JSON

Стратегии:

Географическая предзагрузка

Кэширование тайлов в bounding box:

  • фиксированный zoom range
  • ограниченная область карты
  • сохранение в IndexedDB

Прогрев кэша

Предварительный запрос тайлов:

  • при загрузке приложения
  • при переходе в регион
  • при изменении маршрута

Это уменьшает задержки первого рендера.

Инвалидация кэша

Одна из ключевых проблем — обновление данных.

Подходы:

Версионирование URL

/tiles/v2/{z}/{x}/{y}.pbf

Хеширование контента

  • style hash
  • tileset hash
  • sprite version

Управляемая очистка LRU

Внутренний кэш очищается автоматически, но:

  • Service Worker требует ручной очистки
  • IndexedDB требует миграций

Производительность и баланс памяти

Кэширование напрямую влияет на:

  • потребление RAM
  • загрузку GPU
  • сетевую активность

В Mapbox GL JS важны следующие параметры:

  • maxTileCacheSize (косвенно через конфигурации)
  • reuse of WebGL textures
  • ограничение zoom-level prefetching

Переполнение кэша приводит к:

  • частым повторным загрузкам тайлов
  • фризам при pan/zoom
  • росту latency при рендеринге

Повторное использование данных между стилями

Если несколько стилей используют один tileset:

  • тайлы могут переиспользоваться
  • снижается сетевой трафик
  • ускоряется переключение стилей

Однако это работает только при идентичности:

  • source URL
  • tile scheme
  • zoom constraints

Типичные ошибки кэширования

  • отсутствие версионирования tileset URL
  • агрессивный Cache-Control без инвалидатора
  • дублирование источников с разными параметрами
  • использование уникальных URL для одинаковых тайлов
  • отсутствие контроля Service Worker над обновлением

Кэширование в WebGL контексте

Дополнительный уровень — GPU-кэш:

  • текстуры тайлов
  • буферы вершин
  • sprite atlases

Этот слой не контролируется напрямую, но зависит от:

  • частоты обновления кадра
  • количества видимых тайлов
  • размера viewport

При нехватке GPU памяти происходит пересоздание ресурсов, что визуально выражается в “перемигивании” карты при панорамировании.