Unit 5.3: Relational Databases (Managed PostgreSQL / MariaDB)
Introduction
The relational tier is where FinCorp's most consequential design decisions concentrate. A bank's ledger cannot silently lose committed transactions, yet a tier that blocks writes whenever a node hiccups is its own kind of outage. The managed database services let you place that durability-versus-availability dial precisely, but only if you understand what each setting guarantees and which conveniences the platform deliberately does not offer. This unit works through the replication, scaling, failover, access, and recovery decisions, then builds the FinCorp relational cluster in the Data Center Designer with those decisions baked in.
The honest framing matters more than usual here. There are no read replicas, no managed failover product, and the Backup Service does not touch a managed database. Each gap has a native pattern that composes around it, and an architect who treats these as design inputs rather than missing features ends up with a cleaner, more predictable data tier.
1. The Replication-Mode Decision
A managed PostgreSQL cluster is a primary with one to five instances in total, so up to four standbys. The replication mode governs the contract between a committed transaction and its durability across those nodes, and it is the single decision that sets the cluster's RPO. PostgreSQL supports two current modes: Asynchronous (the default) and Strictly Synchronous. A third mode, non-strict Synchronous, is deprecated for new clusters and should not be chosen; existing clusters on it can be moved to asynchronous or strictly-synchronous through the replication-mode API.
Asynchronous confirms a transaction as soon as it is written to disk on the primary; replication to standbys happens in the background, with lag typically in the low milliseconds. The benefit is the lowest write latency. The cost is a non-zero RPO: if the primary fails before a recent commit has replicated, that commit is lost when a standby is promoted. The documented worst case for the backup path is losing up to the last 30 minutes or 16 MB of data if all replicas lose their data simultaneously, since archived data is shipped in 16 MB chunks or every 30 minutes, whichever comes first. On a healthy multi-node cluster the realistic exposure is a few milliseconds of in-flight commits, but the architectural point stands: asynchronous mode trades a small, bounded data-loss window for availability and latency.
Strictly Synchronous holds the commit until at least one synchronous standby has the transaction, so no committed data is lost during a failover, including a primary storage failure with a simultaneous loss of all standbys. The price is paid in two places. Latency gains a constant per-transaction overhead, because every COMMIT now waits on replication (the inter-node latency is usually below 1 ms, but added to every write). More importantly, this mode sacrifices availability for durability: if no synchronous standby is available, the primary stops accepting writes rather than continue unprotected. To run it safely you therefore need a minimum of three instances, so the loss of one node still leaves a primary and a synchronous standby. Provisioning fewer nodes is the classic trap, since a single standby failure then halts all writes.
The following table from the documentation contrasts the two modes that should be in production use:
| Aspect | Asynchronous | Strictly Synchronous |
|---|---|---|
| Primary failure | A standby will be promoted if the primary node becomes unavailable. | Only standby nodes that contain all confirmed transactions can be promoted. |
| Standby failure | No effect on primary. Standby catches up once it is back online. | At least one standby must be available to accept write requests. There is a short delay in transaction processing if the synchronous standby changes. |
| Consistency model | Strongly consistent (except for lost data.) | Strongly consistent (except for lost data.) |
| Data loss during failover | Non-replicated data is lost. | Not supported. |
| Data loss during primary storage failure | Non-replicated data is lost. | Not supported. |
| Latency | Limited by the performance of the primary. | Limited by the performance of the primary, the strictly synchronous standby, and the latency between them (usually below 1ms). |
PostgreSQL also lets you change commit guarantees per transaction, and the asymmetry matters: you cannot enforce a synchronous commit on an asynchronous cluster (without a synchronous standby, any stronger setting collapses to local), but you can run a strictly-synchronous cluster and relax individual transactions to synchronous_commit=local where a little data loss is acceptable. The defensible default is therefore to set the cluster to the stricter guarantee the workload needs and relax selectively, not the reverse.
MariaDB removes this decision entirely. Managed MariaDB is asynchronous-only: one replication mode, the default. That is a scoping decision, not a defect to work around. MariaDB runs on Virtual Servers (not Cube instances), uses SSD Premium storage with InnoDB, MyISAM, or Aria engines, and ships LTS versions only, currently from 10.6 onward. If a FinCorp workload genuinely needs zero-data-loss commits, it belongs on PostgreSQL in strictly-synchronous mode, not on MariaDB. Choosing the engine is thus partly a durability decision, not only a SQL-dialect one.
1.1 What automatic failover does inside a cluster
Failover within a single cluster is automatic and needs no external product. When the primary becomes unavailable, a standby is promoted. In asynchronous mode any standby can be promoted and non-replicated transactions are lost; in strictly-synchronous mode only a standby holding all confirmed transactions is eligible, which is why the mode cannot lose committed data. At most one synchronous standby exists at a time, and if it fails another is automatically elevated to the synchronous role. This in-cluster promotion is the whole of the platform's managed failover for a database: it protects against node loss inside one cluster, not across clusters or regions.
2. Read Scaling Without Read Replicas
PostgreSQL standbys exist for high availability, not for serving read traffic. There are no read replicas: you cannot point reporting or read-heavy traffic at a standby, and there is no managed read-only endpoint. This is a hard platform boundary, and the native pattern that replaces it has two parts.
First, a connection ceiling that is derived, not chosen. The maximum number of connections to a PostgreSQL cluster is calculated from RAM size and is not user-configurable. The documented mapping is:
| RAM Size | max_connections |
|---|---|
| 4 GB | 384 |
| 5 GB | 512 |
| 6 GB | 640 |
| 7 GB | 768 |
| 8 GB | 896 |
| >8 GB | 1000 |
Of those, 11 connections are reserved for system use, so the application's usable budget is the table value minus eleven. The consequence is that you cannot solve a connection storm by editing a parameter; the only levers are more RAM (up to the 1000-connection ceiling) or fewer real connections. For a microservice estate or a serverless front end that opens far more logical connections than the ceiling allows, the answer is pooling.
Second, the managed connection pooler (pgbouncer). You can enable it on the cluster; the only thing you configure is the pool mode. Transaction mode (the default) returns the connection to the pool at the end of each transaction, which multiplexes many client connections onto few backend connections and is the right choice for typical web and microservice traffic. Session mode holds the backend connection until the client disconnects, which is needed only when a session relies on connection-scoped state such as session variables or prepared statements that must persist. The pooler listens on a different port: 6432 instead of the database's default 5432, so enabling it is also a client-configuration change, not a transparent switch. Applications must be pointed at 6432 to get the benefit.
Read scaling proper is solved one tier up, in the cache. Because standbys cannot serve reads, the platform's read-scaling pattern is the In-Memory DB cache (Unit 5.5) placed in front of the relational tier on the private network, combined with pooling to protect the connection budget. Hot reads are absorbed by the cache, the relational primary handles writes and cache-miss reads, and pooling keeps the connection count under the RAM-derived ceiling. This cache-plus-pooling composition is what "scaling reads" means on this platform, and it is why Unit 5.5 is a direct dependency of any high-read FinCorp service, not an optional extra.
3. Failover Across Clusters and Private Access
In-cluster promotion (Section 1.1) is the only managed failover. There is no managed failover product that spans clusters or regions, and crucially there is no native cross-region or cross-cluster database replication at all. If FinCorp needs continuity beyond a single cluster, that continuity is engineered, and it is steered, not replicated, at the database layer.
The native cross-cluster pattern is customer-orchestrated DNS failover (built in Unit 3.7, revisited for resilience in Unit 7.1). Two independent clusters are stood up, kept in step by the application or by periodic dump/restore, and an external health check re-points a low-TTL Cloud DNS record to whichever endpoint is healthy. Cloud DNS itself is not health-aware; it serves whatever record you set. Two properties drive the design: DNS steers new connections only, so existing sessions do not migrate and the application must reconnect cleanly; and recovery time is dominated by the TTL floor of the failover record, the lever you tune for RTO. Because the second cluster is a separate database, this is an availability mechanism with its own RPO governed by how you keep the two in sync, not a zero-loss mirror.
Access is private-endpoint-only. A managed cluster has no public IP; it is reachable solely from within the Virtual Data Center over a private LAN. During creation you select a datacenter, a LAN, and a private IP. Connections are TLS-protected by default: the SSL mode is prefer and cannot be disabled by the client, with the server certificate issued by a trusted authority. Several internal CIDR ranges are platform-reserved and cannot be used for the cluster's private IP. The payoff is that the data tier sits behind the private Layer 4 balancer of the canonical layered architecture (Unit 1.2), never exposed to the internet, reached only by the application tier and the cache.
4. Migration and Recovery: Dump/Restore and PITR
Two facts define the data-continuity plane for managed relational databases, and both are constraints to design around.
The Backup Service does not cover managed databases. The Acronis-based Backup Service backs up VMs and Block Storage, not DBaaS, and Block Storage snapshots are VM-level rollback, not database-consistent backups. Database continuity is built from two native mechanisms only: managed point-in-time recovery, and logical dump/restore.
Point-in-time recovery is the in-place safety net. The managed service combines periodic base backups with continuous Write-Ahead Log archiving, so a backup represents a time range rather than a single instant. Backups are created when a cluster is created, when its major version is raised, and when a PITR operation runs; they are stored encrypted in an IONOS Cloud Object Storage bucket in the same region (databases in a region without Object Storage are backed up to eu-central-2). Retention defaults to 7 days and can be set from 1 to 365 days through the v2 API; reducing it purges backups older than the new window. A restore targets a non-inclusive ISO-8601 recoveryTargetTime, can use only a backup from the same or an older major version, requires the cluster to be AVAILABLE, can move the database to another region, and makes the database unavailable for the operation's duration (the service recommends at least 4 GB of RAM during a restore, scaled back afterward). Treat the default 7-day window as a deadline: if FinCorp's audit policy needs longer recoverability, raise the retention explicitly at design time rather than discover the gap during an incident.
Dump/restore is the only migration path in or out. There is no managed import wizard and no replication-based migration into the service. Moving an existing PostgreSQL database onto the platform, or off it, uses the standard logical tools pg_dump, pg_restore, and psql; for MariaDB the equivalent is mariadb-dump. The constraints follow from the private-endpoint rule: because the target cluster is reachable only from inside the VDC, the restore must run from a host on the cluster's private LAN (for example, a jump VM in the application tier), and the cutover incurs honest downtime proportional to dataset size while the dump is loaded. This is the relational entry in Unit 7.4's migration plan, where the database wave is the dump/restore wave. Plan it as a sized, scheduled operation, not a background sync.
One credential caveat carries real weight: the user credentials set at cluster creation are the only ones the create path establishes, and they are settable once. Capture them into the secret store at provisioning time, because there is no convenient reset path afterward.
DCD Implementation Walkthrough
You will now build the FinCorp relational cluster: a multi-node private PostgreSQL cluster on the existing FinCorp VDC, with a deliberate replication mode, a real maintenance window, and a private connection path into the application LAN. This realises the data-tier decision from Sections 1 to 3. The prerequisite is an existing VDC with a private LAN that the application tier already uses (the topology from Unit 3.1); the cluster will attach to that LAN with a private IP you choose to avoid the DHCP range.
Build goal: Build a multi-node private cluster with replication mode, maintenance window, and connection details.
Steps (in the Data Center Designer):
- Open Menu > Databases > PostgreSQL. The overview shows the resources allocated to your contract and how many are used; confirm there is headroom before creating the cluster.
- Click Create cluster. Provide a Cluster Name that encodes the FinCorp environment and tier, and select the Location (region) that satisfies the residency decision made back in Unit 1.4. Region is a placement decision, not something to revisit later.
- Choose the PostgreSQL version from the supported set (currently 14, 15, or 16). Selecting a current major version keeps the longest upgrade runway.
- Select the Replication mode. For FinCorp's ledger-grade workload, choose Strictly Synchronous and ensure the instance count in the next step is at least three so a single standby loss does not stop writes. For latency-sensitive, loss-tolerant services, leave it at Asynchronous. Do not select the deprecated non-strict Synchronous mode.
- Set the Backup Location (region). You can place backups in a different region from the database for off-site protection; decide this against the audit and residency requirements rather than accepting the default blindly.
- In Instance configuration, set CPUs and RAM per instance (remember the connection ceiling is derived from RAM), pick a Storage Type (HDD is the default; choose SSD or SSD Premium for the database workload, since SSD below roughly 100 GB is not recommended), and enter the Storage Size. Set the instance count so a strictly-synchronous cluster has three or more nodes.
- In Network configuration, select the Datacenter, the Datacenter LAN that the application tier uses, and a Private IP. There is no public endpoint. To find a safe private IP, note that the LAN's DHCP uses a /24, so reuse the first three octets of the application subnet and pick an address ending between .3 and .10, which DHCP never assigns, to avoid a collision.
- In Maintenance period, choose a Day and a Start Time (UTC). Pick a genuine low-traffic slot, because maintenance runs inside a 4-hour window from that start time. Leaving this effectively unconstrained invites disruptive work during business hours.
- In User Creation, set the initial Username and Password. These are the credentials the cluster is created with; capture them in the secret store immediately, since the create path is the intended place to set them.
- Create the cluster. Once it reaches AVAILABLE, connect from a host on the same private LAN using the assigned private IP or the returned DNS name on port 5432. If you later enable the managed pooler (pgbouncer), repoint clients to port 6432 and pick transaction mode unless a session-scoped feature forces session mode.
Common mistakes:
- Provisioning a strictly-synchronous cluster with fewer than three instances. With only one standby, a single standby failure stops all writes, because strict mode refuses to drop synchronous replication. Size to three or more nodes before choosing the strict mode.
- Choosing the deprecated non-strict Synchronous mode for a new cluster. Use Asynchronous or Strictly Synchronous; the middle mode does not guarantee multi-node durability under all circumstances and exists only as a legacy path.
- Assigning the cluster a private IP inside the DHCP range. Collisions break connectivity intermittently; reuse the LAN's first three octets and pick an address ending between .3 and .10.
- Setting a maintenance window during business hours, or treating it as cosmetic. Maintenance runs in a 4-hour window from the start time you choose; pick a real off-peak slot.
- Expecting standbys to serve read traffic or to be a managed read endpoint. There are no read replicas; scale reads with the In-Memory DB cache plus the pgbouncer pooler, and remember the pooler is on port 6432.
- Assuming the Backup Service or a Block Storage snapshot protects the database. Neither covers DBaaS. Database continuity is PITR (default 7-day retention, set deliberately) plus dump/restore.
- Losing the initial database credentials. They are set once on the create path with no convenient reset; store them at provisioning time.
A short client-side illustration of the two facts that bite most often, the private endpoint and the pooler port:
# Direct connection (port 5432), from a host on the cluster's private LAN
psql -h pg-xxxxxxxx.postgresql.de-fra.ionos.com -U fincorp_app -d ledger
# Through the managed pooler (transaction mode): same host, port 6432
psql -h pg-xxxxxxxx.postgresql.de-fra.ionos.com -U fincorp_app -d ledger --port=6432
Summary
The managed relational tier concentrates FinCorp's durability decisions: PostgreSQL's replication mode sets the cluster's RPO (asynchronous for low-latency, loss-tolerant work; strictly-synchronous with three or more nodes for zero committed-data loss; never the deprecated non-strict mode), while MariaDB removes the choice by being asynchronous-only. Read scaling is not done with replicas, which do not exist, but with an In-Memory cache and the pgbouncer pooler against a RAM-derived connection ceiling. Failover is automatic inside a cluster and engineered across clusters with DNS health checks. Access is private-endpoint-only, and continuity is built from PITR and dump/restore because the Backup Service does not cover databases. The DCD build then commits those choices into a real cluster.
Key Points:
- PostgreSQL replication mode is the RPO dial: Asynchronous (default) accepts a bounded loss window for latency; Strictly Synchronous loses no committed data but needs a three-node minimum and stops writes if no synchronous standby is available. The non-strict Synchronous mode is deprecated; MariaDB is asynchronous-only.
- There are no read replicas. Scale reads with the In-Memory cache plus the managed pgbouncer pooler (transaction mode default, port 6432); the connection ceiling is derived from RAM (up to 1000, minus 11 reserved) and is not configurable.
- Failover is automatic within a cluster (standby promotion); cross-cluster failover is engineered with a customer-orchestrated low-TTL Cloud DNS re-point driven by an external health check, which steers new connections only and whose TTL floor drives RTO.
- Clusters are private-endpoint-only, TLS-enforced (
prefer, not client-disablable), and must be given a private IP outside the DHCP range. - The Backup Service does not cover DBaaS. Continuity is PITR (default 7-day retention, settable 1 to 365 days) plus dump/restore (
pg_dump/pg_restore/psql, ormariadb-dump), run from a host on the cluster's private LAN; this is the migration path in and out.
Important Terminology:
- Strictly Synchronous replication: A commit is confirmed only after a synchronous standby holds it, and the primary refuses writes rather than run unprotected; guarantees zero committed-data loss at the cost of availability and per-transaction latency.
- Asynchronous replication: The primary confirms a commit on local write and replicates in the background; lowest latency, with a bounded data-loss window on failover.
- pgbouncer pooler: The managed connection pooler, configured only by pool mode (transaction or session), reached on port 6432, used to keep client connections under the RAM-derived ceiling.
- Point-in-time recovery (PITR): In-place restore to a chosen non-inclusive timestamp using base backups plus archived WAL, retained 7 days by default (1 to 365 configurable).
Further Reading
- Unit 5.5: In-Memory Database (Cache Tier) - the read-scaling and session-externalisation half of the no-read-replicas pattern.
- Unit 3.7: DNS and Failover Routing - the cross-cluster failover mechanism referenced here.
- Unit 5.7: Data Protection and Lifecycle - how PITR, dump/restore, snapshots, and Object Storage archive compose into one continuity plane.
- Unit 7.4: Migration and Hybrid Cutover - where the database wave is planned as the dump/restore wave.