Pull to refresh

Создание карты всего мира на основе OpenStreetMap данных

Reading time 5 min
Views 18K

Предыстория


При разработке проекта для онлайн навигации (в будущем и оффлайн) возникла необходимость разработки собственных онлайн карт. Сервисы от Google, Bing и т.п. имеют ограничения в использовании их карт в коммерческих целях. Бесплатные же, типа OpenStreetMap, не удовлетворяли требования заказчика.
Стал вопрос о создании онлайн карты (тайлов карты) для всего мира. Стиль приближенный к Google и Skobbler. Данные на основе OpenStreetMap.


Ограничения


Как известно файловые системы имеют ограничения в количестве файлов и каталогов. Поэтому хранение каждого тайла (плитки карты) по отдельности упирается в эти ограничения. Например только для 14-го зума нужно 267 583 488 тайлов (~414).
Посмотреть максимальное количество файлов в Linux: df -i
Решение — хранить тайлы в базе данных.

Железо и ось


Сервер генерации и загрузки данных: Supermicro сервер. 24 ядра по 2GHz, 64Gb RAM, HDD 2.7Tb. С Ubuntu 13.04 на борту.
Сервер на котором используются результаты генерации намного скромнее: 8 ядер по 1.8GHz, 27Gb RAM, 130Gb SSD.

Установка и настройка


Отдельно останавливаться на установке не буду. Так как это хорошо описано в других статьях (см. ссылки ниже).
Установлено:
  • PostgreSQL 9.1
  • PostGIS
  • Mapnik
  • TileMill вместе с OSM Bright (для стилей по умолчанию)
  • Osm2pgsql
  • SQLite 3
  • Node.js
  • nginx


Разработка


Чтобы не изобретать велосипед обратились к открытым источникам. Наилучший вариант для хранения тайлов в базе данных формат MBTiles. Это простая SQLite база позволяющая хранить миллионы тайлов в единственном файле.
Для разработки и редактирования собственного стиля хорошо подходит редактор TileMill, к тому же он позволяет сохранять карты в формате MBTiles.
Для начала нужно загрузить отдельный участок (страну) и отработать стили. Желательно проработать несколько стран с разными алфавитами: латинский, кириллица, арабский, иероглифы. Так вы не столкнетесь с неприятным сюрпризом отсутствия некоторых названий или некорректного отображения стиля для разных стран. Загружать весь мир и отрабатывать стили не советую, так как время динамической генерации в редакторе очень увеличивается.

Загрузка данных в PostgreSQL

Тюнинг PostgreSQL

Для ускорения процеса загрузки проведем некоторые изменения в файле /etc/postgresql/9.1/main/postgresql.conf
max_connections = 150 — вычисляется опытным путем, зависит от количества процессоров. По умолчанию 100.
shared_buffers = 7GB — <25% оперативной памяти системы. Для этого параметра нужно увеличить kernel.shmmax.
temp_buffers = 512MB — используется для доступа ко временным таблицам, нужно для slim mode утилиты osm2pgsql.
work_mem = 3GB — используется для сортировки “ORDER BY” и объединения “JOIN”.
maintenance_work_mem = 16GB — используется для команд VACUUM, CREATE INDEX, ALTER TABLE ADD FOREIGN KEY.
random_page_cost = 3.0 — это настройки нагрузки процессоров. Будьте осторожны с этим параметром!
effective_cache_size = 42GB — до 66% оперативной памяти.
checkpoint_segments = 50
autovacuum = off

Загрузка с помощью osm2pgsql

Данные для загрузки берем на planet.osm.org.
Для загрузки данных в PostgreSQL использовалась утилита osm2pgsql. Для загрузки всего мира использовалась опция slim mode, она позволяет ограничить использование оперативной памяти, при этом создает временные таблицы для хранения промежуточных результатов.
Перед загрузкой подправим файл стилей, который в Ubuntu находиться в /usr/local/share/osm2pgsql/default.style. Для не латинских названий я добавил три поля: int_name (оригинал), name:en (название на английском), is_in:country (страна).
Команда для загрузки всего мира:
time sudo -u postgres osm2pgsql -r pbf -sc -d gis -C 40000 --number-processes 24 --cache-strategy dense --unlogged planet-latest.osm.pbf

Поясню отдельные параметры:
-r pbf — используется pbf формат;
-sc — режим slim mode (s) с созданием новых таблиц (c), для добавления используйте a;
--number-processes 24 — количество параллельных процессов, по количеству CPU-s;
--unlogged — не логировать транзакции.
Загрузка всего мира заняла 28 часов.

