ENHabla con el equipo

Más allá de los frameworks: construir TileserveX para procesamiento geoespacial de latencia ultrabaja

Los servidores de teselas vectoriales suelen obligarte a elegir entre la ergonomía de un framework dinámico y la velocidad pura de un binario compilado. Combinar Plug y Cowboy con NIFs de Rust elimina ese dilema: esta es la arquitectura detrás de TileserveX.

16 de agosto de 2026

Cuando construyes infraestructura geoespacial de misión crítica, la decisión de arquitectura suele reducirse a dos opciones poco atractivas.

Los frameworks dinámicos de alto nivel — Python, Node.js — te dan ergonomía para el desarrollador y un ecosistema geoespacial rico. Bajo carga sostenida de CPU, también pueden traer más uso de memoria y cuellos de botella como el GIL de Python.

Los binarios compilados puros — Rust, C++ — te dan velocidad de ejecución y huellas de memoria pequeñas. También te dan una gestión compleja del estado distribuido, una curva de aprendizaje empinada para el enrutamiento web corriente y un costo real de mantenimiento en cuanto interviene la lógica de negocio.

Construimos TileserveX para averiguar si ese dilema es realmente necesario: un motor de teselas vectoriales que combina Elixir (Plug y Cowboy 2) con Rust (NIFs con Rustler) e implementa encima las especificaciones OGC API.

Arquitectura

TileserveX prescinde deliberadamente de un framework completo como Phoenix a favor de un pipeline HTTP de ejecución mínimo, y separa la concurrencia web, la orquestación de estado y el cómputo nativo de CPU en tres capas.

Tres capas apiladas. Arriba, la capa HTTP y de enrutamiento sobre Cowboy 2 y Plug: despacho directo de los endpoints /ogc/* y /{z}/{x}/{y}.pbf, inyección de cabeceras sin sobrecarga y transmisión de flujos binarios. En medio, la capa de concurrencia y estado sobre BEAM y OTP: caché ETS en memoria con TTL y un proceso de limpieza en segundo plano, ejecución asíncrona de trabajos OGC respaldada por GenServer, y gestión de pools de conexiones a PostGIS, MBTiles y SQLite. Abajo, la capa de ejecución con NIFs de Rust mediante Rustler: codificación y decodificación protobuf de MVT 2.1, matemática espacial para buffer, simplify, centroid y convex hull, y transformaciones de coordenadas entre EPSG:4326 y EPSG:3857.

Enrutamiento a bajo nivel: Plug y Cowboy 2

Phoenix tiene una ergonomía excelente para aplicaciones interactivas full-stack. Servir teselas vectoriales binarias con alto rendimiento es otro problema: lo que quieres es la mínima sobrecarga en el pipeline.

Conectar Plug.Router directamente a Cowboy 2 evita las asignaciones de pila del pipeline de controladores, la sobrecarga del análisis de parámetros y la configuración de pub/sub de canales. Las solicitudes se enrutan y se resuelven de forma directa, y los payloads empaquetados de Protocol Buffers van desde la capa de almacenamiento o la caché directamente a los sockets de red.

Cómputo espacial en NIFs de Rust

La geometría computacional está limitada por CPU por naturaleza: simplificación de líneas, recorte de polígonos (Liang-Barsky, Sutherland-Hodgman), transformaciones de coordenadas, codificación protobuf de MVT 2.1.

En lugar de dejar que esa matemática bloquee los schedulers principales de la BEAM, esas operaciones se delegan en NIFs de Rust mediante Rustler, configurados sobre dirty CPU schedulers. Aquí importan dos propiedades:

  • Serialización de copia cero. Los buffers de geometría vectorial pasan entre la memoria de la BEAM y el código Rust compilado prácticamente sin sobrecarga de serialización.
  • Seguridad de memoria y de hilos en tiempo de compilación. Las garantías de Rust mantienen fuera de la máquina virtual de Erlang las fugas de memoria y las fallas de segmentación, que no son algo que quieras tener ahí.

Cumplimiento de OGC API

TileserveX implementa los estándares con los que se evalúa una plataforma geoespacial:

  • OGC API — Tiles (Parte 1): teselas vectoriales y ráster, prerrenderizadas o dinámicas, en esquemas de pirámide estándar.
  • OGC API — Features (Partes 1–3): conjuntos de datos vectoriales consultables, con filtrado espacial, restricciones por propiedades y soporte flexible de CRS.
  • OGC API — Processes (Parte 1): ejecución asíncrona de trabajos espaciales pesados — buffers, centroides, envolventes convexas — gestionada mediante GenServers de la BEAM.

Qué aporta este diseño

La hipótesis detrás de este diseño es concreta: un servicio Elixir reducido a Plug y Cowboy 2 y acelerado con NIFs de Rust debería conservar la tolerancia a fallos de OTP sin pagar por un framework que no usa.

El aislamiento de procesos y los dirty schedulers lo hacen plausible. La geometría que consume CPU nunca bloquea a los schedulers que responden peticiones, y un fallo en una petición se queda en esa petición. Cuando una base de datos desaparece, el servidor responde 503 con Retry-After en lugar de quedarse colgado.

La conclusión útil para quien deba tomar esta decisión: elegir entre velocidad compilada y concurrencia de actores es menos binario de lo que parece. Elixir para enrutar conexiones y aislar procesos, Rust para el cálculo espacial pesado, es una combinación a considerar antes de irse a un extremo.

¿Quieres este criterio en tu sistema?

Cuéntanos qué construyes o qué está atascado.

Habla con nuestros ingenieros