Incident Library

IL-0212 Slack · 2022-02-22database

Many Slack users could not connect because a Vitess keyspace for channel membership was overloaded by cache-miss queries

Slack stores its data in Vitess, a horizontal scaling system for MySQL with logical databases called keyspaces, and caches frequently used data in Memcached. Mcrouter routes cache requests by consistent hashing over a list of healthy Memcached hosts, and Mcrib, a fairly new control plane, generates that list from the Consul service catalog: when a Memcached instance disappears from Consul, Mcrib promotes a spare, and a node that rejoins is flushed before it serves again. During client boot Slack fetches the members of each GDM the user is in. That data was read from a keyspace sharded by user, so finding the members of one GDM meant a scatter query to every shard. The data is immutable and cached by channel ID with a long TTL, so the query was normally almost always served from the cache.

On 22 February a Consul agent upgrade step covered 25% of the fleet, after two 25% steps the week before had passed without trouble. As Memcached nodes were restarted one after another at the daily traffic peak, Mcrib kept replacing and flushing them and the cache hit rate fell. Because even one channel missing from the cache meant querying every shard, nearly every booting client now needed a query on every shard, and the keyspace was overwhelmed. Timed-out queries could not refill the cache, and client retries added load, so the system stayed in a cascading failure even after the Consul restarts were paused.

Responders throttled client boot requests to cut the load on the datastores, which restored more normal service for users with booted clients. The query was changed to read from Vitess only the data missing from Memcached instead of every shard on each miss, and, because the data tolerates staleness, to read from replicas as well as primaries. The caches refilled, hit rates rose and database load fell, and the boot rate limit was raised slowly back to normal traffic levels until service was fully restored.

Severity
–
Scope
Slack client boot: many users could not connect to Slack, and requests from users with booted clients also failed until boot requests were throttled
Users affected
many Slack users, including internal users
Region
–
Time to detect
–
Time to resolve
–

Symptoms

Just after 6 a.m. Pacific Time on 22 February 2022, user tickets about problems connecting to Slack, problems reported by internal users, and pages and alerts to several engineering teams all arrived at almost the same moment. Many users could not connect: the Slack client could not finish booting, the step that fetches channel lists, preferences and recent conversations, and showed an error page.

Responders saw more load than usual on parts of the database system. One Vitess keyspace, which holds channel membership sharded by user, was severely overloaded, and a large share of its load came from a query that lists Group Direct Message (GDM) conversations by user. That query normally sits behind the Memcached cache tier, so the load suggested that something was wrong with the caches. Because the table was sharded by user, finding the members of a GDM took a scatter query to every shard, and with a large part of the cache empty nearly every user needed such a query to succeed on every shard. Most queries to the channel membership tables sharded by user were timing out, which also meant the cache could not be refilled.

Client boot requests took much longer than usual and often failed, and these slow requests exhausted resources in the database tier, so requests from users whose clients had already booted failed too. Throttling client boot requests reduced the errors and gave users with booted clients more normal service. The first attempt to raise the boot limit went too far: database load rose past sustainable levels and failed requests climbed again, so the limit had to be cut and then raised in smaller steps.

Early on, responders paused the Consul agent restarts that were in progress, before anyone suspected them, but by then this made no difference. The database read load grew superlinearly with the share of cache misses, and client retries, even with exponential backoff and jitter, added to it, so the cache and database tiers stayed in a cascading failure until load was reduced and the query was changed.

Symptom Database overloadHigh error rateHigh latency

Root cause

Trigger
A percentage-based rollout step upgraded the Consul agent on 25% of the fleet, followed by a slow sequential restart of the agents. Each restart on a Memcached node removed it from the Consul service catalog, so Mcrib, the cache-tier control plane, replaced it with an empty spare or flushed it when it rejoined, and the cache hit rate dropped as Slack reached its daily peak traffic.

Detection

User tickets about connection problems, reports from internal users and pages and alerts to several engineering teams arrived almost at the same time, just after 6 a.m. Pacific Time.

Remediation

Action items

Lessons

Slack describes performance bottlenecks, a cascading failure, dependence on a warm cache and a change as the trigger. Once the system had passed the tipping point, lower cache hit rates caused high database load that in turn kept the cache from filling, and a system in that state stays there until an outside intervention, a large cut in load or an increase in capacity, changes it. Mcrib contributed not by being wrong but by being faster than the old Consul lock scheme at replacing Memcached nodes, which increased churn in the cache tier. Client retries still added load despite backoff and jitter. A brief network partition of the cache nodes could set off the same failure, and the interaction between Consul and the caching architecture is now more widely understood.

Sources

Related cases

Check your cluster for this

kubegap audits a Kubernetes cluster for conditions like the ones in this case, Database, In-memory cache, Service discovery among them, read-only, from Claude Code or Codex. Its checks cite public reports like this one.

For AI tools and scripts

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.