Tile caching con TileCache vs MapProxy

  • Categoría de la entrada:Discord Exclusivo
  • Tiempo de lectura:15 minutos de lectura

Cuando trabajas con mapas web, una de las primeras optimizaciones que debes implementar es el cacheo de tiles. Si tu mapa recibe más de 100 visitas diarias, estás desperdiciando recursos del servidor y dando una experiencia lenta al usuario.

Hoy comparamos las dos soluciones más usadas para cachear tiles: TileCache y MapProxy. Con números reales y configuraciones listas para copiar y pegar.

¿Qué es el tile caching?

Cuando un usuario ve tu mapa, el navegador solicita cientos de imágenes pequeñas (llamadas tiles) que se ensamblan para formar el mapa completo.

Sin caché:

  1. Usuario solicita tile -> GeoServer procesa datos -> Genera imagen -> Envía tile.
  2. Tiempo: 200-500ms aproximado por tile.
  3. CPU: Alto consumo.
  4. Otro usuario pide el mismo tile: Se repite todo el proceso.

Con caché:

  1. Usuario solicita tile -> MapProxy verifica caché -> Si existe, lo envía.
  2. Tiempo: 5-20ms aproximado por tile.
  3. CPU: Mínimo.
  4. Otro usuario: Recibe el mismo tile cacheado instantáneamente.

TileCache vs MapProxy: Comparemos

TileCache

Que es lo bueno:

  • Configuración simple (archivo .cfg de 10 líneas).
  • Ligero en recursos.
  • Perfecto para proyectos pequeños.

Que es lo malo:

  • Sin desarrollo activo desde 2014.
  • Usa Python 2.
  • No soporta reproyección al vuelo.
  • Formatos limitados, solo soporta PNG, JPEG.
  • Sin interfaz de administración.

MapProxy

Que es lo bueno:

  • Desarrollo activo. Ultima versión del 2024.
  • Python 3.
  • Reproyección automática entre sistemas de coordenadas.
  • Múltiples formatos (PNG, JPEG, WebP, GeoTIFF).
  • Interfaz web de administración.
  • Puede funcionar como proxy WMS/WMTS.
  • Seeding inteligente (precacheo selectivo).
  • Caché en disco, SQLite, MBTiles, S3, Redis.

Que es lo malo:

  • Configuración más compleja
  • Consume más recursos aunque sigue siendo ligero.

Comparación de velocidad: Números reales

Prueba realizada con GeoServer sirviendo capa vectorial de barrios de Cali (10,000 polígonos):

Sin caché usando GeoServer directo

Zoom 10: 450ms por tile
Zoom 14: 720ms por tile
Zoom 16: 1200ms por tile
CPU: 85-95%

Con TileCache

Primera solicitud (cache miss): 480ms
Solicitudes posteriores: 8-15ms
CPU: 5-10%
Reducción: 97% en tiempo

Con MapProxy

Primera solicitud (cache miss): 420ms
Solicitudes posteriores: 5-12ms
CPU: 3-8%
Reducción: 98% en tiempo
Bonus: Reproyección EPSG:4326 a EPSG:3857 sin costo extra

Ganador: MapProxy.


Instalación de MapProxy

En Ubuntu/Debian:

en terminal de comandos

# Instalar dependencias
sudo apt update
sudo apt install python3-pip python3-pil python3-yaml libgeos-dev

# Instalar MapProxy
pip3 install MapProxy

# Verificar instalación
mapproxy-util --version

En Docker (es mejor para producción):

en terminal de comandos

docker pull mapproxy/mapproxy:latest

docker run -d \
  --name mapproxy \
  -p 8080:8080 \
  -v $(pwd)/mapproxy:/mapproxy \
  mapproxy/mapproxy

Configuración básica de MapProxy

Crea el archivo mapproxy.yaml:

Tu archivo yaml

services:
  demo:
  tms:
    use_grid_names: true
  kml:
    use_grid_names: true
  wmts:
  wms:
    srs: ['EPSG:4326', 'EPSG:3857', 'EPSG:3116']
    image_formats: ['image/png', 'image/jpeg', 'image/webp']

layers:
  - name: barrios_cali
    title: Barrios de Cali
    sources: [barrios_cache]

caches:
  barrios_cache:
    grids: [webmercator, geograficas]
    sources: [barrios_wms]
    cache:
      type: file
      directory_layout: tms
    format: image/png
    request_format: image/png

sources:
  barrios_wms:
    type: wms
    req:
      url: http://localhost:8080/geoserver/wms
      layers: cali:barrios
      transparent: true
    coverage:
      bbox: [-76.6, 3.3, -76.4, 3.6]
      srs: 'EPSG:4326'

grids:
  webmercator:
    srs: 'EPSG:3857'
    origin: nw
  geograficas:
    srs: 'EPSG:4326'
    origin: nw

globals:
  cache:
    base_dir: './cache_data'
    lock_dir: './cache_data/locks'
  image:
    resampling_method: bilinear
    paletted: false

Iniciar MapProxy

en terminal de comandos

# Crear directorio de caché
mkdir cache_data

# Validar configuración
mapproxy-util validate mapproxy.yaml

# Iniciar servidor
mapproxy-util serve-develop mapproxy.yaml

# Acceder a:
# - Demo: http://localhost:8080/demo/
# - WMS: http://localhost:8080/service?
# - WMTS: http://localhost:8080/wmts/1.0.0/WMTSCapabilities.xml

Integración con Leaflet

