Chapter 22 · Production Capstone: Design, Cluster, Secure, Tune, and Recover MariaDB

Run Restore, Failover, Split-Brain, Performance, and Corruption Drills—and Defend the Design

Inject safe failures into the disposable capstone, measure detection and recovery, prove data correctness, exercise restore/failover/divergence/load/configuration drills, and defend the final MariaDB operating model with prioritized next improvements.

Advanced capstone270–360 minutesproduction game-day and design defenseMariaDB Community 12.3.2 current GA referenceCurriculum anchor: MariaDB 11.8 LTS · verify source/target/tool/topology versionsFree local tooling · Last reviewed: August 2026

Learning outcomes

The final lesson is a production game-day. Every failure is injected only into the disposable capstone, and every drill has four outputs: detection time, recovery time, data-correctness evidence, and the SLO/RPO/RTO result. The design is accepted only to the extent the evidence supports it.

01

Run process/node-loss and async failover drills with explicit fencing and client pool refresh.

02

Create and detect divergent writes during an isolated replica partition, then recover by choosing one authority and rebuilding rather than merging blindly.

03

Exercise blocked transactions, accidental DML, backup corruption/missing components, configuration failure and load spikes safely.

04

Record RPO/RTO and correctness using checksums, invariants, GTID/binlog evidence and application outcomes.

05

Defend the final architecture, name residual risks and prioritize the next evidence-driven improvements.

Safety boundary

Do not execute network partitions, process kills, datadir changes, backup-file corruption or conflicting writes against production. The commands below assume the disposable local capstone topology from Lesson 4 or an equivalent isolated environment.

1. Build a game-day scorecard before breaking anything

text · drill-result.csv schema
drill_id,start_utc,detected_utc,recovered_utc,target_rpo_s,target_rto_s,actual_data_loss_s,actual_recovery_s,correctness_pass,slo_pass,evidence_uri,notesRules:  start/detected/recovered use one synchronized clock source  “correctness_pass” requires named invariants, not “site loads”  preserve logs/status/GTID/checksum evidence before cleanup  failure that exceeds target is useful evidence, not a reason to hide the run

Detection time is separate from recovery time. A system that recovers in one minute after an operator notices the problem 40 minutes later does not meet a 30-minute RTO from user impact.

2. Drill A — process/node loss and controlled async failover

text · topology assumptions
primary: writable authority, server_id=221replica: read_only=ON, server_id=222, GTID replication healthyapplication: write endpoint points only to primaryprecondition: SHOW REPLICA STATUS confirms candidate has applied the test transactionbackup/PITR: independent recovery path still exists
terminal · disposable container example
# Record evidence before failure.docker compose exec replica mariadb -uroot -pdisposable-root   -e "SHOW REPLICA STATUS\G"# Kill only the disposable primary.docker compose stop primary# Do NOT route writes yet. First record replica state and fence/confirm old primary is stopped.docker compose exec replica mariadb -uroot -pdisposable-root   -e "SELECT @@server_id,@@read_only,@@global.gtid_slave_pos,@@global.gtid_binlog_pos;"# Promote the chosen replica only after the old writer is fenced.docker compose exec replica mariadb -uroot -pdisposable-root   -e "STOP REPLICA; SET GLOBAL read_only=OFF;"# Refresh/recreate application pools so no stale connections point at the dead writer.

The exact production promotion procedure depends on topology, GTID state, routing and MariaDB version. The learning invariant is universal: fence first, prove candidate state, then route. Do not erase replication metadata immediately; it is incident evidence and may be needed for rejoin planning.

3. Drill B — network partition and deliberate divergent writes

Async replication has no quorum mechanism that automatically prevents both sides from being made writable. This drill demonstrates the “split-brain” risk created by operator/routing error.

