📜 ⬆️ ⬇️

How it works: the architecture of the tile backing of Sputnik maps

We, the satellite team of maps , are developing maps based on OpenStreetMap data. In this post we will talk about the architecture of our tile rendering solution.



The backend map is written in Go using the Mapnik library, so we gave it the name Gopnik. Gopnik sources are available on Github .

The openstreetmap.org service architecture contains many components.
')
Neglecting the details, there are three main parts: the PostgreSQL database, the API for loading and editing data, and the map rendering system.



In order to create your map based on OSM data, you will need to maintain your copy of the database and the rendering system.

Let us touch on some general issues of creating on-line maps. Currently, there are several display technologies: from the option when the server gives the client a ready-made picture, to the option of visualizing the downloaded data on the client side. The most popular at the moment are tile cards. Tile - a small square image with a section of the map. The client downloads the tiles from the server and then sticks them together into a single image.

This technology is easy to implement, minimally loads the client side. Of course, it is not without flaws, but it seems to me that the use of such technology will be justified for a long time.

In the world of OpenStreetMap, a stack of tile maps rests on three pillars:

database (most often PostgreSQL);
rendering library (usually Mapnik);
client javascript library (in most cases - Leaflet).

To put these technologies together, we need a number of other things: to add data, if necessary, to add icons, to describe a drawing style, to set up generation and caching of tiles.

In developing our style, we wanted to achieve both data completeness and ease of perception. The price for beauty was technical difficulty. The style turned out to be about twice as complex and heavy as the openstreetmap.org style.

As a result, updating tiles takes a long time (about 5 days), you need to cache a significant amount of data (approximately 2 TB). All this greatly complicates life.

Most often, the rendering stack is built on the basis of the Apache HTTP server with the mod_tile plugin and backend directly involved in generating tiles: Tirex or Renderd.



This scheme has been tested by time, and that is how the first version of maps.sputinik.ru worked. However, it cannot be said that she completely satisfied us. The first thing we are faced with is the difficulty of using cloud storage for the tile cache. mod_tile was developed with an eye to the file system, and stack with eventual consistency is completely impossible to use without serious improvement. In addition, the renderd balancing scheme has certain drawbacks; it is difficult to use it in a multi-data center environment. And regular utilities do not differ in special convenience.

We conducted an experiment: we sketched a prototype of a system that does exactly what we wanted from it. The prototype caught on and received further development. At its core, the system largely repeats the mod_tile architecture, with some extensions and additions. It is written in the Go language using the Mapnik library, for which it received its name - Gopnik.

Gopnik can be easily scaled by an arbitrary number of nodes, it can use various data storage systems, it supports expansion with the help of plug-ins.

Gopnik consists of two components: dispatcher and render. Dispatcher accepts requests from the user, checks for the presence of tiles in the cache, if necessary, selects the appropriate node in the cluster according to the hash function of the coordinates and sets the task for it to generate tiles. Render provides directly rendering.



Special attention is paid to the problem of interaction with the repository. The catch is that users request tiles one by one. The server, to save resources and to reduce problems with the docking of individual images, immediately generates a large area of ​​the map (usually 8x8 tiles + an additional buffer), which is then cut into pieces. This area is called metatail. Gopnik groups the requests from the user into metatails, the first time a query is sent to an unsaved metatail in the cache, the rendering starts. All requests received later join the pending. Upon completion of the rendering, tiles for all pending requests are returned and the background save to the cache begins. In addition, some (custom) time rendering results are stored in the local node cache in case the client requests other tiles from the newly generated meta file, the local cache can also hold the data until it is completely saved in the stack, if the latter supports saving confirmation.



However, on the fly, you can only generate parts of the map where the amount of data is limited. In other cases, you have to prepare the tiles in advance. For this, there is a special set of utilities in Gopnik.

Using the importer utility, a generation plan is prepared. Prerender coordinates the process. A cluster of nodes prerender slave directly performs rendering.



The system is distributed, resistant to network failures and failure of slave nodes. The single point of failure is the coordinator, however, thanks to the rendering logs, the process can be continued from the point of failure. This solution allows you to avoid complex fully distributed systems, while ensuring an adequate level of fault tolerance.

Sources on Github
Documentation
Based on the report of Maxim Dementiev on Highload ++ 2014

Source: https://habr.com/ru/post/252921/


All Articles