Ствараем і аптымізуем свой tile-сервер для OpenStreetMap на аснове Ubuntu 14.04
- ўстаноўка OpenStreetMap
- Настройка PostgreSQL і Mapnik
- Настройка Apache
- імпарт карты
- Праверка працаздольнасці карты
- Настройка nginx
- Аптымізуем OpenStreetMap (PostGIS)
Сёння я распавяду як даволі проста падняць і наладзіць свой уласны сервер карт (тайловый сервер) на аснове Ubuntu Server 14.04 LTS і OpenStreetMap.
Такім чынам пачнем. з Вікіпедыі :
OpenStreetMap (даслоўна «адкрытая карта вуліц"), скарочана OSM - некамерцыйны вэб-картаграфічны праект па стварэнні сіламі супольнасці удзельнікаў-карыстальнікаў Інтэрнэту падрабязнай свабоднай і бясплатнай геаграфічнай карты свету.
Ёсць даволі падрабязная афіцыйная артыкул аб усталёўцы і наладзе tile-сервера , Але ёсць яшчэ больш просты і хуткі спосаб.
ўстаноўка OpenStreetMap
ставім
sudo apt-get install python-software-propertiesдадаем рэпазітар
sudo add-apt-repository ppa: kakrueger / openstreetmapабнаўляюць
sudo apt-get updateСтавім адзіны пакет, што пацягне за сабой усё неабходнае для працы паўнавартаснага сервера карт.
sudo apt-get install libapache2-mod-tileПа ходзе інсталяцыі (openstreetmap-postgis-db-setup) вам будзе зададзена некалькі пытанняў:
This will enable the apache config for mod_tile WARNING : This will disable the currently active default site config Do you want to enable mod_tile in the apache config ?
адказваем Yes
This script downloads the necessary coastline and boundary data . WARNING: The data is about 400 - 500Mb in size. Do you want to download coastlines?
адказваем Yes
Do you want these scripts to create and setup a new postgis database ready to be used with eg Osm2pgsql . WARNING: This will delete an existing db. Do you want to create a postgis db?
адказваем Yes
If you do not use the default name, you might need to adapt programs and scripts to use the new name . Name of the database to create:
паказваем gis
Please specify which users should have access to the newly created db . You will want the user www-data for rendering and your own user name to import data into the db . The list of users is blank separated: Eg «www-data peter». Other users that should have access to the db :
Паказваем www-data
Ўстаноўлена.
Настройка PostgreSQL і Mapnik
Спачатку пра самую Mapnik :
Mapnik - гэта праграма, якую мы выкарыстоўваем для адмалёўкі асноўнага Slippy Map пласта для OSM, разам з іншымі пластамі накшталт «cycle map» і «noname». Таксама, гэтае імя, дадзенае асноўнаму пласту, што ўводзіць некаторых у зман.
Mapnik - вольны інструментар адмалёўкі карты. Ён напісаны на C ++ і Python. Выкарыстоўвае бібліятэку AGG і дае магчымасць згладжваць аб'екты на карце з вялікай дакладнасцю. Можа чытаць дадзеныя ў фармаце кампаніі ESRI, PostGIS, кропкавыя малюнкі TIFF, файлы .osm, а таксама падтрымлівае любыя GDAL або OGR фарматы. Пакеты даступныя для большасці выпускаў Linux, двайковыя файлы даступныя для Mac OS X і Windows.
Даволі дзіўны нюанс у тым, што нам не прапанавалі задаць пароль для доступу карыстальніка gis (ствараецца аўтаматычна) да аднайменнай БД.
Усталёўваем пароль для карыстальніка gis
su postgres -c "psql -d gis" gis = # \ password gis Цяпер неабходна ўказаць карыстальніка і пароль у файле конфігу mapnik.
Зробім гэта простым спосабам - заменай з дапамогай утыліты rpl:
Дзе «1234567890» - гэта пароль, што мы паказалі для карыстальніка gis
Даём магчымасць падлучацца з лакальнага сервера, выкарыстоўваючы конфіг /etc/postgresql/9.3/main/pg_hba.conf
Дадаем у яго радок
Наладжвальны PostgreSQL (адносна характарыстык сервера: 16 ядраў, 16GB RAM, БД на HDD).
/etc/postgresql/9.3/main/postgresql.confПаказваю толькі тое, што мяняў:
listen_addresses = '*' max_connections = 200 shared_buffers = 12GB work_mem = 2GB maintenance_work_mem = 8GB synchronous_commit = off # толькі для імпарту, потым неабходна прыбраць! fsync = off # толькі для імпарту, потым неабходна прыбраць! wal_buffers = 16MB checkpoint_segments = 1024 checkpoint_completion_target = 0.9 random_page_cost = 2.0 cpu_tuple_cost = 0.001 cpu_index_tuple_cost = 0.0005 effective_cache_size = 14GB autovacuum = off # толькі для імпарту, потым неабходна прыбраць!І перазапускаем Постгрес для прымянення ўсіх налад
service postgresql restartПотюним трохі конфіг дэмана renderd рендерера тайлов (Mapnik rendering daemon) і павялічым колькасць патокаў renderd да колькасці ядраў (у маім выпадкі - 16)
vi /etc/renderd.conf [renderd] num_threads = 16Зараз неабходна перазапусціць дэман renderd рендерер тайлов (Mapnik rendering daemon)
service renderd restartНастройка Apache
Сервер карт будзе працаваць на звязку Apache + PostgreSQL.
Я не ў захапленні ад гэтай звязкі. Пасля асноўных дзеянняў мы яшчэ даставім nginx для больш хуткай працы ў звязку nginx + Apache + PostgreSQL.
Наладжвальны Apache.
Назвы сервера для прыкладу будзе osm.net.
Звярніце ўвагу што порт я ўказаў 8080.
Правыя порт у /etc/apache2/ports.conf на 8080
Listen 8080Дапісваем ў /etc/apache2/apache2.conf назва нашага сервера, бо Апач без гэтага працаваць не можа.
echo "ServerName osm.net" >> /etc/apache2/apache2.confПеразапускаем.
service apache2 restartімпарт карты
Спампоўваем з праекта Geofabrik , Для прыкладу, карту Украіны ў фармаце .pbf і ўліваем яго ў нашу БД.
mkdir / var / osm wget -O /var/osm/ukraine.`date +% Y-% m-% d`.osm.pbf \ https://download.geofabrik.de/europe/ukraine-latest.osm. pbf osm2pgsql -d gis -U gis -W -c --slim -C 4000 --number-processes 16 \ /var/osm/ukraine.`date +% Y-% m-% d`.osm.pbf На віртуальнай машыне з 16 ядрамі, 16GB АЗП і HDD RAID-10 масівам гэта займае каля 30 хвілін.
На хуткасць імпарту даволі моцна ўплывае дыск. На SSD ўліваецца прыкметна хутчэй.
Звярніце ўвагу на параметр -c (--create) пры імпарце праз osm2pgsql. З гэтым параметрам выдаліцца ўся існуючая інфармацыя з табліц. Калі вам неабходна зрабіць імпарт яшчэ некалькіх краін, то замест -c указвайце параметр -a (--append).
Пасля таго як зробіце імпарт усіх неабходных краін (ці ўсяго свету) не забудзьцеся вярнуць у default з конфігу PostgreSQL /etc/postgresql/9.3/main/postgresql.conf параметры synchronous_commit, fsync і autovacuum.
Праверка працаздольнасці карты
Бягучая камплектацыя пастаўляецца прыкладам /var/www/osm/slippymap.html
Я прапаную праверыць на дадзеным этапе правільнасць налады PostgreSQL + Apache (mod_tile) + Mapnik, перад тым, як мы пяройдзем да налады nginx.
Адкрываем ў браўзэры https://osm.net:8080/osm/slippymap.html
Павінен адлюструецца просты інтэрфейс і карта. Важна каб быў абраны пункт у інтэрфейсе «Local Tiles».
Калі позумить і поскроллить, то карта будзе перамалёваць, паступова подгружая розныя Тайле.
Вось напрыклад, адрас Тайле цэнтра горада Кіева будзе выгдядеть так: https://osm.net:8080/osm/11/1197/690.png
І калі вы ўбачылі карцінку - значыць усё зрабілі правільна.
Кэш отрендеренные тайлов будзе складвацца ў тэчку / var / lib / mod_tile / default /.
І тут як-раз настаў час аддаваць гэты кэш ня праз павольнага монстра Apache, а праз хуткі nginx.
Настройка nginx
ставім
apt-get install nginx-light cat /etc/nginx/nginx.conf user www-data www-data; worker_processes 32; worker_priority -20; pid /var/run/nginx.pid; error_log /var/log/nginx/error.log warn; events {worker_connections 1024; accept_mutex on; multi_accept on; } Http {include /etc/nginx/mime.types; default_type application / octet-stream; reset_timedout_connection on; server_tokens off; log_format main '$ remote_addr - [$ time_local]' '$ host {$ upstream_cache_status} "$ request" $ status $ bytes_sent' ' "$ http_referer" "$ http_user_agent"' ' "$ gzip_ratio" $ upstream_response_time'; log_format ip_only '$ remote_addr'; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; client_header_buffer_size 16m; client_max_body_size 512m; server_names_hash_max_size 4096; server_names_hash_bucket_size 512; variables_hash_max_size 4096; variables_hash_bucket_size 512; types_hash_max_size 8192; port_in_redirect off; gzip on; gzip_vary on; gzip_min_length 1024; gzip_buffers 16 8k; gzip_comp_level 5; gzip_http_version 1.0; gzip_proxied any; gzip_disable "msie6"; gzip_types text / plain text / css application / x-javascript text / xml application / xml application / xml + rss text / javascript text / json; fastcgi_temp_path / var / cache / nginx / temp / fastcgi; proxy_temp_path / var / cache / nginx / temp / proxy; charset utf-8; index index.html index.htm; access_log off; error_log / dev / null; include /etc/nginx/conf.d/upstream.conf; include / etc / nginx / sites-enabled / *; } Cat /etc/nginx/conf.d/upstream.conf upstream apache {server 127.0.0.1:8080; } Cat / etc / nginx / sites-enabled / 001-osm server {listen 80; server_name osm.net; access_log /var/log/nginx/osm.net.access.log main; error_log /var/log/nginx/osm.net.error.log; root / var / www; index index.html; charset utf-8; # OSM location ~ * ^ / osm / ([0-9] +) / ([0-9] +) / ([0-9] +) \. Png $ {proxy_pass https: // apache; include / etc / nginx / proxy_params; access_log off; autoindex off; expires 1d; add_header Cache-Control 'public'; } # Static resources location ~ * ^. + \. (Ico | htm | html | txt | jpg | jpeg | css | js | png | gif | map | woff | woff2 | ttf | tif | tiff | pdf) $ {access_log off; autoindex off; expires 1d; add_header Cache-Control 'public'; }}перазапускаем
service nginx restartАптымізуем OpenStreetMap (PostGIS)
(на аснове артыкула PostGIS Tuning )
CREATE INDEX idx_poly_idlanduse ON planet_osm_polygon USING gist (way) WHERE ((landuse IS NOT NULL) OR (leisure IS NOT NULL) OR (aeroway = ANY ( '{apron, aerodrome}' :: text [])) OR (amenity = ANY ( '{parking, university, college, school, hospital, kindergarten, grave_yard}' :: text [])) OR (military = ANY ( '{barracks, danger_area}' :: text [])) OR ( "natural" = ANY ( '{field, beach, desert, heath, mud, grassland, wood, sand, scrub}' :: text [])) OR (power = ANY ( '{station, sub_station, generator}' :: text [ ])) OR (tourism = ANY ( '{attraction, camp_site, caravan_site, picnic_site, zoo}' :: text [])) OR (highway = ANY ( '{services, rest_area}' :: text []))) ; CREATE INDEX "planet_osm_polygon_nobuilding_index" ON "planet_osm_polygon" USING gist ( "way") WHERE "building" IS NULL; CREATE INDEX ferry_idx ON planet_osm_line USING gist (way) WHERE (route = 'ferry' :: text); CREATE INDEX "idx_poly_aeroway" on planet_osm_polygon USING gist (way) WHERE "aeroway" IS NOT NULL; CREATE INDEX "idx_poly_aeroway" on planet_osm_polygon USING gist (way) WHERE "aeroway" IS NOT NULL; CREATE INDEX "idx_poly_historic" on planet_osm_polygon USING gist (way) WHERE "historic" IS NOT NULL; CREATE INDEX "idx_poly_leisure" on planet_osm_polygon USING gist (way) WHERE "leisure" IS NOT NULL; CREATE INDEX "idx_poly_man_made" on planet_osm_polygon USING gist (way) WHERE "man_made" IS NOT NULL; CREATE INDEX "idx_poly_military" on planet_osm_polygon USING gist (way) WHERE "military" IS NOT NULL; CREATE INDEX "idx_poly_power" on planet_osm_polygon USING gist (way) WHERE "power" IS NOT NULL; CREATE INDEX "idx_poly_landuse" on planet_osm_polygon USING gist (way) WHERE "landuse" IS NOT NULL; CREATE INDEX "idx_poly_amenity" on planet_osm_polygon USING gist (way) WHERE "amenity" IS NOT NULL; CREATE INDEX "idx_poly_natural" on planet_osm_polygon USING gist (way) WHERE "natural" IS NOT NULL; CREATE INDEX "idx_poly_highway" on planet_osm_polygon USING gist (way) WHERE "highway" IS NOT NULL; CREATE INDEX "idx_poly_tourism" on planet_osm_polygon USING gist (way) WHERE "tourism" IS NOT NULL; CREATE INDEX "idx_poly_building" on planet_osm_polygon USING gist (way) WHERE "building" IS NOT NULL; CREATE INDEX "idx_poly_barrier" on planet_osm_polygon USING gist (way) WHERE "barrier" IS NOT NULL; CREATE INDEX "idx_poly_railway" on planet_osm_polygon USING gist (way) WHERE "railway" IS NOT NULL; CREATE INDEX "idx_poly_aerialway" on planet_osm_polygon USING gist (way) WHERE "aerialway" IS NOT NULL; CREATE INDEX "idx_poly_power_source" on planet_osm_polygon USING gist (way) WHERE "power_source" IS NOT NULL; CREATE INDEX "idx_poly_generator: source" on planet_osm_polygon USING gist (way) WHERE "generator: source" IS NOT NULL; CREATE INDEX "idx_line_aerialway" on planet_osm_line USING gist (way) WHERE "aerialway" IS NOT NULL; CREATE INDEX "idx_line_waterway" on planet_osm_line USING gist (way) WHERE "waterway" IS NOT NULL; CREATE INDEX "idx_line_bridge" on planet_osm_line USING gist (way) WHERE "bridge" IS NOT NULL; CREATE INDEX "idx_line_tunnel" on planet_osm_line USING gist (way) WHERE "tunnel" IS NOT NULL; CREATE INDEX "idx_line_access" on planet_osm_line USING gist (way) WHERE "access" IS NOT NULL; CREATE INDEX "idx_line_railway" on planet_osm_line USING gist (way) WHERE "railway" IS NOT NULL; CREATE INDEX "idx_line_power" on planet_osm_line USING gist (way) WHERE "power" IS NOT NULL; CREATE INDEX "idx_line_name" on planet_osm_line USING gist (way) WHERE "name" IS NOT NULL; CREATE INDEX "idx_line_ref" on planet_osm_line USING gist (way) WHERE "ref" IS NOT NULL; CREATE INDEX "idx_point_aerialway" on planet_osm_point USING gist (way) WHERE "aerialway" IS NOT NULL; CREATE INDEX "idx_point_power_source" on planet_osm_point USING gist (way) WHERE "power_source" IS NOT NULL; CREATE INDEX "idx_point_shop" on planet_osm_point USING gist (way) WHERE "shop" IS NOT NULL; CREATE INDEX "idx_point_place" on planet_osm_point USING gist (way) WHERE "place" IS NOT NULL; CREATE INDEX "idx_point_barrier" on planet_osm_point USING gist (way) WHERE "barrier" IS NOT NULL; CREATE INDEX "idx_point_railway" on planet_osm_point USING gist (way) WHERE "railway" IS NOT NULL; CREATE INDEX "idx_point_amenity" on planet_osm_point USING gist (way) WHERE "amenity" IS NOT NULL; CREATE INDEX "idx_point_natural" on planet_osm_point USING gist (way) WHERE "natural" IS NOT NULL; CREATE INDEX "idx_point_highway" on planet_osm_point USING gist (way) WHERE "highway" IS NOT NULL; CREATE INDEX "idx_point_tourism" on planet_osm_point USING gist (way) WHERE "tourism" IS NOT NULL; CREATE INDEX "idx_point_power" on planet_osm_point USING gist (way) WHERE "power" IS NOT NULL; CREATE INDEX "idx_point_aeroway" on planet_osm_point USING gist (way) WHERE "aeroway" IS NOT NULL; CREATE INDEX "idx_point_historic" on planet_osm_point USING gist (way) WHERE "historic" IS NOT NULL; CREATE INDEX "idx_point_leisure" on planet_osm_point USING gist (way) WHERE "leisure" IS NOT NULL; CREATE INDEX "idx_point_man_made" on planet_osm_point USING gist (way) WHERE "man_made" IS NOT NULL; CREATE INDEX "idx_point_waterway" on planet_osm_point USING gist (way) WHERE "waterway" IS NOT NULL; CREATE INDEX "idx_point_generator: source" on planet_osm_point USING gist (way) WHERE "generator: source" IS NOT NULL; CREATE INDEX "idx_point_capital" on planet_osm_point USING gist (way) WHERE "capital" IS NOT NULL; CREATE INDEX "idx_point_lock" on planet_osm_point USING gist (way) WHERE "lock" IS NOT NULL; CREATE INDEX "idx_point_landuse" on planet_osm_point USING gist (way) WHERE "landuse" IS NOT NULL; CREATE INDEX "idx_point_military" on planet_osm_point USING gist (way) WHERE "military" IS NOT NULL; CREATE INDEX idx_poly_wayarea_text ON planet_osm_polygon USING gist (way) WHERE name IS NOT NULL AND place IS NULL AND way_areaЗахаваем гэтыя запыты ў файл /var/osm/osm.indexes.sql і выканаем іх su postgres -з "psql -d gis -U gis -W" gis => \ i /var/osm/osm.indexes.sql
Разагрэў кэша Mapnik
Для часта выкарыстоўваюцца тайлов ёсць сэнс "разагрэць" кэш Mapnik.
Для гэтага ёсць вельмі простая каманда: cd / var / lib / mod_tile render_list -m default -a -z 0 -Z 10 -n 16
дзе
-z 0 - пачатковы зум (ад)
-Z 10 - канчатковы зум (да)
-n 16 - колькасць ядраў
Усё той жа прыклад з картай Украіны для 16 ядраў і з зумам ад 0 да 10 займае каля 20 хвілін.
Гэта ўсё.
Ўдачы.
Чытайце таксама:
Do you want to download coastlines?Do you want to create a postgis db?