Репликация сервиса снимков карты Strava

Я некоторое время использовал Strava для своих случайных пробежек, и кое-что, что всегда привлекало мое внимание, это основная лента приложения, где вы можете найти красивую картинку или снимок пути, пройденного вами или вашими друзьями. Сначала я подумал, что приложение загружает набор Geojsons и делает рендеринг для каждого из сообщений во время пробежки, но после работы с мобильными картами в своем собственном проекте я понял, что рендеринг карты — непростая задача для любого устройства. Затем я заметил, что каждый пост содержит изображение маршрута на карте, и эта лента не слишком отличается от любого поста в социальных сетях, тем не менее, мне все еще было любопытно, как мы можем генерировать эти изображения.

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

Сначала о главном: как сгенерировать снимок карты?

через GIPHY

Моим первым шагом была попытка визуализировать карту и сделать ее снимок. Порывшись в Интернете пару минут, я нашел отличную статью «Создание художественных карт с помощью Python», в которой автор учит нас, как с помощью Python создать высококачественную карту любого города.

Следуя руководству и проведя несколько тестов, я заметил, что сценарию требуется слишком много времени между получением информации с Open Street Maps и ее обработкой. Принимая во внимание количество одновременных запросов, которые должна получать Strava, я сказал себе, что должна быть альтернатива, которая потребляет меньше ресурсов, и тогда я нашел API statice Images от Mapbox.

У MapBox есть набор API, которые продаются как программное обеспечение как услуга, но они позволяют вам генерировать API-ключ разработчика и даже создавать свои собственные стили карт. Static Images API позволяет создать полностью настраиваемую карту. Вы задаете такие параметры, как координаты, размеры, географические объекты (точки, линии, полигоны и т.д.) и другие. В ответ вы получаете изображение с картой, которую вы просили.

Сервис работает довольно гладко, и после работы с ним я заметил, что даже Strava использует его (вы можете увидеть отметку MapBox в сноске каждой карты), что определенно является сигналом того, что вы идете в правильном направлении.

import requests


API_URL = "https://api.mapbox.com/styles/v1/{0}/static/{1}/auto/{2}x{3}?access_token={4}"

...
request_url = API_URL.format(
    style_id,           # Map Style Ex. 'mapbox/darkv11' 
    polyline_hash,      # Polyline is alghoritm for hashing list of coordinates.
    width, height,      # Dimenssions of the image 
    token               # Access token provided by MapBox
    )

response = requests.get(request_url)

if (response.status_code == 200):
    open('map.png', 'wb').write(response.content)

else:
    print(response.text)

...

Вход в полноэкранный режим Выход из полноэкранного режима

Перейдем к серьезному: создание сервиса

через GIPHY

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

Поскольку для этого будет использоваться вызов внешнего сервиса, я не мог рассчитывать на синхронное выполнение каждого HTTP-вызова, который будет получать наш сервис, и горизонт становится все темнее, когда вы думаете о возможностях сбоя, учитывая количество запросов и общие проблемы с сетями. Ответ был очевиден: я должен получить запрос, немедленно закрыть его и затем начать обработку карты в новом потоке или фоновом процессе, всегда принимая во внимание, что мы должны быть масштабируемыми. Исходя из этого и стратегии «разделяй и властвуй», я пришел к выводу, что для моего решения потребуются следующие компоненты:

  • Веб-сервер, который получает и проверяет запросы клиентов.
  • Менеджер очереди, который составляет список подтвержденных запросов.
  • Набор рабочих, которые считывают данные из менеджера очереди и выполняют обработку.

Для монтажа такой архитектуры я не мог представить себе более простого способа, чем использование подхода Docker Compose (или Docker + Kubernetes). В итоге у меня получилось дерево папок, как показано ниже.

├───service
│   ├───nginx
│   └───src
│       └───map_equests.py
│       └───main.py
│       └───Dokerfile
│       └───requirements.txt
├───worker
│   └───src
│       └───helpers
│       └───worker.py
│       └───Dokerfile
│       └───requirements.txt
│
├───docker-compose.yml
└───.env

Вход в полноэкранный режим Выход из полноэкранного режима

Выводы

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

Я опубликовал проект на своем аккаунте Github. Вы можете найти репозиторий здесь, чтобы погрузиться в код. Ниже я также приведу несколько ресурсов, которые могут помочь вам в случае, если вы работаете над чем-то подобным или просто ищете информацию об одной из этих технологий.

  • Создание художественных карт с помощью Python
  • Создание красивых карт с помощью Python
  • API статических изображений MapBox
  • Очередь из первых попавшихся
  • Формат алгоритма кодированной полилинии

Оцените статью
devanswers.ru
Добавить комментарий