IL-0331 Razorpay · 2020-06-08 (published)databaseaws
An RDS MySQL Multi-AZ failover lost 5 seconds of committed data and broke replication on all five read replicas
In an RDS Multi-AZ setup, the RDS endpoint points to a primary instance and a standby in another availability zone keeps MySQL shut down while the primary's EBS volume is copied synchronously to the standby's EBS volume. On failover, networking on the primary is cut, MySQL starts on the standby, the endpoint switches to it and the application reconnects; the old primary is then hard-rebooted onto a new host and EBS sync starts toward the new standby. Data reaches the standby only once it is on the primary's EBS volume. Razorpay had set innodb_flush_log_at_trx_commit to 2, so the InnoDB log was written at every commit but flushed to disk only once a second; the RDS default of 1, which flushes at every commit, is required for full ACID compliance. sync_binlog was set to 1, so every commit was flushed to the binary log at once.
When the master failed over in December 2019, transactions from the last 5 seconds had been committed and written to the binary log but not flushed to the primary's EBS volume, so the new primary never had them. The five read replicas had already applied those rows from the binary log. The application then wrote new rows on the new primary and reused auto-increment ids such as X+1 that the replicas already held, and replication on every replica stopped on duplicate-key errors. Razorpay moved replica traffic to the master and recreated all five replicas, waiting six hours for the first, full snapshot from the new machine.
The next day, trace logs showed records missing from the database. Razorpay pulled the exact queries from the binary logs, followed the sequence of events in the application trace logs and corrected the data in RDS after an 8-hour meeting. After a week of calls with RDS solution architects, snapshots kept from the old replicas confirmed that the lost data had been on the replicas, and innodb_flush_log_at_trx_commit on the master was changed from 2 to 1.
- Severity
- –
- Scope
- The API application could not reach its RDS MySQL database for about 110 seconds and returned 5xx errors; replication failed on all five read replicas, whose traffic ran on the master for about six hours; about 5 seconds of transactional data were missing from RDS until corrected by hand
- Users affected
- –
- Region
- –
- Time to detect
- –
- Time to resolve
- –
Symptoms
On a Friday evening in December 2019, Razorpay's internal monitoring alerted on an unusually high number of 5xx errors. The SRE team found that the main application, called API, could not connect to its RDS MySQL database, but within about 110 seconds the application recovered by itself and the alerts stopped. The RDS logs showed that the master instance had gone through a Multi-AZ failover.
Right after the application recovered, a second set of alerts reported that replication had failed on all five read replicas of the API master, each with a duplicate-key error. To keep stale or wrong data away from users, all replica traffic was moved to the master, whose CPU load rose by 50% because the heavier selects now ran there too.
Recreating the replicas starts from a snapshot of the master. Incremental snapshots of the API database had taken about 15-20 minutes before, but this one was still running after about an hour. AWS support explained that the failover had replaced the old master with a new machine, so the first snapshot from it was a full snapshot; it took six hours.
The next day, AWS support said replication does not usually crash during a Multi-AZ failover. Comparing the database with the application trace logs, Razorpay found records that were in the trace logs but not in the database: about 5 seconds of data, just before the 5xx errors began, were missing from RDS.
Root cause
Root cause Configuration change
- Trigger
- The master instance of the API application's RDS MySQL database went through a Multi-AZ failover to its standby in another availability zone.
Detection
An internal monitoring alert on unusually high 5xx errors, then alerts that replication had failed on all replicas. The data loss was found the next day by matching the database against the application trace logs.
Remediation
- Moved all read replica traffic to the master instance
- Recreated all five read replicas after a six-hour full snapshot and moved traffic back to them
- Recovered the missing queries from the binary logs and corrected the data stored in RDS
- Changed innodb_flush_log_at_trx_commit on the master from 2 to 1
Action items
–
Lessons
With innodb_flush_log_at_trx_commit set to 2, Razorpay had been open to data loss on any failover all along, even though RDS Multi-AZ copies everything on the primary's disk to the standby. The incident also taught the team how RDS runs a Multi-AZ setup and its failovers.
Sources
Related cases
IL-0325DigitalOcean's control panel and API were down for 4 hours 56 minutes after the production primary database was deletedDigitalOcean · 2017same root cause · shared Database replication, Database backups and snapshots, Database
IL-0392MariaDB replication of section x1 between eqiad and codfw broke on a missing heartbeat row during a cookbook runWikimedia Foundation · 2024same root cause · shared Database replication, Database
IL-0574Aurora MySQL writer CPU stuck near 100% minutes after Safie pointed production at a new Amazon RDS ProxySafie · 2026same root cause · shared Database
IL-0366Cloud Storage uploads and writes in us-central1 slowed and failed with HTTP 503 as traffic piled onto a few backendsGoogle Cloud · 2026same root cause · shared Database
IL-0179With DEBUG logging and synchronous log output, a high-traffic service filled the 64 KB stdout pipe, so request threads blocked in write() while holding database connections and HikariCP ran dry, failing requests in 30-second burstsMUSINSA · 2026same root cause · shared Database
IL-0561DigitalOcean's Cloud Control Panel and Public API returned up to 25% errors in two windows as authorization timed outDigitalOcean · 2026same root cause · shared Database
IL-0487Autumn's Postgres CPU spiked and about 10% of API requests failed after a collation change left the main query unindexedAutumn · 2026same root cause · shared Database
IL-0283Cloudflare's core proxy returned HTTP 5xx across its network after loading an oversized Bot Management feature fileCloudflare · 2025same root cause · shared Database
IL-0528Cloud Pub/Sub could not publish or subscribe in ten regions, and some ordered subscriptions stayed stuck for hoursGoogle Cloud · 2025same root cause · shared Database
IL-0374DigitalOcean creates and management actions failed globally when its service discovery datastore lost quorumDigitalOcean · 2024same root cause · shared Database replication
IL-0367Azure Storage in Central US rejected VM disk I/O, taking down VMs and the SQL Database and Cosmos DB services on themMicrosoft Azure · 2024same root cause · shared Database
IL-0511MIT xPro stopped responding after a configuration deploy as pgbouncer logins to RDS failed with 'wrong password type'MIT Open Learning · 2023same root cause · shared Database
IL-0272New Cassandra nodes served reads for data they did not hold, so Monzo records looked missing and payments failedMonzo · 2019same root cause · shared Database
IL-0430Mackerel's Redis stopped answering during a replication setup, keepalived failed over by mistake, and Mackerel degradedHatena · 2018same root cause · shared Database replication
IL-0292App Engine Memcache was down in all regions for 1 hour 50 minutes when its global datacenter mapping could not be readGoogle Cloud · 2017same root cause · shared Database
IL-0215Twilio's billing Redis master lost all balances and went read-only, and auto-recharge charged customer cards repeatedlyTwilio · 2013same root cause · shared Database replication
Check your cluster for this
For AI tools and scripts
- This case as JSON: https://incidentlib-api.benchlet.com/cases/IL-0331
- The cases most like it: https://incidentlib-api.benchlet.com/cases/IL-0331/similar
- MCP server (Streamable HTTP, no key):
https://incidentlib-mcp.benchlet.com/mcp
The API needs no key. The MCP server offers search_incidents, get_incident, list_incidents, get_topic and vocab; both are explained on API and MCP.