terminal · isolate the disposable replica
# Recreate/reset the original primary+replica topology before this drill.docker network disconnect servicehub22_net servicehub22-replica# On the isolated replica ONLY, deliberately remove the guardrail for the exercise:docker exec servicehub22-replica mariadb -uroot -pdisposable-root   -e "SET GLOBAL read_only=OFF; INSERT INTO servicehub22.outbox_event(tenant_id,aggregate_type,aggregate_id,event_type,payload) VALUES(1,'ticket',5001,'WRONG_SIDE_WRITE','{}');"# Independently write a different event on the real primary.docker compose exec primary mariadb -uroot -pdisposable-root   -e "INSERT INTO servicehub22.outbox_event(tenant_id,aggregate_type,aggregate_id,event_type,payload) VALUES(1,'ticket',5001,'PRIMARY_WRITE','{}');"# Reconnect network only after collecting GTID/data evidence.docker network connect servicehub22_net servicehub22-replica

Do not try to “merge GTIDs until green.” Two writable histories now exist. Choose the authoritative history according to the incident decision, preserve evidence, and rebuild the non-authoritative node from a trusted seed/backup. The drill justifies fencing and routing controls far better than a diagram does.

4. Drill C — blocked transaction and lock storm diagnosis

sql · Session A
USE servicehub22;START TRANSACTION;UPDATE ticket SET subject='held by drill A'WHERE tenant_id=1 AND ticket_id=5001;-- Keep the transaction open temporarily; do not COMMIT yet.
sql · Session B
SET SESSION innodb_lock_wait_timeout=10;UPDATE servicehub22.ticket SET priority=5WHERE tenant_id=1 AND ticket_id=5001;
sql · Observer session
SHOW PROCESSLIST;SELECT * FROM information_schema.INNODB_TRX\GSHOW ENGINE INNODB STATUS\G

The repair is to identify the blocking transaction and business operation, then choose whether to commit/rollback/terminate it. Randomly killing waiters treats the symptom. End the drill with ROLLBACK in Session A and verify Session B’s outcome.

5. Drill D — accidental DML and PITR boundary

sql · mark the destructive event
SELECT NOW(6) AS before_bad_delete;SELECT COUNT(*) AS before_count FROM servicehub22.ticket WHERE tenant_id=1;-- Disposable incident injection.DELETE FROM servicehub22.ticketWHERE tenant_id=1 AND status='CLOSED';SELECT NOW(6) AS after_bad_delete;SELECT COUNT(*) AS after_count FROM servicehub22.ticket WHERE tenant_id=1;

Do not “undo” by guessing which rows existed. Use the Lesson 4 backup + retained binlogs to restore an isolated target and replay only to the transaction boundary before the destructive commit. Compare counts and named business rows. After proving recovery, decide whether production recovery would be full restore, selective logical extraction, or another controlled method.

6. Drill E — detect a corrupt/missing backup component without destroying the good copy

terminal · checksum a copy, then damage only the copy
cp -a /tmp/capstone22-full /tmp/capstone22-brokenfind /tmp/capstone22-full -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/capstone22-full.sha256# Damage one disposable copy. Choose an ordinary data file inside the copied backup.TARGET=$(find /tmp/capstone22-broken -type f -name '*.ibd' | head -n 1)printf 'broken' > "$TARGET"# A manifest built for the GOOD tree can be adapted to compare paths, or generate paired manifests.find /tmp/capstone22-broken -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/capstone22-broken.sha256diff -u /tmp/capstone22-full.sha256 /tmp/capstone22-broken.sha256 || true# Never use the broken copy for recovery. Preserve it only as drill evidence, then delete it.

Cryptographic checksums detect change; they do not prove semantic restorability. The stronger control is checksum + prepare/restore + database-level invariant checks.

7. Drill F — configuration failure and startup evidence

terminal · ephemeral invalid-option container
# No production config file is edited.docker run --rm --name mariadb22-bad-config   -e MARIADB_ROOT_PASSWORD=disposable-root   mariadb:12.3.2   --definitely-not-a-real-option=1# Expected: server startup fails and logs identify an unknown/invalid option.# Capture the exit code and logs as evidence.

The lesson from a config failure is not merely “fix the typo.” Production change should have syntax/startup validation, canary rollout, previous config retention and a rollback path that does not require discovering the old value during outage.

8. Drill G — load spike and SLO/headroom result

terminal · reuse the Lesson 3 benchmark
# Baseline first; then increase only one demand variable.CONCURRENCY=8  ITERATIONS=100 node bench.mjs  > baseline.jsonCONCURRENCY=32 ITERATIONS=100 node bench.mjs  > spike.json# Capture server/OS evidence over the same windows.# Do not claim 32 is “high” universally; it is just this drill's demand multiplier.

