ADR 0053 — Project OCTOPUS Cell-Based Hyperscale Architecture¶
- Status: Accepted
- Date: 2026-05-14
- Deciders: André Luiz Gallon (Architect/Operator)
- Supersedes: —
- Related: ADR 0043 (OOBI VLAN no-VXLAN), ADR 0048 (ZTP-Prem 12-layer), ADR 0054 (PQC-Everywhere), ADR 0055 (Admin Console), ADR 0056 (Auto-Provisioning)
- Memory:
project_octopus_hyperscale_admin_pqc_locked_2026_05_14.md
Context¶
Project OCTOPUS é o sub-projeto multi-site dentro de TLSStress.Art, materializado em
pkg/octopus/ (PR #753). Os dois serviços cloud-side (CONNECT.Art rendezvous + STUN-coord
signaling) precisam ser projetados desde o início para escalar de dezenas de clientes
(MVP) a centenas de milhares sem refactor doloroso.
Sistemas SaaS que tentam escalar monoliticamente acabam pagando dívida arquitetural catastrófica:
- Stripe levou ~2 anos migrando de monólito Ruby/Mongo para shards Razorpay-style
- Slack reescreveu para Vitess depois de hot-spots irrecuperáveis no MySQL master único
- Snowflake projetou cells desde o dia 1 e nunca precisou pause-the-world migration
- Cloudflare opera cells regionais isoladas ("colos") com APIs cell-aware
Decisões iniciais — formato de IDs, sharding keys, namespaces de banco, separação control-plane vs data-plane — condicionam toda a evolução futura. Refactor depois é caro; design correto desde o início é barato.
Decisão¶
O OCTOPUS adota arquitetura cell-based desde o Wave-0, mas com implementação progressiva disparada por gates de adoção.
Conceitos canônicos¶
- Cell: unidade de isolamento contendo até 10 000 clientes com seu próprio
stack OCTOPUS completo (CONNECT.Art + STUN-coord + state store + observability).
Crash de uma cell NÃO afeta outras cells. Cells são identificadas por
cell_id(formato<region>-<n>, ex.:us-east-1-a,eu-west-1-b). - Region: agregado geográfico de 1+ cells servindo clientes daquela área. Cada region tem edge anycast próprio (Cloudflare Magic Transit / AWS Global Accelerator / Azure Front Door).
- Control Plane: serviços globais que servem TODAS as cells (Admin Console, Provisioning Orchestrator, Token Marketplace, Vault PKI root, audit chain). Multi-region active-active.
- Data Plane: tráfego de clientes através de CONNECT.Art / STUN-coord. Per-cell, cell-isolated.
Sharding key¶
deployment_id é a única sharding key. Consistent hashing distribui deployment_id
across cells. Rebalance hot-spot-aware (cell saturada deflagra split).
Schemas / IDs cell-ready desde dia 1 (mesmo em single-cell)¶
- Todo
DeploymentIDULID encoded para sort-by-time + uniqueness sem coordenação - Todos os Postgres schemas têm coluna
cell_idna chave primária (NULL aceito em Wave-1; obrigatório em Wave-3+) - APIs cloud emitem header
X-Octopus-Cellem toda response — observability cell-aware desde o dia 1 - Métricas Prometheus carregam label
cell_id(cardinality já controlada) - Audit chain Merkle tem branch per-cell, root global
Gates de evolução por wave¶
| Wave | Trigger entry | Arquitetura | Estimativa |
|---|---|---|---|
| 1 | scaffold (#753 merge) | Single region, single cell, DynamoDB regional, schemas cell-ready | shipping now |
| 2 | 500+ clientes ativos OU p99 > 100ms 1-region | Multi region (3-5 cells single-per-region), DynamoDB Global Tables, GeoIP routing | +3-6 meses |
| 3 | 5 000+ clientes OU uma cell > 60% saturada | Multi cell per region, NATS JetStream event bus, Cloudflare Workers + Anycast edge | +3-6 meses |
| 4 | 50 000+ clientes OU > 3 cells/region saturadas | FoundationDB ou Spanner global, ClickHouse petabyte analytics, OpenTelemetry single fabric | +6-9 meses |
Cada wave é incremental sobre a anterior; nunca rewrite from scratch. Investidor cobra plano de scale antes de Series A — este ADR é a resposta.
Alternativas consideradas¶
| Alternativa | Por que rejeitada |
|---|---|
| Monolítico até dor | Pago em refactor depois (2+ anos custo). Risco de blow-up sob tração. Não vendável para Series A. |
| Cells desde Wave-1 | 6× código + complexidade operacional ANTES de ter clientes. Premature operationalization. |
Sharding por customer_id em vez de deployment_id |
customer_id é unidade de billing/admin; deployment_id é unidade de tráfego cloud. Tráfego é o que satura — shardar pelo eixo que satura. |
| Per-cliente isolation (1 cell por cliente Enterprise) | Reservado para tier "Dedicated Cell" (premium SKU futuro). Default é shared-cell até 10k/cell. |
Consequências¶
Positivas¶
- Blast radius limitado a 1 cell (até 10k clientes afetados, nunca todos)
- Capacity planning por cell: previsível, modelável
- Tier "Dedicated Cell" virá vender-se sozinho para Enterprise (compliance, isolation guarantees)
- Cells de carga distintas (free/pro/enterprise) podem ter SKUs separados de hardware
- Multi-cloud failover: se AWS us-east-1 cai, traffic GeoIP-encaminhado para GCP us-east1 cell hot-standby
Negativas¶
- Cross-cell features (ex.: customer com deployments em 2 regiões) precisam de coordinator no Control Plane (added complexity)
- Operations team precisa de "cell awareness" — runbooks, on-call rotation per-cell
- Audit chain Merkle root global tem latência de finalização (consenso multi-cell)
Neutras¶
cell_idaparece em todos os logs, métricas, schemas — overhead de tags desde o dia 1
Implementação Wave-1 (do scaffold atual ao gate de Wave-2)¶
PRs antecipados:
- PR-OCTOPUS-3: cell-aware IDs/schemas em
pkg/octopus/common/types/— ULID,cell_idem todos DTOs (defaultdefault-1), headerX-Octopus-Cell - PR-OCTOPUS-7: HPA + VPA + Karpenter manifests por cell
- PR-OCTOPUS-8: Multi-region failover Route53 + Cloud DNS + Azure Traffic Manager
- PR-OCTOPUS-10: SLO dashboards + error budgets cell-aware
Quando 500+ clientes ativos ou latência p99 > 100ms em uma região: triggar Wave-2.
Implementação Wave-1 — substrato de tenant do cell-0 (2026-06-13)¶
Esta seção detalha a mecânica concreta de isolamento por tenant do primeiro
cell real (Hetzner, hel1-0), que o Provisioning Orchestrator (ADR 0056)
materializa nas activities AllocateCell / ProvisionTenant /
ReserveConnectArtSlot / ReserveStunCoordSlot (antes fail-closed). É a
realização Wave-1 (single-cell) das decisões estratégicas acima — incremental,
nunca rewrite.
Identidade do cell¶
cell_id = "hel1-0"(formato<region>-<n>, valida emcommon/types.CellID).AllocateCell(country)em Wave-1 retorna sempre o cell único (não há GeoIP routing até Wave-2); a assinatura porcountryé preservada para o roteamento futuro. O ADR mantémdefault-1como fallback de dev.
Cell control DB (Postgres) — plano de controle do cell¶
Um Postgres no cell (database cell) hospeda o registro de controle, separado
do Postgres do Temporal (concern distinto). Schema (migração 0001_cell_control.sql):
tenants(
deployment_id text primary key, -- sharding key (ULID/dpl_*)
cell_id text not null,
customer_email text,
status text not null, -- provisioning|provisioned|rollback_pending|released
created_at timestamptz default now(),
updated_at timestamptz default now()
)
slots(
deployment_id text not null,
kind text not null, -- 'connect-art' | 'stun-coord'
cell_id text not null,
reserved_at timestamptz default now(),
released_at timestamptz, -- NULL = ativo
primary key (deployment_id, kind)
)
-- tabela de dados de exemplo com RLS por tenant (modelo p/ as tabelas de tráfego):
tenant_data(
deployment_id text not null,
...,
-- RLS: policy USING (deployment_id = current_setting('octopus.tenant', true))
)
Todas as tabelas carregam cell_id na chave (NULL aceito em Wave-1, obrigatório
em Wave-3+) conforme a decisão "schemas cell-ready desde o dia 1".
Isolamento: Postgres RLS (shared-schema, não schema-per-tenant)¶
Wave-1 usa Row-Level Security em schema compartilhado (escala a 10k tenants/cell
sem 10k schemas). As tabelas de dados de tráfego têm ENABLE ROW LEVEL SECURITY +
policy USING (deployment_id = current_setting('octopus.tenant', true)). A conexão
de runtime de cada deployment seta SET octopus.tenant = '<deployment_id>' (ou via
um role por-tenant com SET ROLE), de modo que um tenant nunca lê linhas de outro.
ProvisionTenant não cria schema — apenas registra o tenant (a policy é
template, criada na migração) e prepara seu contexto RLS.
Redis namespace¶
Convenção de namespacing por prefixo de chave: octopus:{cell_id}:{deployment_id}:*.
ProvisionTenant não cria nada no Redis (namespacing é lógico via prefixo); o
runtime do tenant é obrigado ao prefixo pelo seu token/config. (Redis ACL por-tenant
é Wave-2+.)
Contrato de admissão CONNECT.Art / STUN-coord (o que é um "slot")¶
CONNECT.Art (rendezvous, Pattern A, ADR 0050) e STUN-coord (signaling, Pattern B,
ADR 0051) são data-plane. Um slot NÃO é um recurso de runtime escasso — é a
entrada de admissão que autoriza um deployment_id a usar aquele serviço no
cell. Reserve{ConnectArt,StunCoord}Slot faz UPSERT em slots; os serviços de
data-plane consultam slots (ou um cache dele) para admitir/rejeitar um
deployment_id apresentando seu cert (emitido via cert-manager, ADR 0053-PKI/H4).
Assim a reserva é uma escrita de controle real e idempotente, e o enforcement de
runtime é uma leitura do mesmo registro — sem acoplar o provisioner ao runtime.
Mapeamento activity → operação (idempotente, transacional)¶
| Activity | Operação no cell control DB |
|---|---|
AllocateCell |
retorna hel1-0 (validado); sem escrita |
ProvisionTenant |
INSERT tenants ... ON CONFLICT (deployment_id) DO UPDATE status='provisioned' |
ReserveConnectArtSlot |
INSERT slots(deployment_id,'connect-art') ON CONFLICT DO UPDATE released_at=NULL |
ReserveStunCoordSlot |
idem, kind='stun-coord' |
ReleaseConnectArtSlot (comp.) |
UPDATE slots SET released_at=now() WHERE deployment_id,kind |
ReleaseStunCoordSlot (comp.) |
idem |
MarkTenantRollbackPending (comp.) |
UPDATE tenants SET status='rollback_pending' |
ReleaseCellAllocation (comp.) |
UPDATE tenants SET status='released' |
Toda activity é idempotente (UPSERT por chave determinística), satisfazendo o
contrato de retry do Temporal (ADR 0056). O idempotencyKey derivado de
(WorkflowID, ActivityName, Attempt) é gravado para auditoria.
Fronteiras (o que é Wave-1 vs adiado)¶
- Wave-1 (este H5): cell control DB + RLS shared-schema + slots como admissão + activities reais idempotentes. O saga de onboarding completa fim-a-fim no cell.
- Adiado (Wave-2+): registro de runtime ao vivo no CONNECT.Art/STUN-coord
(hoje a admissão é por leitura do
slots), Redis ACL por-tenant, GeoIP cell routing, multi-cell rebalance, schema-per-tenant para tier "Dedicated Cell".
Postura de custo¶
O cell control DB reaproveita a instância Postgres já presente no cell (database
cell separado), evitando custo incremental. Tudo roda no único VPS Hetzner do
cell-0 (~$12-15/mo, off-AWS) — ver project_f2_onboarding_wiring_2026_06_13.
Patent claim potencial¶
Family E — Cell-Based Hyperscale Federation with Per-Tenant Routing Locality:
combinação de (1) sharding por deployment_id ULID, (2) GeoIP cell routing,
(3) cross-cell coordinator com Merkle audit chain global, (4) cell-as-tier SKU.
Provisional draft Q4 2026 se Pattern A + B + C provisional drafts já filed em Q3 2026.