Chapter 15 · Group Replication, InnoDB Cluster, Router, and High Availability

Failure Injection, Split-Brain Avoidance, Maintenance, Upgrades, and HA Acceptance Tests

Turn high availability into an acceptance-tested runbook: inject node, primary, Router, and network failures; preserve quorum and fencing; validate data correctness; and gate maintenance/upgrades on reversible preflight evidence.

Advanced180–240 minHA acceptance + maintenance drillMySQL Server/Shell/Router 8.4.10 LTSHA / operationsLast reviewed: August 2026

Learning outcomes

High availability cannot be accepted from a diagram. The ServiceHub team needs evidence for what happens when one member dies, the primary dies, Router restarts, a network partition removes quorum, or maintenance changes versions/configuration. This lesson turns those scenarios into an acceptance matrix with explicit safety gates and stop conditions.

01

Create an HA acceptance matrix covering single-member loss, primary loss, Router restart, network isolation, and planned maintenance.

02

Use quorum, fencing, AdminAPI status, GTID/member evidence, Router reconnect behavior, and business invariants as separate acceptance dimensions.

03

Distinguish automatic recoverable failures from conditions requiring operator intervention, reprovisioning, or force-quorum procedures.

04

Apply preflight/canary/rollback thinking to Group Replication and InnoDB Cluster maintenance and upgrades.

05

Finish the lab with a written production runbook that protects correctness before availability.

Define acceptance before injecting failure

A failure test without acceptance criteria becomes theater: the operator kills a process, sees something reconnect, and declares success. Instead define what must remain true. For ServiceHub, the most important invariant is that each committed work-order command has exactly one durable business outcome and there is never more than one writable authority after partition/failover.

Declared lab baseline

Mandatory labs target MySQL Community Server 8.4.10 LTS, MySQL Shell 8.4.10 LTS, and—where routing is required—MySQL Router 8.4.10 LTS. The examples use three disposable members because a three-member group can retain majority after one member fails. All data and credentials are lab-only.

ScenarioExpected automatic behaviorCorrectness evidenceOperator action
one secondary lostcluster remains available with two-member majorityremaining members ONLINE; GTID/business state intactrepair/rejoin before another failure
primary lostremaining majority elects a primaryone writable primary; committed marker visible after reconnectreconnect application; rejoin/rebuild failed member
Router process lostdatabase cluster remains healthy; that Router endpoint is unavailablecluster status unaffectedclient fails over to another Router/service endpoint; restart Router
majority network partitionminority must not continue writesno independent writable historiesrestore network or fence/force quorum under runbook
planned maintenancecontrolled member-by-member workquorum preserved; version/GTID/schema checks passstop if compatibility or backlog gates fail

Acceptance marker: a business invariant you can verify everywhere

sql · SQL — create an idempotent HA test ledger on the primary
CREATE DATABASE IF NOT EXISTS servicehub_ha_acceptance;CREATE TABLE IF NOT EXISTS servicehub_ha_acceptance.commands (  command_id CHAR(36) PRIMARY KEY,  command_type VARCHAR(40) NOT NULL,  payload_hash CHAR(64) NOT NULL,  created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),  UNIQUE KEY uq_payload(command_type,payload_hash)) ENGINE=InnoDB;INSERT INTO servicehub_ha_acceptance.commands(command_id,command_type,payload_hash)VALUES(UUID(),'HA_BASELINE',SHA2('servicehub-ha-baseline',256));SELECT COUNT(*) AS baseline_rows,       COUNT(DISTINCT command_id) AS distinct_commandsFROM servicehub_ha_acceptance.commands;

The primary key and business uniqueness constraint make duplicate acceptance visible. During failover tests, use a new UUID and deterministic payload hash so a retry can distinguish “already committed” from “never committed.” This is much stronger than checking only whether SELECT 1 succeeds.

Test 1: single secondary loss

text · shell + MySQL Shell — degrade and recover
docker stop servicehub-ha-db3# MySQL Shell on a surviving member:cluster.status({extended:2})# Verify writes still work through Router RW endpoint, then recover:docker start servicehub-ha-db3cluster.rejoinInstance('icadmin@127.0.0.1:33153')cluster.status({extended:2})

