Gopnik: тайловый бэкенд Карт sputnik.ru

Gopnik: тайловый бэкенд Карт sputnik.ru

610

Мы, команда Карт «Спутника» , разрабатываем карты на базе данных «OpenStreetMap». В данной заметке мы поведаем о архитектуре нашего решения для рендеринга тайлов.

Бэкенд карт написан на языке Go с внедрением библиотеки Mapnik, потому – Gopnik 🙂
Исходники Gopnik доступны на Github.

Архитектура сервиса openstreetmap.org содержит множество компонентов.
Пренебрегая деталями, можно выделить три главных части: базу данных PostgreSQL, API для загрузки и редактирования данных и система рендеринга карт.

Для того, чтоб сделать свою карту на базе данных OSM, будет нужно поддерживать свою копию базы данных и систему рендеринга.
Тайл — маленькое квадратное изображение с участком карты. Коснемся неких общих вопросцев сотворения on-line карт. Большей популярностью на данный момент пользуются тайловые карты. Клиент загружает тайлы с сервера и потом склеивает их в единое изображение. На текущий момент существует несколько технологий отображения: от варианта, когда сервер дает клиенту готовую картину, до варианта визуализации загруженных данных на стороне клиента.
Эта разработка проста в реализации, мало загружает клиентскую сторону. Естественно, не лишена она и недочетов, но как мне кажется, внедрение таковой технологии будет оправдано на протяжении еще долгого времени.

В мире OpenStreetMap стек тайловых карт держится на 3-х китах:
базе данных (почаще всего PostgreSQL);
библиотеке рендеринга (традиционно Mapnik);
клиентская javascript-библиотека (в большинстве случаев — Leaflet).
Чтоб соединить эти технологии воедино, будет нужно еще ряд вещей: дополнить, по необходимости, данные, добавить иконки, обрисовать стиль рисования, настроить генерацию и кэширование тайлов.
Разрабатывая собственный стиль мы желали достигнуть сразу полноты данных и легкости восприятия. Стиль оказался приблизительно в два раза наиболее сложным и тяжеловесным, ежели стиль openstreetmap.org Платой за красоту стала техно сложность.

Как следствие, обновление тайлов занимает длительное время (около 5 дней), нужно кэшировать существенное количество данных (приблизительно 2Тб). Все это сильно осложняет жизнь.
Почаще всего стек рендеринга строится на базе HTTP-сервера Apache c плагином mod_tile и бекендом, конкретно занимающимся генерацией тайлов: Tirex либо Renderd.

Не считая того, схема балансировки renderd имеет определенные недостатки, применять ее в среде пары дата-центров проблемно. mod_tile разрабатывался с оглядкой на файловую систему, а сторадж с eventual consistency применять и совсем нереально без суровой доработки. Но нельзя огласить, что она нас на сто процентов устраивала. Эта схема проверена временем, конкретно так и работала 1-ая версия maps.sputinik.ru. Да и штатные утилиты особенным удобством не различаются. 1-ое, с чем мы столкнулись — проблематичность использования пасмурных хранилищ для тайлового кэша.
Макет прижился и получил предстоящее развитие. Мы провели опыт: набросали макет системы, которая делает ровно то, что мы от нее желали. По собственной сущности система, во многом, повторяет архитектуру mod_tile, с некими расширениями и дополнениями. Она написана на языке Go с внедрением библиотеки Mapnik, за что и получила свое заглавие — Gopnik.
Gopnik просто масштабируется по произвольному количеству узлов, может применять разные системы хранения данных, поддерживает расширение при помощи плагинов.

Gopnik состоит из 2-ух компонент: dispatcher и render. Dispatcher воспринимает запросы от юзера, инспектирует наличие тайлов в кэше, в случае необходимости выбирает пригодный узел в кластере по хэш-функции координат и ставит ему задачку на генерацию тайлов. Render обеспечивает конкретно рендеринг.

Gopnik группирует запросы от юзера по метатайлам, при первом запросе к несохраненному в кэше метатайлу, начинается рендеринг. Сервер же, для экономии ресурсов и для уменьшения заморочек со стыковкой отдельных картинок генерирует сходу огромную область карты (традиционно 8×8 тайлов + доп буфер), которая потом нарезается на кусочки. По завершении рендеринга ворачиваются тайлы для всех ожидающих запросов и начинается фоновое сохранения в кэш. Загвоздка в том, что юзеры запрашивают тайлы по одному. Отдельное внимание уделено дилемме взаимодействия с хранилищем. Все запросы, поступившие позже, присоединяются к ожиданию. Такую область именуют метатайлом. Не считая того, некое (настраиваемое) время результаты рендеринга хранятся в локальном кэше узла на вариант, раз клиент запросит остальные тайлы из лишь что сгенерированного метатайла, так же локальный кэш может держать данные до полного сохранения их в сторадж, раз крайний поддерживает доказательство сохранения.

Но на лету можно генерировать только те части карты, где количество данных ограничено. В других вариантах приходится подготавливать тайлы заблаговременно. Для этого в Gopnik’е существует особый набор утилит.
Prerender координирует процесс. При помощи утилиты importer подготавливается план генерации. Кластер узлов prerender slave конкретно выполняет рендеринг.

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

Исходники на Github
Документация
По мотивам доклада Максима Дементьева на Highload++ 2014 habrahabr.ru