Resumen
Un estudio de arquitectura para un sistema de peaje en carretera donde el carril no puede esperar a la nube. Cámaras OCR y lectores RFID alimentan un proceso local en .NET Core que tiene que levantar o bajar una barrera en menos de 200 milisegundos, persistir cada evento en SQLite local, y reconciliar con un backend en la nube por MQTT cuando la conectividad lo permita — incluso después de horas sin conexión.
- Presupuesto de decisión
- < 200 msde vehículo identificado a decisión de barrera
Problema
Un vehículo que se acerca a un carril de peaje a velocidad le da al sistema una ventana fija y muy corta para identificarlo y decidir si la barrera abre. Ese presupuesto — menos de 200 milisegundos — es más pequeño que un solo viaje redondo a un servicio en la nube en un buen día, y los sitios en carretera no tienen buenos días de forma confiable.
La consecuencia de equivocarse es física. Un carril que deja de funcionar porque un enlace está caído no es un servicio degradado: es una fila de vehículos detenidos sobre una carretera.
Restricciones
- De identificación a decisión de barrera en menos de 200 milisegundos
- Operación autónoma completa durante pérdida de red, por horas y no por segundos
- Ningún evento se puede perder, incluidos los registrados sin conexión
- Dos tecnologías de identificación con características de precisión y falla distintas
- Hardware de carretera limitado y sin operador presente
Rol y contribución
Ingeniero de Software — arquitectura de sistemas
- Definí el modelo de fallas y qué puede dar por hecho cada capa sobre las demás
- Ubiqué la frontera de decisión en el carril y no en la nube
- Diseñé la persistencia local como el registro autoritativo del carril
- Diseñé el protocolo de reconciliación store-and-forward sobre MQTT
Diseño del sistema
Arquitectura
Responsabilidades de borde y nube
Cámaras OCR y lectores RFID identifican un vehículo y pasan el resultado a un proceso en .NET Core que corre localmente en el carril. Ese proceso toma la decisión de barrera dentro del presupuesto de latencia local, usando únicamente datos que tiene localmente, y escribe el evento en una base de datos SQLite local que es autoritativa en el carril. Un componente de sincronización publica los eventos al backend en la nube por MQTT cuando hay conectividad y los almacena en SQLite cuando no la hay, de modo que los eventos registrados sin conexión se entregan cuando el enlace regresa.
- Carril
- Cámaras OCR
- Lectores RFID
- .NET Core
- SQLite
- Transporte
- MQTT
- Sincronización store-and-forward
- Nube
- Backend central
- Reconciliación de cuentas
Alcance de este proyecto
Este es un proyecto de arquitectura e ingeniería académica. No es un sistema de peaje comercial desplegado, y las cifras de abajo son objetivos de diseño y no mediciones tomadas de hardware de carretera en operación.
Dónde va la frontera de decisión
Cada pregunta de diseño aquí se desprende de una sola ubicación: la decisión de levantar la barrera se toma en el carril, usando datos que el carril ya tiene, y nada de esa decisión espera a la red.
Eso invierte el arreglo habitual. La nube no es el sistema de registro que el borde consulta — es un consumidor de eventos que el borde ya confirmó. La conectividad pasa a ser una propiedad que afecta qué tan rápido se pone al día la vista central, nunca si un vehículo puede pasar.
Diseñar para horas sin conexión, no segundos
La distinción importa porque un búfer de reintento dimensionado para un corte breve es un componente distinto de uno dimensionado para una caída prolongada. Segundos de desconexión se pueden mantener en memoria y reproducir. Horas no: el búfer tiene que sobrevivir a un reinicio de proceso y a un corte de energía, lo que lo convierte en un problema de persistencia y no de red.
SQLite local hace entonces doble trabajo. Es el registro operativo del carril y es la cola de salida. Un evento es durable en el momento en que se toma la decisión, y la sincronización es una preocupación separada que lee de ahí — así que la ruta de código que decide si una barrera abre no contiene ninguna operación de red.
Dos entradas de identificación
OCR y RFID fallan distinto. Una lectura de tag es rápida e inequívoca cuando hay tag y es inútil cuando no lo hay; el reconocimiento de placa funciona para cualquier vehículo pero se degrada con clima, luz, velocidad y estado de la placa.
Correr ambos no es redundancia por sí misma — es cobertura de dos modos de falla disjuntos. Sí implica que el carril puede sostener dos identificaciones de confianza distinta dentro de la misma ventana de decisión, y resolver ese conflicto es parte de la lógica local y no algo que se difiere a la nube, porque diferirlo rompería el presupuesto de latencia.
Decisiones clave y trade-offs
Decisión
Hacer al carril autoritativo y tratar a la nube como consumidor
- Contexto
- Una decisión de barrera debe completarse en menos de 200 milisegundos; un viaje redondo a la nube no se puede garantizar dentro de ese presupuesto, y el enlace puede estar ausente por completo.
- Alternativas consideradas
- Nube autoritativa con caché local como respaldo
- Decisiones locales que requieren confirmación de la nube antes de mover la barrera
- Enfoque elegido
- El carril decide y confirma localmente; la nube reconcilia después a partir de los eventos publicados.
- Razón
- Es el único arreglo donde el presupuesto de latencia y el requisito sin conexión se cumplen por construcción y no por esperar que la red coopere.
- Trade-off
- La vista central es eventualmente consistente, y la reconciliación tiene que manejar eventos que llegan horas tarde y fuera de orden.
Decisión
Usar SQLite local como registro operativo y cola de salida a la vez
- Contexto
- Los eventos creados durante un corte deben sobrevivir a un reinicio y entregarse después.
- Alternativas consideradas
- Una cola en memoria con reintento
- Un broker de mensajes dedicado corriendo en el carril
- Enfoque elegido
- Persistir en SQLite al momento de decidir; la sincronización lee de ese almacén.
- Razón
- Una cola en memoria pierde eventos ante un corte de energía, que es exactamente la condición que necesita sobrevivir. Un broker local agrega un segundo componente con estado a hardware sin operador.
- Trade-off
- La latencia de escritura a disco queda dentro de la ruta de decisión, y el almacén necesita su propia política de retención para no crecer sin límite durante un corte largo.
Decisión
Publicar por MQTT en vez de llamar a una API HTTP
- Contexto
- La conectividad en carretera es intermitente y con frecuencia sobre enlaces limitados.
- Alternativas consideradas
- HTTP por lotes con reintento
- Una conexión bidireccional persistente al backend
- Enfoque elegido
- Publicación por MQTT con búfer local.
- Razón
- MQTT está diseñado exactamente para esta forma: mensajes pequeños, enlaces poco confiables, muchos extremos, y un broker que desacopla la publicación de la entrega. La lógica de reintento sobre HTTP terminaría reimplementando el mismo comportamiento, peor.
- Trade-off
- Un broker pasa a ser parte de la huella operativa, con su propia disponibilidad y superficie de seguridad.
Resultado
- Una arquitectura donde el presupuesto de latencia y el requisito sin conexión se cumplen por construcción y no por disponibilidad de red
- Sin pérdida de eventos ante reinicios o cortes prolongados, al hacer de la persistencia el primer paso de la ruta de decisión
- Dos tecnologías de identificación que cubren modos de falla disjuntos, resueltas localmente
Aprendizajes
- Ubicar la frontera de decisión es la elección arquitectónica; casi todo lo demás se desprende de ahí.
- 'Sin conexión por segundos' y 'sin conexión por horas' son requisitos distintos que producen componentes distintos. Dimensionar eso mal es un error de diseño, no de ajuste.
- La consistencia eventual es fácil de aceptar en un diagrama y cara en código de reconciliación, que es donde termina la mayor parte de la complejidad real.
- Las consecuencias físicas cambian el modo de falla aceptable: un sistema que se detiene es peor que uno que es temporalmente aproximado.
Próximas mejoras
- Latencia medida sobre hardware representativo de carretera, para confirmar que el presupuesto se sostiene en la práctica
- Una política definida de resolución de conflictos para la reconciliación cuando un evento tardío contradice el estado central
- Política de retención y contrapresión para el almacén local durante un corte prolongado
- Diseño de seguridad para la identidad del dispositivo y la autenticidad de los mensajes sobre el transporte MQTT