Acceptance is not merely “the INSERT worked.” The cluster must show a two-member majority during the failure, the recovered member must return ONLINE, and business rows/GTID history must converge. Record how long the cluster ran with reduced fault tolerance; alerting should make that degraded window operationally visible.

Test 2: unexpected primary loss

First identify the current primary. Open a Router client, insert a uniquely keyed command, then stop the primary container. Watch Group Replication elect a replacement and Router route a new connection. Do not reuse the broken session as proof of transparent failover.

javascript · MySQL Shell — identify the writer before failure
cluster.status({extended:2})
sql · SQL via Router — committed pre-failure marker
SET @cmd = UUID();INSERT INTO servicehub_ha_acceptance.commands(command_id,command_type,payload_hash)VALUES (@cmd,'PRIMARY_FAILOVER',SHA2(CONCAT('before-',@cmd),256));SELECT @cmd AS committed_command_id, @@hostname AS backend;
text · shell — stop the actual current primary container
# Example only; choose the container that cluster.status() reports as primary.docker stop servicehub-ha-db1# Then inspect election from a surviving member.cluster.status({extended:2})

Reconnect through Router and query the recorded command. If the write committed before failure, it must exist exactly once. If the connection disappeared during commit in a different test, use the command ID to resolve the ambiguity before retrying.

Test 3: Router loss must not become database loss

If you deploy only one Router, the database can be healthy while the application endpoint is down. That is a middleware single point of failure. Stop the disposable Router process and verify that direct cluster health remains OK. In production, applications normally need multiple Router instances or a service layer that can reach another Router.

text · shell — Router failure boundary
# Stop the disposable Router process/service.# Exact command depends on how the bootstrap directory/service was started.# Then verify cluster status independently in MySQL Shell:cluster.status({extended:2})# Restart Router and reconnect through its configured read/write endpoint.

Test 4: network isolation and split-brain avoidance

A partition that leaves one member isolated from the other two is different from a process crash: all machines may still be alive. The majority side can continue; the isolated minority cannot safely act as an independent group. A more severe partition may leave only a minority reachable to the application site, in which case the safe service can become unavailable.

Do not execute force quorum as a reflex

Before forceQuorumUsingPartitionOf(), fence excluded members at the application/network/process layer and prove they cannot accept writes. Decide which partition owns the authoritative history. Record possible data loss. After quorum is forced, reprovision/rejoin excluded members under the recovery plan; never simply reconnect two formerly writable partitions.

Partition decisionProceed only if
wait for network repairservice can tolerate temporary unavailability and no emergency reconfiguration is needed
force quorum around surviving partitionexcluded side is fenced; authoritative partition chosen; GTID/business state captured; risk accepted
abandon/rebuild a memberits history is incompatible or cannot be trusted
escalate to incident commanderstate is ambiguous, two sides may have accepted writes, or fencing cannot be proven

Planned maintenance: preserve quorum and reversibility

Maintenance is the best time to practice disciplined failover because the failure is scheduled. Work one member at a time. Before touching a node, check cluster status, application error budget, transaction queues, backup/recovery readiness, and version compatibility. After each step, wait for the member to return ONLINE and catch up before touching the next member.

javascript · MySQL Shell — preflight evidence before each member
cluster.status({extended:3})cluster.options({all:true})// Also record server versions and Group Replication member versions from SQL.
sql · SQL — version and member state gate
SELECT MEMBER_HOST,MEMBER_PORT,MEMBER_STATE,MEMBER_ROLE,MEMBER_VERSIONFROM performance_schema.replication_group_members;SELECT @@version, @@version_comment, @@global.gtid_executed;

Mixed-version operation during a rolling upgrade is subject to version-compatibility rules. Do not infer that “newer can always join older” or vice versa. Check the current release's Group Replication upgrade documentation immediately before maintenance.

Compatibility/lock-risk failure: detect before changing the cluster