Создание собственных стилей в TileMill

Подготовка для не латинских названий

Как я писал выше для начала я загрузил в PostgreSQL несколько отдельных стран. Так как в мире используются много алфавитов нужно было обрабатывать и надписи написанные не на латинице (после оригинала в скобках указывать название на латинице). Для этого в таблице planet_osm_point создадим поле nonlatin:
ALTER TABLE planet_osm_point ADD COLUMN nonlatin boolean;
UPDATE planet_osm_point SET nonlatin='1' WHERE name similar to '%[^\x20-\x7e]+%';


Редактирование стилей

Для того чтобы иметь стили по умолчанию нужно установить OSM Bright для TileMill.
TileMill умеет работать с тремя источниками данных: файлы, SQLite, PostGIS. Для оформления стилей карты используется CartoCSS, если вы знакомы с CSS, то найдете много общего.
Будьте осторожны, некоторые фильтры (запросы до PostGIS PostgreSQL) из стилей OSM Bright довольно тяжелые и требуют много времени на выполнение. Поэтому нужно оптимизировать SQL-запросы для ускорения.
Выборка латинских и не латинских названий в запросах:
SELECT ..,
CASE WHEN nonlatin=true AND "name:en" IS NOT NULL THEN CONCAT("name:en",' (',name,')') ELSE name END as en_name
...


Генерация MBTiles

В TileMill выбираем Export/MBTiles. Указываем название файла, зумы (приближение карты), координаты центра и границы.
Границы всего мира: -180.0, -85, 180.0, 85
Для удобства генерировал карту отдельными зумами.
  • Зумы 0-10, общее время генерации 13 часов
  • Зум 11, общее время 7 часов
  • Зум 12, 18 часов
  • Зум 13, 3 дня
  • Зум 14, 9 дней

Зумы 15, 16, 17 решено оставить в динамической генерации. Для ускорения работы использовать кеширование.

Объединение отдельных MBTiles файлов

Для объединения отдельных файлов MBTiles можно использовать команду:
echo '.dump' | sqlite3 file1.mbtiles | sqlite3 file2.mbtiles

Результат будет в файле file2.mbtiles.

Использование

Запуск MBTiles

Для запуска MBTiles используем Node.js:
nohup node /usr/share/tileserver/mbtiles-server/server.js /media/data/mbtiles/filename.mbtiles PORTNUMBER &

Где PORTNUMBER номер порта по которому будут доступны плитки (тайлы) карты.

Файл конфигурации NGINX

Для доступа к карте используем nginx.
Пример файла конфигурации:
server {
        listen  80;
        server_name  your_server_map_tiles_name.com;
        
        #dinamically generation
        location ^~ /15/ {
            rewrite ^/15/(.*)$ http://localhost:20008/tile/projectName/15/$1 last;
        }
...
        #using MBTiles via runned port
        location / {
                proxy_pass       http://localhost:PORTNUMBER;
                proxy_set_header Host      $host;
                proxy_set_header X-Real-IP $remote_addr;
        }
}

Таким образом по адресу your_server_map_tiles_name.com/zoom/x/y.png будет доступна плитка вашей карты.

Особенности и пожелания


Лучше всего файл MBTiles размещать на диске SSD для ускорения загрузки.
Для iPhone приложения используются нестандартные Retina тайлы, размером 512х512 пикселей.
Для уменьшения нагрузки для динамической генерации (зумы 15-17) используется кеширование в Redis.

Результат


Результат можно увидеть здесь: tourstart.org/drive
Или скачать приложение для iPhone: itunes.apple.com/app/tourstart/id586049610?mt=8

Статьи использованные в процессе работы


habrahabr.ru/post/144675
switch2osm.org/serving-tiles/manually-building-a-tile-server-12-04
wiki.openstreetmap.org/wiki/Osm2pgsql
github.com/mapbox/mbtiles-spec
www.mapbox.com/tilemill/docs/linux-install
www.mapbox.com/tilemill/docs/guides/osm-bright-mac-quickstart
www.mapbox.com/carto/api/2.1.0

Извините. Для размещения в хабе OpenStreetMap недостаточно кармы.
Буду рад ответить на интересующие вас вопросы.
Tags:
Hubs:
0
Comments 5
Comments Comments 5

Articles