Cases3 cases
1 to 3 of 3
IL-0572About 10 million Pub/Sub messages backed up and Merpay accounting data was not written to Cloud Spanner for over a dayMercari2026- Symptoms
From about 6:00 on the last business day of a month, Cloud Pub/Sub messages of the Merpay accounting event pipeline began to back up, new accounting data stopped being registered in Cloud Spanner, and the accounting system intermittently could not accept new data. The backlog grew to about 10 million messages.
- Trigger
More than a month earlier the Cloud Functions of the pipeline had been moved from 1st gen to 2nd gen (based on Cloud Run) without setting --max-instances in the deploy command, which lowered the scale limit from effectively unlimited, the 1st gen default, to 100, the 2nd gen default. The month-end peak, which on that day continued for about 40 minutes, reached that limit.
- Root cause
- Component
- Contributing factor
- Remediation
- Re-ingested the messages saved to GCS by the Dataflow subscription, avoiding data loss
- Action items
- Set max-instances and the other scaling parameters of Cloud Run explicitly in the deploy definition, raising max-instances from 100 to 1000 in steps
- Set min-instances to 1 to avoid cold starts, raise concurrency from 1 to 10, and set CPU to 1 and memory from 512MB to 1Gi
- Use the dual CPU scaling mode of spanner-autoscaler v0.8.0 with a new Total CPU threshold of 70%
- Lower the High priority CPU threshold from 60% to 55% so scale-up starts earlier
- Forbid Spanner scale-down between 5:00 and 7:00
- Reserve Spanner processing units on a schedule for periods with predictable load
- Alert in Datadog when the Cloud Run instance count reaches 40% and 60% of its limit
- Alert in Datadog when undelivered Pub/Sub messages exceed a threshold, lowering it step by step
- Lessons
When moving to a new generation of a managed service, defaults that the team never changed can surface as problems under load, so parameters that only matter at peak, such as scale limits, concurrency and timeouts, should be set explicitly at every migration. An outage rarely has one cause; the fact that the previous month passed under the same conditions pointed to traffic continuity, and prevention needs to look at the trigger, the amplification and what turned it into damage. Capacity settings and the monitoring that shows when they are approached have to be designed together, and teams that run systems they inherited should review these settings and assumptions regularly.
IL-0288ZooKeeperWait rose to thousands of seconds on three redundant ClickHouse instances, degrading a CDN77 data pipelineCDN772026- Symptoms
At 13:30 UTC on 9 March 2026, CDN77's data team was alerted to a sudden rise in the ZooKeeperWait metric on the ClickHouse cluster behind one of its large data pipelines. Alerting for this cluster size is set at 10 sec for the low watermark and 20 sec for the high one, and the metric reached thousands of seconds. The same rise appeared on three symmetrically redundant ClickHouse instances in different datacenters, each with its own ZooKeeper instance, and the pipeline stayed degraded for over an hour, with no observable impact on internal users, customers or partners.
- Trigger
From 13:15 UTC two client machines that had been cut off from the network for several months came back and their log shippers sent months of queued, very small batches of health check data with old timestamps, spanning a very large time range.
- Root cause
- Component
- Contributing factor
- Detection
An alert on the ZooKeeperWait metric fired at 13:30 UTC, fifteen minutes after the problematic inserts began at 13:15. The cluster's alerting uses a low watermark of 10 sec and a high watermark of 20 sec.
- Remediation
- Dropped and recreated the one table partitioned by 5 minutes that had not cleared its backlog of parts
- Broadened that table's partitioning from minutes to hours
- Action items
- Reject out-of-range timestamps in the root MaterializedView tables
- Record statistics on rejected rows in a second materialized view
- Refine the deliberately wide rejection boundaries as data on rejections comes in
- Keep a minimal test scenario with an insert query whose timestamps span days or months
- Make a range of observability improvements
- Lessons
Data structure matters even in a pipeline built around volume: incoherent timestamps can destabilise it as effectively as changes in cardinality. A metric that looks odd and cannot be explained at once should not be set aside under incident pressure; the falling mean insert size was what led to the cause. Means and medians each have their place, and here the mean, not the median, exposed the problem. Partitioning has to be chosen carefully: too few partitions give oversized parts, slow mutations and costly or ineffective TTL, while too many slow column scans, add final merging to aggregating queries and overload the Keeper.
IL-0582Jobs piled up in Kanmu's PostgreSQL-based qg job queue on Aurora as dequeue slowed and dead tuples kept growingKanmu2024- Symptoms
A Datadog alert fired because a large number of unprocessed jobs had piled up in Kanmu's job queue and were not being worked off. The jobs were the batch enqueued at about the same time every day, in the usual volume, but the workers took far longer than normal to dequeue and process them.
- Trigger
A heavy ad hoc analysis query from the BI tool Redash ran for a long time on the writer instance, because the Redash data source pointed at the cluster endpoint.
- Root cause
- Component
- Contributing factor
- Detection
A Datadog alert on unprocessed jobs piling up in the job queue.
- Remediation
- Changed the Redash data source to the reader endpoint
- Ended the long-running Redash query with pg_terminate_backend
- Ran VACUUM on que_jobs by hand again, which cleaned up the dead tuples
- Action items
- Make Redash unable to connect to the writer instance even if the writer endpoint is set, by mapping its host name to a TEST-NET-1 address in the Redash container's /etc/hosts
- Set statement_timeout on PostgreSQL users so that long queries stop automatically
- Consider improving qg's dequeue algorithm or adopting a job queue such as river that uses SELECT FOR UPDATE SKIP LOCKED
- Lessons
A long-running query on the same database instance, even one unrelated to que_jobs, can keep VACUUM from removing que_jobs dead tuples, so the table keeps growing and the job queue slows down. qg's design with advisory locks and a recursive CTE is sensitive to dead tuples.
These 3 cases involve Database and PostgreSQL vacuum. 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 cause3
Breaking change in an upgrade1 case
- Contributing factor
- Organisation
Capacity exhaustion1 case
- Contributing factor
- Organisation
Operator error1 case
- Component
- Contributing factor
- Organisation