El procesamiento de datos en el edge, lo más cerca posible de la fuente de generación, es una estrategia fundamental para optimizar la eficiencia y reducir los costos operativos en sistemas distribuidos a gran escala. En el contexto de la observabilidad, donde los volúmenes de logs pueden superar el billón de eventos por segundo, la capacidad de filtrar, transformar y redactar datos antes de su ingestión y almacenamiento downstream se convierte en un imperativo técnico. Este enfoque no solo mitiga la carga en los sistemas de análisis y almacenamiento, sino que también aborda requisitos de seguridad y cumplimiento al permitir la ofuscación de información sensible en el punto de origen.
Históricamente, esta transformación se realizaba mediante servicios de procesamiento intermedios, lo que introducía latencia, complejidad operativa y costos adicionales de infraestructura. La integración de capacidades de transformación SQL directamente en el pipeline de exportación de logs representa una evolución hacia arquitecturas de datos más eficientes, donde la lógica de negocio se aplica de manera declarativa y en el punto óptimo del flujo de datos. Esto se alinea con el principio de 'shift left' en el procesamiento de datos, moviendo la complejidad y el costo de la transformación a una etapa temprana del ciclo de vida del dato.
Arquitectura del Sistema
El componente central de Logpush Transformers es su integración con Bufstream, el servicio de entrega de logs de Cloudflare. Bufstream, escrito en Go, consume lotes de logs comprimidos en formato Cap'n Proto desde Buftee, el broker de mensajes distribuido interno de Cloudflare. Para los trabajos de Logpush con un Transformer adjunto, Bufstream descomprime el lote, parsea los logs y construye un Apache Arrow RecordBatch tipado. Este RecordBatch se pasa a un motor de ejecución SQL embebido, Apache DataFusion, que está escrito en Rust.
La comunicación entre Go y Rust se realiza a través de la Interfaz de Función Externa (FFI) de Apache Arrow, que expone una Interfaz Binaria de Aplicación (ABI) de C. Go utiliza cgo para invocar el código Rust, pasando punteros a buffers de Arrow IPC. Es crucial destacar que la propiedad de la memoria se gestiona explícitamente: Go pasa un puntero temporal a Rust, y Rust devuelve un nuevo buffer de salida que Go copia y luego libera la asignación de Rust. Esto previene problemas de gestión de memoria entre runtimes. DataFusion, al recibir los datos en su formato columnar nativo de Arrow, puede ejecutar el plan de consulta SQL de manera eficiente y vectorizada. El plan lógico de DataFusion se genera una vez por 'time slice' de un trabajo y se reutiliza para cada lote de Arrow. Después de la ejecución, el resultado en formato Arrow se convierte de nuevo a NDJSON, se comprime con gzip y se sube al destino configurado. La resiliencia se asegura con una estrategia de 'fail closed': si una transformación falla, el lote no se entrega y se reintenta, con mecanismos de backoff y deshabilitación automática para trabajos persistentemente fallidos.
Flujo de Transformación de Logs en Logpush
- 1 Buftee Envía lotes de logs comprimidos (Cap'n Proto) a Bufstream.
- 2 Bufstream (Go) Recibe, descomprime y parsea los logs.
- 3 Bufstream (Go) Construye Apache Arrow RecordBatch tipado.
- 4 Go/Rust FFI (cgo) Pasa puntero a buffer Arrow IPC a Rust.
- 5 DataFusion (Rust) Lee RecordBatch, ejecuta consulta SQL (plan lógico pre-compilado).
- 6 DataFusion (Rust) Devuelve Arrow RecordBatch transformado (nueva asignación de memoria).
- 7 Go/Rust FFI (cgo) Go copia el buffer de salida y libera la asignación de Rust.
- 8 Bufstream (Go) Convierte Arrow a NDJSON, comprime y sube a destino.
| Capa | Tecnología | Justificación |
|---|---|---|
| data-processing | Apache DataFusion | Motor de ejecución de consultas SQL embebido para filtrado, redacción y transformación de logs. Proporciona un planificador SQL y un motor de ejecución columnar vectorizado. vs Cloudflare Workers (WebAssembly), Otros motores SQL embebidos |
| data-processing | Apache Arrow | Formato de memoria columnar independiente del lenguaje para el intercambio eficiente de datos entre Go y Rust (DataFusion). Permite la ejecución analítica de alto rendimiento. vs JSON (para parsing por registro), Protocol Buffers (para intercambio) |
| messaging | Buftee | Broker de mensajes distribuido interno de Cloudflare. Fuente de los logs para Bufstream. |
| storage | Cloudflare R2 | Almacenamiento de objetos donde se guardan las consultas SQL de los Transformers. |
Trade-offs
Ganancias
- ▲ Reducción de volumen de datos downstream
- ▲ Normalización de esquemas en el origen
- ▲ Reducción de costos de exportación, ingestión y almacenamiento
- ▲ Eliminación de servicios de procesamiento intermedios
- ▲ Fiabilidad y throughput de entrega
Costes
- △ Aumento del uso de CPU en el servicio de entrega (Bufstream)
- △ Complejidad de interoperabilidad Go/Rust y gestión de memoria
SELECT
extract(epoch FROM to_timestamp(EdgeStartTimestamp)) AS unix_ts,
regexp_replace(ClientIP, '\.\d+\.\d+$', '.XXX.XXX') AS redacted_ip,
UPPER(ClientRequestMethod) AS method,
EdgeResponseStatus AS status,
RayID AS ray_id,
'cloudflare' AS provider,
named_struct(
'host', ClientRequestHost,
'path', ClientRequestPath
) AS request,
EdgeResponseStatus >= 500 AS is_server_error
FROM http_requests
WHERE ClientRequestHost NOT IN (
'internal.example.com',
'health.example.com'
)
AND ClientRequestPath NOT LIKE '/healthz%'
AND ClientRequestPath NOT LIKE '/metrics%'Fundamentos Teóricos
La arquitectura de Logpush Transformers se basa en principios bien establecidos de sistemas de bases de datos y procesamiento de datos distribuidos. La elección de Apache Arrow como formato de memoria columnar es un reflejo directo de la investigación en sistemas de bases de datos in-memory y procesamiento analítico, donde el formato columnar ha demostrado ser superior para cargas de trabajo analíticas debido a su eficiencia en el uso de la caché de CPU y su capacidad para la ejecución vectorizada. Este concepto fue popularizado por sistemas como C-Store (Stonebraker et al., 2005).
La integración de un motor SQL embebido como Apache DataFusion dentro de un servicio de streaming de logs recuerda el patrón de 'stream processing' con capacidades de consulta declarativas, similar a los sistemas que implementan SQL sobre streams de datos. La gestión de la consistencia y la resiliencia en un entorno distribuido, con mecanismos de reintento y 'fail closed', se alinea con los principios de diseño de sistemas tolerantes a fallos, donde la idempotencia y la entrega 'at-least-once' (o 'exactly-once' con coordinación adicional) son consideraciones clave, como se discute en trabajos sobre sistemas de mensajería distribuida y procesamiento de eventos complejos.