The prompt requires a failure caught during preflight/canary validation. A realistic example is a schema change that needs a long metadata lock while a production transaction is holding the table. Instead of launching the DDL cluster-wide during maintenance, test on a canary workload, inspect lock behavior, and use an expand/contract migration if the blocking window violates the maintenance objective.

sql · Session A — hold a disposable transaction
START TRANSACTION;SELECT * FROM servicehub_ha_acceptance.commandsWHERE command_type='HA_BASELINE'FOR UPDATE;-- Keep open briefly for the canary test.
sql · Session B — demonstrate a lock-sensitive change, then cancel
-- In the disposable lab only:ALTER TABLE servicehub_ha_acceptance.commands  ADD COLUMN operator_note VARCHAR(100) NULL;-- If this waits beyond the canary budget, cancel/rollback the test rather than-- forcing production through the same blocking window.

A reversible alternative is expand/contract: add a nullable/backward-compatible structure during one deployment, update application writers/readers gradually, backfill in bounded work, verify, then remove the old contract later. The exact method depends on the schema change; the principle is to avoid coupling “upgrade” to one irreversible blocking event.

Complete outage is not quorum loss

If Group Replication has stopped on all members after a major outage, the recovery problem is different from one surviving minority partition. MySQL Shell provides dba.rebootClusterFromCompleteOutage(). The operator should connect to the most appropriate up-to-date member, compare GTID/state where possible, and avoid the force option unless the documented risk is understood. An outage runbook should never treat “pick any node and bootstrap it” as acceptable.

javascript · MySQL Shell — syntax reference, not a routine command
// Only after a real complete outage and state review:var cluster = dba.rebootClusterFromCompleteOutage('ServiceHubHA')cluster.status({extended:2})

Final HA acceptance matrix

GatePass condition
Membershipexpected members ONLINE; degraded members explicitly accounted for
Quorummajority preserved for normal service; no force operation without fencing evidence
Write ownershipexactly one writable primary in single-primary design
Routernew connections reach eligible role after topology change
Applicationbroken/ambiguous transactions handled with reconnect + idempotency verification
Correctnessbusiness invariants and unique command markers hold after failover/rejoin
RecoverabilityChapter 13 backup/PITR remains independently tested
Maintenanceversion/schema/config preflight passes; rollback/expand-contract path documented
Observabilityalerts distinguish node loss, quorum loss, Router loss, backlog/recovery, and application errors

Production judgment and bridge to Chapter 16

High availability is a system of mechanisms and operating decisions: Group Replication protects distributed write ownership with quorum/certification; InnoDB Cluster provides a supported lifecycle control plane; Router provides metadata-aware client routing; the application owns reconnect, retry, idempotency, and user-facing behavior; backup/PITR protects against failures that replication faithfully copies.

The next chapter makes these mechanisms observable in normal operation. Chapter 16 moves into Performance Schema, the sys schema, logs, metrics, and dashboards so operators can detect the precursor signals—queue growth, connection pressure, waits, I/O, memory, and errors—before every problem becomes a failover drill.

Knowledge check

  1. Why is “the new primary accepts SELECT 1” insufficient as a failover acceptance test?
  2. What should happen to an isolated minority partition?
  3. Why can a single Router still be a single point of failure even with a healthy three-node cluster?
  4. What is the safe order for rolling member maintenance?
  5. When is rebootClusterFromCompleteOutage() conceptually different from forceQuorumUsingPartitionOf()?
Reveal answers
  1. It proves connectivity only. You also need one-writer ownership, quorum/member state, Router/application reconnect, GTID/data correctness, and business invariants.
  2. It must not independently create a writable history; quorum rules intentionally prevent unsafe progress.
  3. The database may remain available while the sole middleware endpoint is down; multiple Router/service endpoints are needed for end-to-end HA.
  4. Preflight; maintain one member; return it ONLINE/caught up and verify; only then proceed to another member, preserving majority throughout.
  5. Reboot-after-outage reconstructs a cluster when Group Replication is stopped across the deployment; force quorum redefines membership around a surviving partition after quorum loss and therefore carries explicit split-brain/fencing risk.

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.