Record whether throughput rises, flattens or falls while p95/p99 and errors change. The capacity knee is workload/hardware-specific. Headroom policy should keep expected bursts away from the region where latency accelerates and errors begin.

9. Correctness verification after every drill

sql · minimum capstone invariants
-- No cross-tenant foreign-key violations can exist if constraints are intact.SELECT COUNT(*) AS tickets_missing_customerFROM servicehub22.ticket tLEFT JOIN servicehub22.customer c  ON c.tenant_id=t.tenant_id AND c.customer_id=t.customer_idWHERE c.customer_id IS NULL;SELECT COUNT(*) AS comments_missing_ticketFROM servicehub22.ticket_comment cLEFT JOIN servicehub22.ticket t  ON t.tenant_id=c.tenant_id AND t.ticket_id=c.ticket_idWHERE t.ticket_id IS NULL;-- Record selected business counts and checksums appropriate to your dataset.SELECT tenant_id,status,COUNT(*)FROM servicehub22.ticketGROUP BY tenant_id,statusORDER BY tenant_id,status;CHECKSUM TABLE servicehub22.tenant,               servicehub22.customer,               servicehub22.ticket,               servicehub22.ticket_comment;

CHECKSUM TABLE is supplementary evidence, not a universal cross-version/cross-engine business-proof mechanism. Application invariants and source-of-truth comparisons are still required.

10. Defend the design: evidence, residual risk, next improvements

Decision Evidence earned in capstone Residual risk / revisit trigger
InnoDB relational model FK/check/index tests + transaction workload schema growth and tenant skew may require lifecycle redesign
Async GTID replica lag/breakage/failover drill possible data-loss window; external fencing/routing remains required
Physical backup + binlog PITR prepare/restore/replay drill retention, offsite failure domain and restore automation need continuous testing
Least privilege + TLS contract grants + TLS/session checks secret rotation/certificate lifecycle are operational dependencies
Evidence-driven tuning repeatable before/after benchmark future workload shape may invalidate current index/config choices
Upgrade gate version/config/backup/canary checklist downgrade may require restore/rebuild; plugin/topology compatibility evolves
text · final design defense template
1. Workload and SLOs   exact user journeys, percentiles, availability, RPO/RTO, growth, retention2. Data correctness   schema invariants, tenant isolation, transactions, idempotency3. Capacity/performance   representative workload, bottleneck evidence, headroom and triggers4. Security   identities/roles, TLS verification, secrets, admin separation5. HA vs DR   write authority, replica/Galera choice, fencing/routing, backups/PITR6. Observability   user-impact signals, DB/OS evidence, alert thresholds and ownership7. Change management   migrations, config inventory, upgrade gate, canary, rollback boundary8. Game-day results   each drill's detection, RPO, RTO, correctness and failed assumptions9. Residual risks   what is consciously NOT solved10. Next 90-day priorities   highest risk-reduction work with measurable exit criteria

11. Final checks and course completion

Check your reasoning

  1. Why rebuild the non-authoritative node after divergent async writes?
  2. Why record detection time separately from recovery time?
  3. What does a successful checksum fail to prove?
  4. Why is a failed drill valuable?
  5. What is the capstone’s central operating principle?
Review the answers
  1. Because two independent histories exist; forcing replication “green” can hide lost/conflicting data. Choose one authority and reseed the other from trusted state.

  2. RTO is experienced from impact; slow detection can violate it even when the technical repair itself is fast.

  3. That all business invariants are correct, that the chosen recovery point is right, or that every application-visible row is semantically correct.

  4. It reveals that an architecture assumption or runbook does not meet the stated SLO/RPO/RTO, creating actionable evidence before a real incident.

  5. Define a measurable contract, observe actual state, change one thing deliberately, verify recovery/correctness, and keep residual risk explicit.

Course complete

You now have the pieces of a MariaDB production operating model: architecture record, schema and privileges, application contract, evidence-driven tuning, backup/PITR, HA, observability, upgrade gates and failure-drill results. Production readiness is not permanent; schedule recurring restore, failover, performance and upgrade rehearsals as the workload and MariaDB release state change.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.