Saltearse al contenido

El bucket es la base de datos

NamiDB no tiene un control plane externo. Sin cluster de Raft. Sin ZooKeeper. Sin tabla de locks en DynamoDB. Sin etcd. El bucket es la base de datos — cada byte de estado del motor es un objeto plano en el store compatible con S3 que abriste con tg.Client("s3://...").

Qué vive en el bucket

s3://my-bucket/data/{namespace}/
├── manifest.json # CAS root: epoch, current SST list, LSN watermark
├── wal/ # Write-ahead log segments
│ ├── 0000-0042.wal
│ └── 0043-current.wal
├── sst/ # Sorted-string tables
│ ├── node/L0/... # Parquet node SSTs
│ ├── node/L1/...
│ ├── edge/L0/... # Custom edge SSTs with CSR adjacency
│ └── edge/L1/...
└── schema/ # Label & property schemas
└── current.json

Tres categorías:

  1. El manifest — un único objeto JSON, diminuto, que nombra cada SST actualmente vivo para el namespace, más el epoch, más el LSN watermark. Todas las escrituras se coordinan mediante CAS del manifest.
  2. El WAL — segmentos append-only. Cada escritura es durable apenas retorna una llamada a commit_batch.
  3. SSTs — archivos columnares inmutables. Los nodos van a Parquet; las aristas van a un formato custom CSR-aware (RFC-002).

Qué reemplaza al tier de consenso

Conditional writes de S3. Desde 2024, S3 respeta los headers If-Match / If-None-Match en PutObject. NamiDB escribe un nuevo manifest con If-Match: <previous-etag>; el primer writer gana, el resto recibe un 412 Precondition Failed y reintenta.

Esa primitiva por sí sola reemplaza:

Sin conditional writesCon conditional writes
Servicio de locks externo (DynamoDB, ZooKeeper)CAS del manifest sobre el propio objeto
Quorum de Raft / Paxos para el manifestPutObject condicional
Una base de datos de metadatos aparteUn manifest.json por namespace

Qué se gana con esto

  • Durabilidad es la que te da S3. 99.999999999%, multi-AZ.
  • Backups son aws s3 sync. No hay metadatos separados que capturar.
  • Restore es aws s3 sync en la otra dirección.
  • El costo escala a cero cuando ningún cliente abre el namespace. No hay compute corriendo. No hay capacidad de DynamoDB reservada.
  • Los tenants son carpetas. Cada ?ns=... es un sub-árbol en el bucket.
  • Dos procesos pueden abrir el mismo namespace. El que gana el CAS del manifest al momento del commit es el que puede escribir; el otro se fencea limpio (incremento de epoch) y vuelve a leer.

Qué se resigna

  • El throughput de escritura por namespace está acotado por un único writer por vez. Esto es una feature de correctness pero un techo para la tasa cruda de escritura. Sharding por namespace es la respuesta cuando se necesita más.
  • La latencia de lectura está acotada por abajo por la latencia de GET de S3 en el camino caliente. Los caches cross-snapshot (RFC-018, RFC-019, RFC-020) la ocultan en su mayoría para queries repetidas.
  • Transacciones fuertes cross-namespace están fuera de scope. Cada namespace es una unidad aislada.

Ver también