IL-0566 Devsisters · 2021-03-06databaseaws
Hot ranges after a Cookie Run: Kingdom guild update drove CockroachDB nodes to 100% CPU, forcing emergency maintenance
CockroachDB stores data in units called ranges and splits or merges them on its own by size and queries per second; by default a range stays between 128MB and 512MB and below 2500 queries per second. Ranges are cut from primary keys in sorted order, so similar keys land in the same or neighbouring ranges, and a range that receives most of the workload, a hot range, leaves its few nodes carrying the whole load. In the Cookie Run: Kingdom guild update, which ended at 11:00 on 6 March 2021, the new guild tables were split in advance, but the root cause was an index prefix structure that was added and changed without the team noticing. Analytics tables written by the game server use primary keys of the form <feature>-<uuid>; they had never been split and had caused no problem since launch, because the tutorial spread players' first writes over time. The guild feature had almost no such funnel, so right after the update every player wrote huge numbers of guild-<uuid> keys before the system could split the range. In a second table, a refactoring changed the primary-key format, so only a small part of its already split ranges was used. Both tables existed before, had no schema change and took no direct gameplay traffic, so nobody expected hot ranges.
CockroachDB's load-based rebalancing could have fixed this over time, but the node added during the maintenance made CockroachDB move ranges onto it, and moving ranges uses the same queue as splitting them. The replication queue had not drained by the reopening, so the hot ranges could only be spread after the new node had received its share. From about 13:00 the team used the game's login block without kicking players as a makeshift queue, since the game had no access queue; at 14:50, when several nodes failed health checks, it put the game into full emergency maintenance, and the cluster improved at once. Because full backups stalled, the team backed up the game data table by table, with help from CockroachDB support, paused writing of play records, and from about 18:30 split the problem tables while waiting for the replication queue to reach zero. A node that failed its Host Status Check at about 19:20 and logged filemap_fdatawait_range_keep_errors was decommissioned, after which no range was under-replicated and cluster metrics returned to normal.
The game reopened around 22:00 ahead of the midnight login-bonus rush. One node reached 100% CPU, was calmed with the login-block queue, and soon did it again; because it was always the same node, the problem was most likely the node itself, and terminating it ended the incident.
- Severity
- –
- Scope
- Cookie Run: Kingdom returned errors after the guild update, new logins were blocked for periods, and the game was in emergency maintenance from 14:50 until it reopened in the evening
- Users affected
- –
- Region
- –
- Time to detect
- –
- Time to resolve
- –
Symptoms
About half an hour after the Cookie Run: Kingdom guild update maintenance ended at 11:00 on 6 March 2021, one CockroachDB node was using all 24 cores of its 24-core machine and server metrics began to show a significant number of errors. Soon two more nodes showed abnormal CPU use.
Right after the maintenance, database CPU had looked a little higher than expected, but with more players online than usual and a new interactive feature, the team judged it nothing to worry about. Once single nodes hit the ceiling, it was clear that load was not being spread evenly and that the overloaded nodes were hurting the stability of the whole database cluster.
Blocking new logins while letting players already in the game continue calmed the cluster for a while, but at 14:50 several nodes suddenly started failing health checks, more nodes than right after the maintenance. During the instability CockroachDB marked some ranges Unavailable, blocking access because it could not guarantee their consistency. A full database backup with the BACKUP statement stalled partway, and an export to CSV made the cluster less stable and was stopped.
Later, at about 19:20, a Slack alert reported that a database node had failed its Host Status Check, and the channel that watches for abnormal server logs reported filemap_fdatawait_range_keep_errors from the same instance. After the game reopened, one database node reached 100% CPU, and after it was calmed with the login block, the same node went back to 100% CPU again and again.
Root cause
Root cause Faulty deployment
- Trigger
- During the guild update maintenance, new guild tables were added and pre-split across the cluster, and a new database node was added to replace one removed a few days earlier for a physical hardware issue. When the game reopened, all players at once wrote to existing tables whose primary-key prefixes were new or had changed in the update.
Detection
Monitoring after the maintenance showed one node's CPU at the ceiling together with errors in server metrics. Later a Slack alert reported a node failing its Host Status Check, and the abnormal-log channel reported filemap_fdatawait_range_keep_errors.
Remediation
- Blocked new logins without kicking players already in the game, using the maintenance switch as a makeshift access queue
- Put the game into full emergency maintenance at 14:50 when several nodes failed health checks
- Backed up the game data table by table after the full database backup stalled
- Paused writing play records to reduce load on the database before reopening
- Split the problem tables from about 18:30
- Decommissioned the node that failed its Host Status Check
- Reopened the game and used the login-block queue again when a node reached 100% CPU
- Terminated the node that kept returning to 100% CPU
Action items
–
Lessons
In a single-server relational database a change to the primary-key prefix is usually harmless, but in CockroachDB's distributed design such a change on a production cluster needs great care. The team had studied this in CockroachDB documentation, but living through it taught far more than reading about it.
Sources
References
Related cases
IL-0356Every domain hosted on Railway returned HTTP 404 to new connections for five minutes because route lookups failedRailway · 2026same root cause · shared Database
IL-0136A deployment that cleared an internal service's caches at peak traffic sent 20 times the normal load to the Azure OpenAI metadata backend in Sweden Central, and health checks that depended on its database restarted instances in a loop for almost six hoursMicrosoft Azure · 2026same root cause · shared Database
IL-0570Dropping an unused MySQL table stalled queries on its busy parent table and crowdworks.jp was hard to reach for a minuteCrowdWorks · 2026same root cause · shared Database
IL-0510MIT Learn's RDS PostgreSQL ran out of storage after a release and learn.mit.edu returned 503s and 504s for hoursMIT Open Learning · 2026same root cause · shared Database
IL-0380A compaction change in InfluxDB Cloud us-east-1 dropped data from compacted files, and queries missed data for weeksInfluxData · 2026same root cause · shared Database
IL-0369Railway's backend API went down when a column migration waited on locks and replicas could not get database connectionsRailway · 2025same root cause · shared Database
IL-0547Buildkite annotation queries timed out and drove database CPU up across shards after a migration removed an indexBuildkite · 2025same root cause · shared Database
IL-0315Railway's backend API went down when an index build locked a billion-row Postgres table and used up every connectionRailway · 2025same root cause · shared Database
IL-0327After a blue/green upgrade of CircleCI's workflows database every query hit disk, and workflow starts lagged or failedCircleCI · 2025same root cause · shared Database
IL-0324Three MediaWiki deployments lost Memcached after a PHP 8.1 rollout and overloaded the External Storage database clusterWikimedia Foundation · 2025same root cause · shared Database
IL-0307Supabase's Postgres connection pooler Supavisor 2.0 dropped connections for about 80% of us-east-1 tenantsSupabase · 2025same root cause · shared Database
IL-0552CircleCI's archival database ran out of storage, slowing workflow and job starts and the display of workflows in the UICircleCI · 2025same root cause · shared Database
IL-0554A database migration used up Sentry US's Postgres connections, and the site and event ingestion were down for 22 minutesSentry · 2024same root cause · shared Database
IL-0571STORES reservation returned bursts of 504 errors when a smart-list query held a database process for over 20 minutesSTORES · 2024same root cause · shared Database
IL-0293Cloud Bigtable in us-central1 had higher latency and connection errors for about 32 hours from low-rate packet lossGoogle Cloud · 2023same root cause · shared Database
IL-0523TANF-app production deployments were blocked for two months when a search-index migration ran out of database disk spaceU.S. Department of Health and Human Services · 2023same root cause · shared Database
IL-0567Aurora MySQL behind Cookie Run: OvenBreak hit 100% CPU after a sales-ranking feature launch, and players could not playDevsisters · 2023same root cause · shared Database
IL-0483Replicate's website and API returned slow responses and HTTP 500s for two hours as PostgreSQL connections ran outReplicate · 2023same root cause · shared Database
IL-0371Half of new connections to Render Postgres databases with point-in-time recovery failed while their backup jobs ranRender · 2023same root cause · shared Database
IL-0524An index migration locked Open Collective's whole Transactions table and degraded the service for nearly an hourOpen Collective · 2023same root cause · shared Database
IL-0328A field type change in the database of CircleCI's job distribution service left all jobs stuck in "not running"CircleCI · 2021same root cause · shared Database
IL-0391GoCardless API requests timed out for about 15 seconds while a Postgres migration waited for an AccessExclusive lockGoCardless · 2015same root cause · shared Database
Check your cluster for this
For AI tools and scripts
- This case as JSON: https://incidentlib-api.benchlet.com/cases/IL-0566
- The cases most like it: https://incidentlib-api.benchlet.com/cases/IL-0566/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.