Recently I’ve been experimenting with TileStache tiles caching system, which is similar to TileCache and other tile caching systems in scope. TileStache revealed itself as a powerful and flexible product and was very good to cache tiles generated with my Django-backed mapscript-powered WMS server. Caching and serving tiles with TileStache was by far faster then running the whole mapscript WMS machinery. But I wanted to do more: if I could just convince nginx to serve the tiles directly from disk, this would have been even faster. Of course for this to work, TileStache must be configured to cache tiles on disk, which is what you normally want. nginx is really good at serving static files and it is luckily wery flexible and easy to configure (once you know what to do). The following configuration uses named regular expression captures and a try_files instruction to check for the tile existance, if found, the tile is served directly, if not found the internal redirect to the @django named location takes place. The 404 trick in the base location (/) was necessary to avoid duplication of the @django location content, but there might be a better way.

nginx configuration file

server {
    listen   88 default;
    server_name  localhost;
    access_log  /var/log/nginx/access.log;
    rewrite  "^/[a-z]{2}/(static|media)/(.*)$"  /$1/$2;
    root /www/django_app/;

    location  /media/ {
        alias /www/django/contrib/admin/media/;
    }

    location  /static/ {
        alias /www/django_app/site_media/;
    }

    location ~ ^/(?<lang_code>..)/resource/tiles/1\.0\.0/(?<tile_path>.*)$ {
        alias /tmp/stache/;
        add_header X-Static super;
        try_files $http_host/$lang_code/$tile_path @django;
    }
        
    location / {
        add_header X-Static hit;
        error_page 404 = @django;
        return 404;
    }
        
    location @django {
        add_header X-Static miss;
        uwsgi_pass unix:///run/uwsgi/app/xxx/socket;
    }

    
}

Results

I run the test on the production environment and these are the result:

Using TileStache

uwsgi serves the tiles through TileStache.

$ ab -c 100 -n 1000 http://www.xxx.it/it/resource/tilestache/1.0.0/track_2/11/1076/735.png
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.xxx.it (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.1.19
Server Hostname:        www.xxx.it
Server Port:            80

Document Path:          /it/resource/tilestache/1.0.0/track_2/11/1076/735.png
Document Length:        16915 bytes

Concurrency Level:      100
Time taken for tests:   5.680 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      17296896 bytes
HTML transferred:       16915000 bytes
Requests per second:    176.05 [#/sec] (mean)
Time per request:       568.019 [ms] (mean)
Time per request:       5.680 [ms] (mean, across all concurrent requests)
Transfer rate:          2973.76 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   3.5      0      14
Processing:   130  541 108.2    508     816
Waiting:      130  540 108.1    508     816
Total:        143  542 107.5    508     816

Percentage of the requests served within a certain time (ms)
  50%    508
  66%    562
  75%    599
  80%    627
  90%    716
  95%    751
  98%    787
  99%    803
 100%    816 (longest request)

Direct serving by nginx

$ ab -c 100 -n 1000 http://www.xxx.it/it/resource/tiles/1.0.0/track_2/11/1076/735.png
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.xxx.it (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.1.19
Server Hostname:        www.xxx.it
Server Port:            80

Document Path:          /it/resource/tiles/1.0.0/track_2/11/1076/735.png
Document Length:        16915 bytes

Concurrency Level:      100
Time taken for tests:   0.233 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      17256000 bytes
HTML transferred:       16915000 bytes
Requests per second:    4300.28 [#/sec] (mean)
Time per request:       23.254 [ms] (mean)
Time per request:       0.233 [ms] (mean, across all concurrent requests)
Transfer rate:          72466.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    6   3.3      6      14
Processing:     5   16   4.2     16      25
Waiting:        1    8   4.4      7      20
Total:         11   22   3.6     22      35

Percentage of the requests served within a certain time (ms)
  50%     22
  66%     24
  75%     25
  80%     26
  90%     26
  95%     28
  98%     30
  99%     33
 100%     35 (longest request)

Conclusions

Unsurprisingly, the solution with files served directly is several times faster: 24 in this test case.

3 Responses to “Serving your map tiles 30 times faster”