...

пятница, 6 марта 2015 г.

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

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


Бэкенд карт написан на языке Go с использованием библиотеки Mapnik, поэтому – Gopnik :-)

Исходники Gopnik доступны на Github.



Архитектура сервиса openstreetmap.org содержит множество компонентов.

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



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

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

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


В мире OpenStreetMap стек тайловых карт держится на трех китах:

базе данных (чаще всего PostgreSQL);

библиотеке рендеринга (обычно Mapnik);

клиентская javascript-библиотека (в большинстве случаев — Leaflet).

Чтобы соединить эти технологии воедино, потребуется еще ряд вещей: дополнить, по необходимости, данные, добавить иконки, описать стиль рисования, настроить генерацию и кэширование тайлов.

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


Как следствие, обновление тайлов занимает продолжительное время (около 5 дней), необходимо кэшировать значительное количество данных (примерно 2Тб). Все это сильно осложняет жизнь.

Чаще всего стек рендеринга строится на основе HTTP-сервера Apache c плагином mod_tile и бекендом, непосредственно занимающимся генерацией тайлов: Tirex или Renderd.


mod_tile, renderd


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

Мы провели эксперимент: набросали прототип системы, которая делает ровно то, что мы от нее хотели. Прототип прижился и получил дальнейшее развитие. По своей сути система, во многом, повторяет архитектуру mod_tile, с некоторыми расширениями и дополнениями. Она написана на языке Go с использованием библиотеки Mapnik, за что и получила свое название — Gopnik.

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


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



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



Однако на лету можно генерировать лишь те части карты, где количество данных ограничено. В остальных случаях приходится подготавливать тайлы заранее. Для этого в Gopnik'е существует специальный набор утилит.

При помощи утилиты importer подготавливается план генерации. Prerender координирует процесс. Кластер узлов prerender slave непосредственно выполняет рендеринг.



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


Исходники на Github

Документация

По мотивам доклада Максима Дементьева на Highload++ 2014


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий