Rate limiting

Визуализация карты в MapLibre GL JS опирается на непрерывный поток сетевых запросов: векторные тайлы, растровые тайлы, спрайты, glyphs (шрифты), данные источников GeoJSON. При изменении масштаба или перемещении карты библиотека динамически пересчитывает набор необходимых ресурсов. Без контроля нагрузки это приводит к резкому всплеску HTTP-запросов, перегрузке клиента, API и тайл-сервера.

Ограничение частоты запросов в контексте MapLibre GL JS — это совокупность механизмов, которые регулируют количество, скорость и приоритет сетевых обращений к источникам данных.


Модель генерации запросов в рендере карты

MapLibre GL JS использует тайловую модель. Каждый визуальный кадр потенциально требует:

  • векторные тайлы слоёв (vector sources)
  • растровые тайлы (raster sources)
  • изображения (icons/sprites)
  • шрифтовые глифы (glyphs)

При изменении состояния карты (zoom, center, bearing, pitch) происходит пересчёт видимых тайлов. Это приводит к:

  • созданию нового набора tile requests
  • отмене устаревших запросов
  • перерасчёту приоритетов загрузки

Ключевой фактор нагрузки — высокая частота событий move и zoom, которые могут генерировать десятки изменений в секунду.


Внутренние механизмы ограничения параллелизма

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

Основные параметры управления:

  • parallel tile requests
  • image request concurrency
  • glyph request batching
  • worker pool scheduling

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

Загрузка тайлов происходит через внутренний scheduler, который:

  1. собирает список необходимых ресурсов
  2. сортирует по приоритету (ближайшие к viewport — выше)
  3. ограничивает количество активных запросов
  4. перераспределяет очередь при изменении состояния карты

Ограничение через HTTP-ответы сервера

В реальных системах rate limiting часто реализуется на стороне тайл-сервера. При превышении лимитов сервер может возвращать:

  • 429 Too Many Requests
  • Retry-After header
  • временные ошибки 503

MapLibre GL JS не игнорирует такие ответы: они приводят к включению повторных попыток загрузки с увеличением задержки.

Типичная стратегия обработки:

  • фиксирование ошибки загрузки тайла
  • повтор через экспоненциальную задержку
  • исключение ресурса из активного рендера до повторной попытки

Экспоненциальное замедление повторных запросов

При повторных ошибках загрузки применяется backoff-модель:

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

Это предотвращает «шторм запросов» при деградации сервиса.

Модель можно представить как:

[ t_{retry} = t_{base} ^n]

где:

    1. — количество неудачных попыток
  • (t_{base}) — базовая задержка

t_{retry} = t_{base} ^n


Дебаунсинг пользовательских событий

Хотя MapLibre GL JS сам управляет рендерингом, прикладной код часто создаёт дополнительную нагрузку:

  • запросы к API при каждом move
  • фильтрация данных по bbox в реальном времени
  • синхронизация состояния UI

Для снижения нагрузки используется подавление частоты вызовов:

  • debounce для move и zoom
  • throttle для событий прокрутки
  • переход на moveend или idle

Пример типового паттерна:

map.on('moveend', () => {
  const center = map.getCenter();
  const zoom = map.getZoom();

  fetchData({ center, zoom });
});

Такой подход переносит вычисления с высокочастотных событий на финальное состояние камеры.


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

Векторные источники (vector sources) и растровые источники (raster sources) могут создавать тысячи запросов при перемещении карты. Контроль осуществляется через конфигурацию источника:

  • ограничение zoom-диапазона (minzoom, maxzoom)
  • уменьшение детализации тайлов
  • использование генерализованных данных

Пример настройки:

map.addSource('tiles', {
  type: 'vector',
  tiles: [
    'https://tiles.example.com/{z}/{x}/{y}.pbf'
  ],
  minzoom: 5,
  maxzoom: 14
});

Чем уже диапазон zoom, тем меньше потенциальных запросов при интерактивной навигации.


Кэширование как форма снижения нагрузки

MapLibre GL JS активно использует кэш:

  • tile cache (в памяти)
  • glyph cache
  • sprite cache

Повторное посещение области карты не приводит к повторным запросам, если ресурс ещё находится в кэше.

Кэш снижает нагрузку в двух ключевых сценариях:

  • возврат к ранее просмотренной области
  • плавное панорамирование внутри одного региона

Однако кэш ограничен по размеру и может вытесняться LRU-алгоритмом.


Ограничение параллельных загрузок

Для предотвращения перегрузки браузера используется контроль количества одновременных загрузок ресурсов. Это особенно важно для:

  • мобильных устройств
  • слабых CPU
  • медленных сетей

Типичные ограничения:

  • число параллельных tile requests
  • число image requests
  • очередь загрузки glyphs

При превышении лимитов новые запросы ставятся в очередь, а не отправляются немедленно.


AbortController и отмена устаревших запросов

При каждом изменении состояния карты часть запросов становится неактуальной. MapLibre GL JS использует отмену запросов через механизм AbortController (или аналогичные внутренние механизмы).

Это позволяет:

  • отменять тайлы вне viewport
  • прекращать загрузку при быстром zoom transition
  • освобождать сетевые ресурсы

Отмена запроса не равна ошибке — это нормальный процесс оптимизации.


Приоритизация тайлов

Система загрузки тайлов использует приоритеты:

  • центр экрана имеет максимальный приоритет
  • периферийные области — сниженный
  • тайлы вне viewport — низший или нулевой приоритет

Приоритет влияет на порядок выполнения очереди запросов, что снижает визуальные артефакты и улучшает perceived performance.


Серверные стратегии снижения нагрузки

На стороне тайл-сервера применяются дополнительные методы контроля:

  • CDN кэширование тайлов
  • агрегация запросов
  • генерация предварительно подготовленных тайлов
  • ограничение RPS (requests per second)
  • географическое распределение нагрузки

Векторные тайлы особенно чувствительны к rate limiting из-за высокой плотности запросов при зуме.


Поведение при перегрузке сети

При деградации сети или сервера наблюдается каскад эффектов:

  • рост задержек загрузки тайлов
  • увеличение числа retry попыток
  • временные пустые зоны на карте
  • снижение FPS из-за ожидания данных

MapLibre GL JS минимизирует визуальные сбои за счёт:

  • рендеринга кешированных тайлов
  • постепенного заполнения пустых областей
  • асинхронного обновления слоёв

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

Ключевая задача rate limiting в MapLibre GL JS — поддержание баланса:

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

Эффективная конфигурация достигается сочетанием:

  • ограничения параллельных запросов
  • правильной архитектуры источников данных
  • кэширования
  • оптимизации событий UI
  • серверного throttling и CDN

Каждый из этих уровней снижает вероятность перегрузки и обеспечивает стабильный рендеринг карты при интенсивной интерактивности.