{"id":"IL-0388","org":"Discord","date":"2017-10-13","docs":[],"title":{"en":"A Google Cloud live migration took a Discord Redis primary offline, and the failover broke API instances and then guilds","ko":"Redis 고가용 클러스터의 primary 노드가 내려간 뒤 Discord API 가 느려지고 길드 일부가 오프라인으로 보이며 접속이 실패했다"},"domain":["database","gcp"],"impact":{"scope":"API latency and errors, then guilds appearing offline and connection failures, ending in a full restart of Discord that reconnected all clients","users":"Discord users; millions of clients reconnected over about 20 minutes","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":null,"related":[],"sources":[{"url":"https://status.discordapp.com/incidents/qk9cdgnqnhcn","kind":"official-status","archived":"https://web.archive.org/web/20191208211931/https://status.discordapp.com/incidents/qk9cdgnqnhcn"}],"summary":{"en":"A Google Cloud Platform automatic migration made the primary node of a highly available Redis cluster used by Discord's API services drop offline. The cluster failed over to its secondary, but the failover triggered a bug, already known and scheduled to be fixed within weeks, in how the API instances handle Redis failover. Engineers escalated a P1 ticket with GCP support at 14:02 PDT and ran a rolling restart of all API instances at 14:11. Latency stayed high, and engineers found a misconfigured edge caching rule for an expensive API route that made clients call it aggressively. The requests overloaded a non-critical Cassandra cluster. Engineers corrected the rule, disabled the endpoint on the edge network, recovered Cassandra and restarted the API instances again, and the API was back to normal at 14:57.\n\nAt 15:41 new anomalies appeared: a node of the \"guilds\" cluster made part of the guilds appear offline, and nodes of the \"sessions\" cluster misbehaved. Engineers removed the guilds node from the service hashring, restarted it, and at 16:07 decided on a full restart of the service to reset the invalid state, forcing all users to reconnect. During the reboot the \"push\" component failed, and engineers found that, through human error, an API setting that lets users reconnect quickly and safely was set wrong. After it was corrected, service recovered slowly from 16:33 and was fully restored at 16:52, with millions of clients reconnected over about 20 minutes.\n\nDiscord could not say exactly why the partial API outage spread into a full system failure. The first failure made nodes of other services behave incorrectly until they ran out of memory and failed. In a later update, after alerts added for this postmortem caught similar behaviour on a node, Discord found possible flaws in a library that service uses and began rolling out an update.","ko":"2017년 10월 13일 14:01 PDT 쯤 Discord API 서비스가 쓰는 Redis 고가용 클러스터의 primary 인스턴스를 Google Cloud Platform 이 자동으로 마이그레이션했다. 이 마이그레이션으로 노드가 잘못 오프라인이 됐고, 클러스터는 secondary 노드로 failover 했다. 그러나 일부 API 인스턴스가 failover 를 제대로 처리하지 못했다. 이 버그는 Discord 가 전부터 알고 있었고 몇 주 안에 고치기로 일정을 잡아 둔 것이었다. 엔지니어들은 GCP 지원에 P1 티켓을 올리고, 14:11 에 모든 API 인스턴스를 롤링 재시작했다.\n\n재시작 뒤에도 API 지연이 계속 높았다. 14:18 부터 14:57 사이에 비용이 큰 API 경로 하나에 엣지 캐시 규칙이 잘못 걸려 클라이언트가 그 경로를 공격적으로 호출한다는 것을 찾아 고쳤다. 그 요청량으로 중요하지 않은 Cassandra 클러스터 하나가 쓰러졌다. 엔드포인트를 쓸 수 없는 동안에는 응답을 캐시할 수 없어서, 상위 엣지 네트워크에서 그 엔드포인트를 막았다. Cassandra 클러스터를 되살린 뒤 API 인스턴스를 다시 롤링 재시작했고, 14:57 에 API 가 정상으로 돌아왔다.\n\n15:41 에 다시 이상이 보였다. \"guilds\" 클러스터의 노드 하나가 잘못 동작해 길드 일부가 오프라인으로 보였고, 엔지니어들은 그 노드를 해시링에서 강제로 빼고 강제로 재시작했다. 이어 \"sessions\" 클러스터의 노드 몇 개도 이상하게 동작하자, 16:07 에 모든 사용자를 다시 접속시켜 여러 서비스의 잘못된 상태를 초기화하는 전체 재시작을 하기로 했다. 재시작 중 16:19 에 \"push\" 구성 요소가 또 실패해, 한 엔지니어는 이를 고치고 다른 엔지니어는 이 구성 요소에 기대는 트래픽 일부를 막아 부하를 줄였다. 사용자가 빠르고 안전하게 다시 접속하게 해 주는 중요한 API 설정이 사람의 실수로 잘못 들어가 있던 것도 찾아 고쳤다. 16:33 부터 서비스가 천천히 회복했고 16:52 에 완전히 복구됐다. 수백만 클라이언트가 20분에 걸쳐 다시 접속했다.\n\n처음의 API 부분 장애가 왜 전체 장애로 번졌는지는 사후 분석을 쓴 시점까지 밝혀지지 않았다. 처음 장애가 다른 서비스의 노드 일부를 잘못 동작하게 했고, 그 노드들이 결국 메모리가 바닥나 죽으면서 여러 안전장치가 있는데도 연쇄 장애를 일으켰다. 그 뒤 토요일에는 이 사후 분석의 결과로 더한 알림이 같은 증상을 잡았다. 엔지니어들은 해당 노드를 안전하게 빼서 조사했고, 그 서비스가 쓰는 라이브러리에서 결함으로 보이는 것을 찾았다."},"trigger":{"en":"Google Cloud Platform automatically migrated the Redis instance that was the primary of a highly available cluster used by the API services, and the node incorrectly dropped offline.","ko":"14:01 PDT 쯤 Google Cloud Platform 이 API 서비스용 Redis 고가용 클러스터의 primary 인스턴스를 자동으로 마이그레이션했다. 이 마이그레이션으로 노드가 잘못 오프라인이 되면서 클러스터가 재조정됐고, API 인스턴스의 Redis failover 처리에 있던 알려진 문제가 드러났다."},"severity":"unknown","symptoms":["failover-failed","high-latency","service-unavailable"],"timeline":{"detected_after":"0m","resolved_after":"2h 51m"},"date_kind":"incident","detection":{"en":"Real-time metrics and monitoring alerted engineers at 14:01 PDT. The second phase was seen at 15:41 as another anomaly in monitoring, and end user reports of servers appearing offline were escalated at 15:42.","ko":"14:01 PDT 에 실시간 지표와 모니터링이 이상을 알렸다. 15:41 에 모니터링에서 다시 이상이 보였고, 15:42 에 서버 일부가 오프라인으로 보인다는 사용자 신고가 엔지니어링 팀에 들어왔다."},"components":["cache","database","cdn"],"root_cause":"software-bug","remediation":[{"text":{"en":"Ran a rolling restart of all API instances to clear the Redis connection issues","ko":"Redis 연결 문제를 풀려고 14:11 PDT 에 모든 API 인스턴스를 롤링 재시작했다. 재시작은 14:15 에 끝났지만 API 지연은 계속 높았다."}},{"text":{"en":"Corrected the misconfigured edge caching rule for the expensive API route","ko":"비용이 큰 API 경로에 잘못 걸린 엣지 캐시 규칙을 고쳤다."}},{"text":{"en":"Disabled the problem API endpoint on the edge network","ko":"엔드포인트를 쓸 수 없는 동안에는 응답을 캐시할 수 없어서, 문제를 일으킨 API 엔드포인트를 상위 엣지 네트워크에서 막았다."}},{"text":{"en":"Recovered the Cassandra cluster","ko":"부하로 쓰러진 Cassandra 클러스터를 되살려 정상 서비스로 돌렸다."}},{"text":{"en":"Ran a second rolling restart of all API instances for the latency left by the Cassandra issues","ko":"Cassandra 클러스터 문제로 생긴 지연을 풀려고 모든 API 인스턴스를 다시 롤링 재시작했다. 14:57 에 API 가 정상으로 돌아왔다."}},{"text":{"en":"Removed the misbehaving guilds node from the service hashring","ko":"15:50 PDT 에 이상하게 동작하는 \"guilds\" 노드를 서비스 해시링에서 강제로 빼서, 그 서버가 스스로 제대로 내려가기를 기대했다."}},{"text":{"en":"Forcefully restarted the misbehaving guilds node","ko":"15:52 PDT 에 그 guilds 노드를 강제로 재시작했고, 재시작은 성공했다."}},{"text":{"en":"Restarted the whole service, forcing all users to reconnect","ko":"16:07 PDT 에 전체 서비스를 재시작하기로 하고, 모든 사용자를 다시 접속시켜 여러 서비스의 잘못된 상태를 초기화했다."}},{"text":{"en":"Blocked traffic that relied on the failing push component to reduce its load","ko":"\"push\" 구성 요소의 부하를 줄이려고 이 구성 요소에 기대는 트래픽 여러 갈래를 차단 목록에 넣었다."}},{"text":{"en":"Corrected the API setting that lets users reconnect quickly and safely","ko":"사용자가 빠르고 안전하게 다시 접속하게 해 주는 API 설정이 사람의 실수로 잘못 들어가 있던 것을 고쳤다. 16:33 부터 서비스가 천천히 회복했다."}}],"action_items":[{"text":{"en":"Fix the known issues with Redis failover within the coming weeks","ko":"Redis failover 의 알려진 문제를 고치는 일의 우선순위를 올려, 앞으로 몇 주 안에 끝내려 한다. 노드 하나의 장애로 문제가 더 생기지 않게 하려는 것이다."}},{"text":{"en":"Change the cached route so this type of error does not degrade other services","ko":"캐시가 잘못 걸렸던 경로의 동작을 바꿔, 앞으로 이런 오류가 나도 다른 서비스를 망가뜨리지 않고 제대로 처리하게 했다."}},{"text":{"en":"Monitor the signals that would have warned of the cascading failure","ko":"연쇄 장애를 미리 알려 줄 수 있었던 신호 일부에 모니터링을 더했다. 엔지니어가 조사하고 대비할 시간을 벌려는 것이다."}},{"text":{"en":"Improve the reliability and failure handling of the affected services","ko":"이번 장애에 영향을 받은 서비스들의 전반적인 신뢰성과 장애 처리를 개선할 계획을 이어 간다."}},{"text":{"en":"Roll out an update of the library with the suspected flaws","ko":"문제가 된 서비스가 쓰는 라이브러리에서 결함으로 보이는 것을 찾았고, 이를 고칠 것으로 보는 업데이트를 배포하고 있다."}}],"contributing":["known-bug-unpatched","overlapping-failures","monitoring-blind-spot"],"recurrence_of":null,"symptoms_text":{"en":"At about 14:01 PDT on 13 October 2017, Discord engineers were alerted to anomalies by real-time metrics and monitoring. A Redis instance that was the primary of a highly available cluster used by the API services had dropped offline after Google Cloud Platform migrated it automatically, and some API instances did not handle the failover to the secondary node correctly.\n\nThe Redis cluster itself had failed over properly to the secondary node, and the old primary was completely unavailable. After a rolling restart of all API instances, the API endpoints still showed abnormal latency. A misconfigured edge caching rule for an expensive API route made clients call that route aggressively, and the volume of requests made a non-critical Cassandra cluster fall over under load.\n\nAt 15:41 PDT, after the API had returned to normal at 14:57, monitoring showed another anomaly, and user reports said some servers appeared offline. A node of the \"guilds\" cluster was misbehaving, so part of Discord's guilds appeared offline, and then nodes of the \"sessions\" cluster misbehaved too. During the full restart that followed, a component called \"push\" also failed. Nodes of other services had run out of memory and failed, which spread the failure through the real-time system.","ko":"2017년 10월 13일 14:01 PDT 에 실시간 지표와 모니터링이 이상을 알렸다. API 서비스가 쓰는 Redis 고가용 클러스터에서 primary 노드가 완전히 사라졌다. 클러스터는 secondary 노드로 제대로 failover 했지만, 일부 API 인스턴스가 failover 를 제대로 처리하지 못했다.\n\nAPI 인스턴스를 롤링 재시작한 뒤에도 API 엔드포인트의 지연이 비정상으로 높았다. 비용이 큰 API 경로 하나에 엣지 캐시 규칙이 잘못 걸려 있어 클라이언트가 그 경로를 공격적으로 호출했다. 이 요청량 때문에 중요하지 않은 Cassandra 클러스터 하나가 부하를 못 이기고 쓰러졌다.\n\n15:41 PDT 에 모니터링에서 다시 이상이 보였고, 15:42 에는 서버 일부가 오프라인으로 보인다는 사용자 신고가 엔지니어링 팀에 들어왔다. \"guilds\" 클러스터의 노드 하나가 이상하게 동작해 Discord 길드 일부가 사용자에게 오프라인으로 보였다. 상태 페이지에는 15:54 PDT 에 길드를 쓸 수 없고 접속에 문제가 있다는 공지가 올라왔다.\n\n15:55 PDT 에는 \"sessions\" 클러스터의 노드 몇 개도 이상하게 동작했다. 처음 장애가 다른 서비스의 노드 일부를 잘못 동작하게 했고, 그 노드들은 결국 메모리가 바닥나 죽으면서 연쇄 장애를 일으켰다. 16:19 PDT 에는 전체 재시작 도중 \"push\" 라는 구성 요소에서 또 장애 알림이 왔다.\n\n처음에는 Redis 연결 문제를 풀려고 14:11 PDT 에 모든 API 인스턴스를 롤링 재시작했고, 14:15 에 끝났다. guilds 노드는 서비스 해시링에서 강제로 빼 스스로 내려가게 하려 했고, 이어 강제로 재시작했다."},"updated_at":"2026-11-14T12:34:03.926390Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0388","org_slug":"discord"}