Кэширование на сервере

Векторные карты в MapLibre GL JS строятся из множества независимых ресурсов: тайлов, стилей, шрифтовых глифов, спрайтов и изображений слоёв. Каждый из этих компонентов загружается по HTTP(S), что делает сетевую подсистему критическим фактором производительности. Серверное кэширование определяет, насколько быстро клиент может собирать карту и как часто происходит повторная загрузка идентичных данных.


Иерархия кэшируемых ресурсов в MapLibre GL JS

MapLibre GL JS обращается к нескольким типам ресурсов, каждый из которых требует отдельной стратегии кэширования:

  • Vector tiles (MVT) — основные данные карты
  • Raster tiles — растровые подложки
  • Style JSON — описание слоёв и источников данных
  • Sprites — набор иконок и текстур интерфейса карты
  • Glyphs — растровые шрифты для подписей
  • GeoJSON источники (опционально)

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


Кэширование тайлов: основная нагрузка системы

Структура URL тайлов

Типичный векторный тайл в MapLibre GL JS запрашивается по схеме:

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

Или через шаблоны:

https://tiles.example.com/streets/{z}/{x}/{y}.vector.pbf

Кэширование тайлов эффективно только при стабильности URL-структуры. Любое изменение параметров запроса (query string, заголовки авторизации) снижает вероятность попадания в CDN cache hit ratio.


Заголовки HTTP для тайлового кэша

Наиболее критичные заголовки:

Cache-Control

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

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

ETag

ETag: "tile-v3-48291"

Позволяет клиенту и CDN выполнять условные запросы. Особенно полезен при динамически обновляемых наборах данных.

Last-Modified

Last-Modified: Tue, 10 Jun 2026 12:00:00 GMT

Используется как fallback механизм для кэшей, не поддерживающих ETag.


Версионирование тайлов как ключ к эффективному кэшированию

Одним из наиболее эффективных подходов является внедрение версионирования в путь ресурса:

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

или через хеш данных:

/tiles/8f3a91c/{z}/{x}/{y}.pbf

Такой подход позволяет задавать максимально агрессивный кэш:

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

Обновление данных приводит к изменению версии, что автоматически инвалидирует кэш без необходимости purge на CDN уровне.


CDN-слой как основа масштабирования

MapLibre GL JS практически всегда работает в связке с CDN, так как количество запросов на тайлы может достигать десятков тысяч в минуту на одного пользователя при активном перемещении карты.

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

CDN кэширует:

  • бинарные .pbf тайлы
  • растровые .png/.jpg тайлы
  • sprite atlas (.png) и метаданные (.json)
  • glyph ranges

При корректной конфигурации cache hit ratio достигает 95–99%, снижая нагрузку на origin-сервер.


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

Файл стиля (style.json) является точкой входа для всей карты. Он содержит ссылки на источники данных и описание слоёв.

Рекомендуемая стратегия:

Cache-Control: public, max-age=3600

или при версионировании:

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

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

Инвалидация стиля

Изменение стиля может привести к:

  • изменению источников данных
  • добавлению новых слоёв
  • обновлению sprite/glyph ссылок

Поэтому стиль часто связывается с версией сборки фронтенда:

style-v12.json

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

Sprite в MapLibre GL GL JS состоит из двух файлов:

  • sprite.png
  • sprite.json

Особенности кэширования

Спрайты являются полностью статическими ресурсами при сборке:

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

Любое изменение иконок приводит к генерации нового sprite atlas, что полностью исключает необходимость частичной инвалидации.


Кэширование глифов (шрифтов)

Глифы загружаются по диапазонам:

/fonts/{fontstack}/{start}-{end}.pbf

Пример:

/fonts/Open Sans Regular/0-255.pbf

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

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

Рекомендуемые заголовки:

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

Reverse proxy как уровень кэширования

Nginx

Классическая схема:

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=tiles:10g max_size=100g inactive=60d;

Конфигурация:

location /tiles/ {
    proxy_cache tiles;
    proxy_cache_valid 200 301 302 365d;
    proxy_cache_use_stale error timeout updating;
    add_header X-Cache-Status $upstream_cache_status;
}

Nginx эффективно кэширует тайлы на диске, уменьшая обращения к backend.


Varnish

Varnish применяется для более сложной логики:

  • нормализация URL
  • инвалидация по тегам
  • разделение кэша по регионам

Пример VCL:

if (req.url ~ "\.(pbf|png|jpg)$") {
    set req.ttl = 365d;
}

Кэширование на уровне object storage

При использовании S3-совместимых хранилищ:

  • тайлы размещаются как статические объекты
  • используется CDN поверх bucket

Заголовки задаются на уровне объекта:

aws s3 cp tile.pbf s3://bucket/tiles/ --cache-control "public,max-age=31536000,immutable"

Особенности поведения MapLibre GL JS при загрузке ресурсов

MapLibre GL JS использует параллельную загрузку ресурсов:

  1. Загружается style.json

  2. Инициализируются источники

  3. Параллельно запрашиваются:

    • тайлы
    • glyph ranges
    • sprite

Важный аспект

Browser cache и HTTP cache CDN работают совместно:

  • CDN снижает latency
  • браузер устраняет повторные запросы при панорамировании

Инвалидация кэша и её стратегии

Существует три основных подхода:

1. Версионирование ресурсов

Наиболее стабильный метод:

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

Инвалидация происходит автоматически.


2. Purge CDN

Используется при невозможности версионирования:

  • удаление объектов из edge cache
  • ручной или API-driven purge

Недостаток — высокая стоимость и задержки.


3. Short TTL + revalidation

Пример:

Cache-Control: public, max-age=300, must-revalidate

Используется для динамических данных.


Оптимизация cache hit ratio

Факторы, влияющие на эффективность:

  • стабильность URL
  • отсутствие query string параметров
  • использование CDN edge locations
  • корректные cache headers
  • предсказуемая структура тайлов

Частые ошибки конфигурации

1. Динамические query параметры

/tiles/{z}/{x}/{y}.pbf?token=abc

Сильно снижает cache hit ratio.


2. Отсутствие версионирования

Приводит к необходимости постоянного purge.


3. Кэширование style.json с коротким TTL без версии

Вызывает рассинхронизацию между стилем и тайлами.


4. Разные домены без общего CDN

Разделение ресурсов:

  • tiles.example.com
  • fonts.example.com
  • sprites.example.com

Усложняет кросс-кэширование.


Согласованность между слоями кэша

Эффективная система кэширования требует согласованности между:

  • backend (tile server)
  • reverse proxy
  • CDN edge
  • browser cache

Любое расхождение в TTL или версии приводит к артефактам:

  • устаревшие тайлы при новом стиле
  • отсутствующие глифы
  • рассинхронизация sprite atlas

Производственные архитектуры

Статическая генерация (MBTiles → CDN)

  • генерация тайлов заранее
  • экспорт в S3
  • CDN как единственный слой доставки

Высочайшая эффективность кэширования.


Динамический tile server (Tegola, TileServer GL)

  • генерация по запросу
  • агрессивное кэширование на edge

Баланс между гибкостью и производительностью.


Гибридный подход

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

Используется в аналитических и real-time системах.


Поведение при масштабировании

При росте нагрузки:

  • cache hit ratio становится критическим параметром
  • origin server должен обрабатывать только cache miss
  • CDN берёт на себя 95%+ трафика

MapLibre GL JS при интенсивном pan/zoom генерирует burst-запросы, которые эффективно сглаживаются только многоуровневым кэшированием.


Контроль качества кэширования

Метрики:

  • cache hit ratio (CDN)
  • origin request rate
  • tile latency p95/p99
  • revalidation rate
  • stale responses frequency

Эти показатели определяют устойчивость карты под нагрузкой и корректность конфигурации HTTP-кэша.