Incident Library
  • Root cause
  • Component
  • Symptom
  • Contributing factor
  • Case

Cases4 cases

1 to 4 of 4

  1. Symptoms

    On the afternoon of 28 October 2021 (13:37 PST), Vault performance at Roblox degraded and a single Consul server showed high CPU load. Consul cluster metrics showed that writes to its key-value (KV) store had a 50th percentile latency of 2 seconds instead of the usual under 300 ms. Players were not yet affected.

    Trigger

    On 27 October at 14:00, one day before the outage, Roblox enabled the Consul streaming feature on the backend service responsible for traffic routing and, to prepare for end-of-year traffic, added 50% more nodes to traffic routing.

    Root cause
    Component
    Contributing factor
    Detection

    Roblox engineers began investigating when Vault performance degraded and a single Consul server had high CPU load, before players were affected. Consul cluster metrics then showed elevated KV write latency.

    Remediation
    • Replaced one Consul cluster node on the suspicion of degraded hardware
    • Replaced all Consul nodes with 128-core machines with faster NVMe SSDs
    • Shut down the Consul cluster and reset its state from a snapshot taken at the start of the outage, with access blocked by iptables
    • Blocked external traffic, disabled all non-essential Consul use, scaled services down and lowered health check frequency from 60 seconds to 10 minutes
    • Moved the Consul cluster back to 64-core servers
    • Disabled the streaming feature for all Consul systems, which brought KV write latency back to 300ms
    • Kept the slow Consul servers from staying elected as leader
    • Redeployed the caching system and fixed its wrong scheduling data and failed deployments
    • Restarted the stopped services at the right capacity levels
    • Let players back in with DNS steering in roughly 10% steps while checking database load, cache performance and stability
    Action items
    • HashiCorp builds laboratory benchmarks and scale tests that reproduce the streaming contention
    • HashiCorp improves the design of streaming so it does not contend under extreme load
    • Compact the BoltDB database with existing BoltDB tooling
    • Remove the circular dependency between the telemetry systems and Consul
    • Extend telemetry with targeted alerts on Consul and BoltDB performance and with visibility into traffic between services and Consul
    • Run the backend in an additional, geographically distinct data center and in multiple availability zones
    • Split critical services into their own dedicated Consul clusters
    • Move data that core services keep directly in the Consul KV store to a more suitable storage system
    • Delete obsolete KV data from Consul
    • Upgrade to a Consul version that replaces BoltDB with bbolt, in Q1
    • Redesign cache deployment so the cache system can be brought up quickly from a standing start
    • Deploy Nomad enhancements that make it easier to turn up large jobs after a long period of unavailability
    • Use mechanisms for faster machine configuration changes
    • Reintroduce streaming only after a new implementation has been tested at Roblox's scale and workload
    Lessons

    Two mostly unrelated problems deep inside Consul, contention in streaming under very high read and write load and BoltDB freelist growth, were hard to diagnose, and that difficulty was the main reason the outage lasted so long. A single Consul cluster serving every workload made the impact larger, and monitoring that depended on Consul hid the cause when it was needed most. Faster hardware did not help and may have hurt, because the contention was worse on NUMA machines. HashiCorp had benchmarked streaming at a similar scale, but the problem needed both a large number of streams and a high churn rate. Restarting a platform from a fully stopped state, including warming caches, took a long time and needed tools built for bootstrapping rather than incremental change.

  2. Symptoms

    At 4:45pm Pacific on 12 May 2020, Slack was alerted that it was serving more HTTP 503 errors than normal. A subset of the webapp fleet was under heavy load while the rest of the webapp instances were not.

    Trigger

    At the end of the US business day the webapp tier began its usual scale-down, and autoscaling terminated the oldest instances first, which were the only backends left in most HAProxy instances' state.

    Root cause
    Component
    Contributing factor
    Detection

    An alert for more HTTP 503 errors than normal. The alerting meant to catch stale HAProxy state was not working.

    Remediation
    • Did a rolling restart of the HAProxy fleet
    Action items
    • Move all ingress load balancing from HAProxy to Envoy Proxy, with endpoint discovery through an xDS control plane
    Lessons

    The alerting for this exact failure had stopped working, and nobody noticed because the HAProxy stack had run for a long time without needing changes, so few engineers worked with its monitoring and alerting. A slot limit that had been ample a few months earlier was reached after pandemic-driven growth and one large autoscaling event.

  3. Symptoms

    On 16 March 2020 at 14:19 PDT most of Discord's Elixir services, which handle real-time connections and chat message processing, crashed at once. Discord lost much of its real-time capacity, the failure cascaded into dependent systems, and most users could not connect for about an hour.

    Trigger

    At 14:18 the Google Cloud managed instance group autoscaler added a node to Discord's API cluster, and the TCP connection of its first announce request to etcd was reset after the request headers were sent but before the body.

    Root cause
    Component
    Contributing factor
    Detection

    At 14:21 several internal alarms fired on a drop in key metrics, along with anomaly alerts for cluster utilization, and a SEV1 incident was declared.

    Remediation
    • Restarted the lost real-time capacity and repaired the failed nodes
    • Throttled connections to Discord to help services recover
    • Stopped anti-entropy repairs on two ScyllaDB clusters so reconnecting users would not starve them of resources
    • Raised the connection throttle step by step to let more users reconnect
    Action items
    • Make the etcd clients send each announce request in a single TCP packet, so headers and body arrive together or not at all
    • Add error handling that ignores services whose key value is corrupt instead of crash-looping
    • File an upstream bug report with the Go project about net/http not checking the body against Content-Length
    Lessons

    Discord's service discovery code handled many etcd failure modes but did not expect a client to write a key without a value because of a transient network error. Go's net/http accepts a request whose body is shorter than its Content-Length header, which breaks the HTTP 1.1 specification and added a failure case nobody had anticipated.

  4. Symptoms

    On 18 January 2019 from 09:09 UTC the leader of the three-node Apache ZooKeeper ensemble behind Elastic Cloud in AWS eu-west-1 (Ireland) ran at heavy CPU load, and its clients lost their connections. From about 10:08 UTC customers in the region had severely degraded access to their Elasticsearch and Kibana deployments for roughly 3 hours, and for about 20 minutes every deployment in the region was unavailable.

    Trigger

    At 09:09 UTC the leader server of the ZooKeeper ensemble in the eu-west-1 coordination layer hit a high CPU threshold, which caused client disconnections.

    Root cause
    Component
    Contributing factor
    Detection

    The on-call SREs received alerts about service degradation in the coordination layer at 09:35 UTC, after the high CPU on the ZooKeeper leader had caused client disconnections, and started a production incident.

    Remediation
    • Scaled the proxy layer up and out to take the surging client traffic hitting the load balancers
    • Triggered a leader election in the ZooKeeper ensemble and stabilised it
    Action items
    • Replace Curator's TreeCache with TreeWatcher across all Elasticsearch Service providers and regions
    • Contribute TreeWatcher upstream to the Apache Curator project
    • Roll out a new proxy layer that keeps the routing table in a versioned local file, so it can route traffic while the ZooKeeper connection is lost or flaky
Check your cluster for this

These 4 cases involve Service discovery and Coordination and key-value store. 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