Subchapter 25.20
references/phases/clarify/clarify-database.mdMarkdown11 KBView on GitHub
Fragment unit. See
clarify.mdfor how it is composed into the phase.This fragment asks nothing. It returns rows;
clarify-assemble.mdpresents them.
Fires when the inventory contains a relational database, a cache, or a Cosmos account. Category D.
The availability row (Q-D1) is the most consequential row in the entire phase. It selects RDS versus Aurora, which is roughly a 2× difference on the database line, and it is the one answer that cannot be read from the estate.
| Read from the inventory | Resolves |
|---|---|
each flexible server’s high_availability.mode and zone | the source’s HA posture — context for Q-D1, never the answer |
sku_name, storage_mb, version, backup_retention_days | sizing inputs and the engine-version floor |
Microsoft.Sql/servers/databases sku_name (DTU or vCore) and elastic_pool_id | the Azure SQL tier; an elastic_pool_id routes to the specialist gate instead |
Cosmos kind / capabilities | which API, and therefore whether Q-D5 fires at all |
Cosmos throughput and per-container throughput | the RU/s figure Q-D5 converts |
Disposition:
single-az.What availability do your databases need on AWS?
[A] Single-AZ — one instance, automated backups (dev-tier default)
[B] Multi-AZ — synchronous standby, automatic failover, roughly 2x the cost
[C] Multi-AZ with high availability — Aurora, fastest failover
[D] Multi-region — Aurora Global DatabaseInterpret → data.availability:
| Answer | Write | When global.user_geography is not global |
|---|---|---|
| [A] | single-az | — |
| [B] | multi-az | — |
| [C] | multi-az-ha | — |
| [D] | multi-region | Still write multi-region (the user picked [D]). Design honors it and says in the rationale that global infrastructure was requested without global users (database.md §1). |
Canonical clarify-availability.md: Catastrophic + user_geography: "global" is the
combination that warrants Aurora Global. Do not auto-upgrade [C] to multi-region
because geography is global — that would invent Aurora Global without the recorded
availability answer. Do not refuse [D] when geography is single-region / multi-region.
Consequence line (PROPOSED case): Assuming single-AZ → the smallest defensible database line. Multi-AZ roughly doubles it and buys automatic failover; Aurora is a different operational model again.
Consequence line (ESSENTIAL case — say this instead): Your pg-contoso-store is
configured ZoneRedundant with a standby in zone 2 today. We will not assume you want to
keep paying for that, and we will not assume you want to give it up. This one needs an
answer.
Two rules, and both matter:
single-az, explicitly not Aurora.
Inferring Aurora from the source’s HA inflates the estimate with no visible cause, and
the customer has no way to see which of their own inputs drove it.Either way, if the source is zone-redundant and the answer resolves to single-AZ, Design
emits an availability_downgrade_from_source finding — the downgrade is a decision, so it
gets said out loud rather than buried in a sizing table.
database.md §1 turns this row into the RDS-versus-Aurora family selection as a
post-rubric override: it beats whatever the six criteria would have chosen, because
availability is never inferable from configuration.
Disposition: ESSENTIAL when any relational database is present. No default.
How should the data move?
[A] AWS DMS with continuous replication — near-zero downtime,
more setup, needs logical replication enabled on the source
[B] Dump and restore during a maintenance window — simpler,
downtime proportional to database sizeNo default, for the same reason as the VM cutover question: the two produce different runbooks, not different numbers. DMS is a replication project with a validation phase; a dump/restore is a scheduled outage. Guessing makes every Generate artifact wrong.
Pair the row with the extracted size so the choice is informed — a 60 GiB database and a 6 TiB database make [B] a very different proposition.
Disposition: DETECTED when every source is a burstable/dev tier (the answer is
steady); PROPOSED otherwise. Default: steady.
[A] Steady — roughly constant query load (default)
[B] Read-heavy with peaks — would benefit from read replicas
[C] Spiky / unpredictableConsequence line: Assuming steady → sized from current capacity, no read replicas. Read-heavy workloads add replicas, which adds cost but usually less than upsizing the primary.
Disposition: PROPOSED. Default: medium.
[A] Low [B] Medium — gp3 general purpose (default) [C] High — needs provisioned IOPSConsequence line: Assuming medium I/O → gp3 storage. High-IOPS workloads need io2 or provisioned IOPS, which is a materially different storage line.
Storage size is never right-sized downward from utilization. Shrinking allocated
storage is not an online operation on RDS, so a too-small guess is expensive to undo.
Carry storage_mb across as allocated GiB and keep the source’s headroom.
Disposition: ESSENTIAL when a Cosmos Core (SQL) API account is present; N/A otherwise — the four wire-protocol APIs (Mongo, Cassandra, Gremlin, Table) are fast-path rows and need no conversion.
Your Cosmos account cosmos-contoso-catalog is provisioned at 4,000 RU/s.
Converting that to DynamoDB capacity depends entirely on the read/write mix.
[A] Read-heavy — roughly 90% reads
[B] Balanced — roughly 50/50
[C] Write-heavy — roughly 90% writesNo default, because the answer moves the result by multiples. A write costs substantially more RU than an eventually-consistent read, so the same 4,000 RU/s converts to very different WCU/RCU depending on the mix — and only the customer knows theirs. A silent assumption here produces a confident number that can be wrong by 5×.
Also record, as findings rather than questions:
max_throughput is a ceiling, not a demand.Disposition: DETECTED when the source is Microsoft.Cache/Redis (plain Azure Cache
for Redis has no modules — the answer is no); PROPOSED when it is
Microsoft.Cache/redisEnterprise. Default: false.
Consequence line: Assuming no Redis modules → ElastiCache Redis is a drop-in. RediSearch, RedisJSON and RedisTimeSeries have no ElastiCache or MemoryDB equivalent, and that is a feature gap rather than a sizing difference.
"data": {
"availability": { "disposition": "ESSENTIAL", "value": null, "default": null,
"source_ha_context": "pg-contoso-store: ZoneRedundant, standby zone 2" },
"db_cutover": { "disposition": "ESSENTIAL", "value": null, "default": null },
"traffic_pattern": { "disposition": "PROPOSED", "value": null, "default": "steady" },
"storage_io": { "disposition": "PROPOSED", "value": null, "default": "medium" },
"cosmos_rw_split": { "disposition": "N/A", "value": null, "default": null },
"redis_modules": { "disposition": "DETECTED", "value": false, "default": false }
}source_ha_context is carried so the assembler can print the ESSENTIAL row’s consequence
line with the actual resource named. A generic “your source may be HA” is ignorable; naming
the server is not.
| Row | Consumer |
|---|---|
availability | database.md §1 — the post-rubric override that selects RDS vs Aurora |
db_cutover | Generate’s migration runbook, and the DMS-versus-dump tooling choice |
traffic_pattern, storage_io | Estimate’s instance class and storage type |
cosmos_rw_split | database.md §4’s RU/s → WCU/RCU conversion |
redis_modules | database.md‘s ElastiCache eliminator |
Implemented for Postgres/MySQL Flexible Server, Single Server, Azure SQL Database, Cosmos Core, and Redis. Managed Instance and elastic pools never reach this fragment — they are specialist gates, and the sheet should say they were deferred rather than leaving them silent.