Graph
Cases2 cases
1 to 2 of 2
- Symptoms
On 2 September 2025 the matrix.org homeserver went down at 17:45 UTC and stayed down until 18:00 UTC the next day. Both machines of its PostgreSQL cluster were out of action: the original primary had lost its RAID array during a disk expansion, and the data directory of the new primary had been deleted by mistake.
- Trigger
During maintenance to add drives, an existing drive disappeared from the primary database server's RAID 10 array at 11:17 UTC, which led to a failover and a rebuild of that server. The outage itself began when the data directory of the new primary on db-01 was deleted while clearing a failed restore on db-02.
- Root cause
- Component
- Contributing factor
- Detection
Monitoring fired when the drive disappeared from db-02's RAID array at 11:17 UTC, and Mythic Beasts confirmed the issue. The team realised it had deleted db-01's data directory, and the backend team was then paged, an incident was opened and an emergency was declared.
- Remediation
- Created a fresh RAID 10 array on db-02
- Unblocked WAL archiving from the new primary on db-01 to S3
- Started restoring db-02 from the S3 backups with wal-g
- Shut down Synapse and the damaged primary database
- Remounted the data partition of db-01 read-only
- Copied the WALs missing from S3 from db-01 to db-02
- Updated wal-g and patched it to continue from the partial restore
- Configured a restore_command wrapper that fetched WALs from S3 and the local files, and replayed them in standby mode
- Promoted db-02 to primary and restarted Synapse
- Ran backups against the primary while no replica existed
- Rebuilt db-01 as a replica from a base backup of db-02
- Action items
- Run pg_repack to reclaim free space
- Take incremental backups more often, since they restore faster than WAL replay
- Reduce Synapse's storage requirements
- Consider changing the terminal background colour by the database's role, for example by watching for the standby.signal file
- Consider wrapper scripts around sensitive commands, such as an alias for rm, and automating operations such as starting a base backup from primary to secondary
- Shorten the recovery time, with infrastructure from service providers
- Upgrade wal-g on all servers and repeat disaster recovery testing with it
- Explore ZFS local snapshots at the next hardware refresh
- Make status.matrix.org the source of truth during incidents and keep social media updated
- Lessons
Most of the difficulty came from the size of the database: restoring 51TB and replaying WALs took far longer than hoped, and incremental backups restore much faster than WAL replay. Running a destructive command on the wrong server was the turning point, and Matrix.org looks for better tooling and processes rather than blaming the individual; working as a trio did not catch the mistake, and server names that suggest a role caused confusion because a primary and a secondary swap roles. The recovery lost no data, but the recovery time needs to be shorter, and the wal-g versions on the disaster recovery server and the production servers had drifted apart.
IL-0431During Mackerel's move to AWS, PostgreSQL failed over to a replica that had stopped replicating, losing an hour of dataHatena2017- Symptoms
On 7 August 2017, while checking the application after the maintenance that moved Mackerel from an on-premises data center to AWS, the team found that data updated during a specific time window was missing. Everything written to the PostgreSQL database between 14:30 and 15:30 JST was gone.
- Trigger
One hour after the application was switched to the newly promoted primary db001, db001 lost network connectivity and the database failed over to the standby db002.
- Root cause
- Component
- Contributing factor
- Detection
The team found the missing data while checking how the application behaved after the migration work.
- Remediation
- Tried to restore the lost updates by hand from the table data left on db001 and gave up
- Tried point-in-time recovery from the base backup and WAL and gave up
- Built a new replica db003 with db002 as primary to restore redundancy
- Kept db001 in maintenance state for investigation
- Watched db002 for some time to confirm the problem did not recur, then completed the migration
- Action items
- Change the PostgreSQL replica creation script to set recovery_target_timeline = 'latest' in recovery.conf by default
- Add a check to a server configuration test tool such as Serverspec that recovery.conf contains recovery_target_timeline = 'latest'
- Lessons
A setting needed only for a rare layout, such as a grandchild replica during a migration, was applied by hand through a script option and was forgotten. Because recovery_target_timeline = 'latest' is harmless on ordinary standbys too, Hatena now sets it by default whenever a replica is created. The staging rehearsal used the same layout and steps but had the setting right, so it could not catch the mistake. Hatena notes that a similar layout may be used again for a future PostgreSQL upgrade or a move to another region.
These 2 cases involve Database and Database replication. kubegap audits a Kubernetes cluster for gaps like these, read-only, from Claude Code or Codex; its checks cite public reports like the ones in this library.
By root cause1
Operator error2 cases
- Contributing factor
- Organisation