tu archivo javascript

// Usando tiles cacheados de MapProxy
const map = L.map('map').setView([3.4516, -76.5320], 13);

// TMS 
L.tileLayer('http://localhost:8080/tiles/barrios_cache/webmercator/{z}/{x}/{y}.png', {
  attribution: 'Datos: Alcaldía de Cali',
  tms: true  // Importante: TMS usa origen inferior izquierdo
}).addTo(map);

Seeding: Precachear tiles

El “seeding” es generar tiles antes de que los usuarios los soliciten. Esto es muy útil para:

  • Lanzamiento de aplicaciones. Dejas la caché lista desde el día 1.
  • Actualizaciones de datos para regenerar caché afectada.
  • Áreas de interés. Solo cachear zonas relevantes.

Crear archivo seed.yaml:

Tu archivo yaml

seeds:
  barrios_seed:
    caches: [barrios_cache]
    grids: [webmercator]
    coverages: [cali_centro]
    levels:
      from: 10
      to: 16

coverages:
  cali_centro:
    bbox: [-76.5500, 3.4200, -76.5100, 3.4700]
    srs: 'EPSG:4326'

Ejecutar seeding:

en terminal de comandos

# Seed completo
mapproxy-seed -f mapproxy.yaml -s seed.yaml

# Solo mostrar estadísticas (no genera tiles)
mapproxy-seed -f mapproxy.yaml -s seed.yaml --dry-run

# Continuar seed interrumpido
mapproxy-seed -f mapproxy.yaml -s seed.yaml --continue

# Usar 4 procesos paralelos (más rápido)
mapproxy-seed -f mapproxy.yaml -s seed.yaml -c 4

Configuración avanzada: Múltiples capas

Tu archivo yaml

layers:
  - name: mapa_base
    title: Mapa base completo
    sources: [calles_cache, barrios_cache, limites_cache]

caches:
  calles_cache:
    sources: [calles_wms]
    grids: [webmercator]
    
  barrios_cache:
    sources: [barrios_wms]
    grids: [webmercator]
    meta_size: [4, 4]  
    meta_buffer: 10    
    
  limites_cache:
    sources: [limites_wms]
    grids: [webmercator]
    format: image/png8  

sources:
  calles_wms:
    type: wms
    req:
      url: http://geoserver:8080/wms
      layers: cali:calles
      
  barrios_wms:
    type: wms
    req:
      url: http://geoserver:8080/wms
      layers: cali:barrios
      
  limites_wms:
    type: wms
    req:
      url: http://geoserver:8080/wms
      layers: cali:limites

Optimización de almacenamiento con MBTiles

MBTiles es un formato de base de datos SQLite que guarda tiles de forma compacta:

Tu archivo yaml

caches:
  barrios_cache:
    sources: [barrios_wms]
    grids: [webmercator]
    cache:
      type: mbtiles
      filename: cache_data/barrios.mbtiles

Ventajas de MBTiles:

  • 30 a 50% menos espacio que archivos individuales.
  • Más rápido en SSD.
  • Portable.
  • Compatible con aplicaciones móviles offline.

Desventajas:

  • Locks de escritura. Problemas con concurrencia alta.
  • Más difícil de depurar.

¿Cuándo vale la pena cachear tiles?

SÍ necesitas caché cuando:

  • Tu mapa recibe más de 50 visitas diarias.
  • Usas capas con renderizado complejo con muchos polígonos y estilos pesados.
  • Tu servidor tiene recursos limitados.
  • Tus datos no cambian constantemente.
  • Quieres servir tiles en múltiples proyecciones.
  • Necesitas mapas offline o para apps móviles.

NO necesitas caché cuando:

  • Tus datos cambian cada minuto.
  • Tu mapa es dinámico porque tiene filtros o consultas personalizadas por usuario.
  • Tienes menos de 20 visitas diarias.
  • Usas tiles base externos de openStreetMap, Google o Mapbox.
  • Tu servidor tiene recursos sobrados y las capas son simples.

Limpieza de caché

Con el tiempo el caché crece por lo que debes aplicar limpieza:

en terminal de comandos

# Ver tamaño del caché
du -sh cache_data/

# Limpiar tiles antiguos de más de 30 días 
mapproxy-seed -f mapproxy.yaml -s seed.yaml --cleanup --older-than="30d"

# Limpiar zoom específico
mapproxy-seed -f mapproxy.yaml -s seed.yaml --cleanup --levels=17,18

Monitoreo de MapProxy

MapProxy no tiene dashboard built-in, pero puedes monitorearlo así:

en terminal de comandos

# Ver logs
tail -f /var/log/mapproxy.log

# Estadísticas básicas con Apache/Nginx access logs
awk '{print $7}' /var/log/nginx/mapproxy_access.log | grep -E "/tiles/" | wc -l

Configuración de producción con Nginx

nginx

upstream mapproxy {
  server localhost:8080;
}

server {
  listen 80;
  server_name tiles.midominio.com;
  
  location / {
    proxy_pass http://mapproxy;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    
    # Caché en Nginx 
    proxy_cache tiles_cache;
    proxy_cache_valid 200 30d;
    proxy_cache_valid 404 1m;
    add_header X-Cache-Status $upstream_cache_status;
  }
}

# Definir zona de caché
proxy_cache_path /var/cache/nginx/tiles 
  levels=1:2 
  keys_zone=tiles_cache:100m 
  max_size=10g 
  inactive=30d;

Recursos