Arquitectura de Bases de Datos OLTP: De Principios a Implementación en Rust
Se han implementado subsistemas clave del motor OLTP: almacenamiento unificado en un solo archivo por base de datos, almacenamiento respaldado en disco con MVCC de registro UNDO, recuperación basada en WAL y ARIES, un BufferPool compartido, un motor en memoria y un protocolo pgwire compatible con PostgreSQL. El código es funcional pero requiere pruebas de carga y estabilización de casos límite. No es un producto final, sino una etapa temprana con contratos establecidos.
Principios de Diseño Fundamentales
El proyecto se basa en reglas estrictas para la toma de decisiones. Cada nueva decisión debe adherirse a ellas o justificar cualquier desviación.
Restrictivo por Defecto
Los componentes tienen límites explícitos con comportamiento de fallo cerrado en lugar de limitación. Esto garantiza predictibilidad bajo carga.
| Componente | Límite | Acción ante Violación | SQLSTATE |
|-----------|---------|------------------------|----------|
| BufferPool | buffer_pool_size_mb | Evicción (CLOCK), vaciado WAL primero | — |
| TxnWriteSet | txn_max_write_set_mb | Rechazar DML | 54023 |
| UndoStore | undo_max_size_mb | Rechazar escrituras | 53100 |
| Pool de conexiones | max_connections | Rechazar nuevas conexiones | 53300 |
| Tiempo límite de sentencia | statement_timeout_ms | Cancelar consulta | 57014 |
| Antigüedad de snapshot | max_snapshot_age | Forzar cierre de snapshots obsoletos | 40001 |
El fallo cerrado proporciona códigos SQLSTATE claros para lógica de reintento de aplicaciones o cortacircuitos.
Enfoque Contrato-Primero
Los contratos arquitectónicos se definen en traits de Rust: TableEngine, PageProvider, TransactionLogSink, StorageIo. Esto evita la desviación de implementación al hacer cumplir invariantes en tiempo de compilación.
¿Por qué Rust?
Rust fue elegido por su latencia predecible, control de asignación de memoria y seguridad de tipos. Send/Sync en límites async/síncronos, errores explícitos en lugar de problemas en tiempo de ejecución. C++ requiere disciplina adicional, mientras que Go no es adecuado debido al GC para la latencia de cola en OLTP.
Separación de Responsabilidades
La base de datos funciona como un motor de datos sin lógica de negocio: sin disparadores, PL/pgSQL o procedimientos almacenados inicialmente. Las funciones definidas por el usuario pueden agregarse más tarde con aislamiento y sin efectos secundarios.
Asincronicidad Híbrida
- Capa de red/pgwire: asíncrona (aceptar, TLS, enviar).
- Núcleo (ejecución de consultas, almacenamiento, WAL, MVCC): síncrono para corrección y depuración.
- El límite es unidireccional a través de un puente.
StorageIo está abstraído para permitir E/S asíncrona futura sin reescribir la lógica de transacciones.
| Capa | Tiempo de Ejecución | Ejemplos |
|------|---------|---------|
| Red/Protocolo | asíncrono | pgwire, TLS |
| Ejecución de Consultas | síncrono | plan, ejecutar |
| Almacenamiento/WAL | síncrono (E/S asíncrona después) | HeapStore, BufferPool |
| MVCC/Transacciones | síncrono | snapshot, bloqueos |
Compatibilidad con PostgreSQL
Pgwire permite la integración con controladores y ORMs sin migraciones de cliente. La compatibilidad es a nivel de cable a través de una capa límite, sin copiar internos de PostgreSQL (montón MVCC, VACUUM). El núcleo conserva libertad arquitectónica.
Restricciones de Plataforma y Fiabilidad
Solo Linux para centrarse en io_uring y eBPF sin compromisos multiplataforma. Prioridades: sin corrupción de datos, reversión segura de optimizaciones, resiliencia a entrada de usuario, seguridad integrada.
Conclusiones Clave
- Restrictivo por Defecto con fallo cerrado para predictibilidad bajo carga.
- Contrato-Primero mediante traits de Rust para control de invariantes.
- Asíncrono/síncrono híbrido: estabilidad del núcleo antes de aceleración de E/S.
- Compatibilidad pgwire sin copiar internos de PostgreSQL.
- Motor de datos sin lógica de negocio para pureza y capacidad de prueba.
— Editorial Team
Aún no hay comentarios.