{"id":"IL-0270","org":"Discord","date":"2023-11-06","docs":[],"title":{"en":"Discord's ScyllaDB authentication cluster overloaded during an OS upgrade, and logins failed for about 50 minutes","ko":"인증용 ScyllaDB 클러스터가 과부하로 조회를 처리하지 못해 Discord 에서 약 50분 동안 접속과 로그인이 되지 않았다"},"domain":["database"],"impact":{"scope":"Discord authentication: users could not connect, log in, read or send messages; availability fell to about 25%, then about 50% of users could use Discord until 11:43 AM PST","users":"Discord users; about 50% could use the service from 11:05 AM until recovery","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Taking a whole zone out of a three-zone cluster leaves no margin, so one additional slow node in another zone was enough to overload it. For some Scylla clusters the row cache hit rate of restarted nodes must reach a safe level before the next zone goes down, and a short zonal test beforehand gave false confidence. The small but critical authentication cluster needs to be run differently from Discord's much larger Scylla clusters, with more redundancy.","ko":"클러스터는 존 하나를 잃어도 견디게 설계했지만, 존 하나가 내려간 상태에서 다른 존의 노드 하나 성능이 떨어진 것만으로 이 정도 장애가 났다는 것은 클러스터의 용량이 부족했다는 뜻이다. 노드 재시작 전에 캐시 적중률이 일정 수준이 돼야 하는 것도 용량 부족의 신호다. 업그레이드 전 존 중단 시험은 계속 진행해도 안전하다는 잘못된 확신을 줬다. 이 작고 중요한 클러스터는 훨씬 큰 다른 클러스터들과 다르게 운영해야 한다."},"related":[],"sources":[{"url":"https://discord.com/blog/authentication-outage","kind":"blog","archived":"https://web.archive.org/web/20260927221438/https://discord.com/blog/authentication-outage"}],"summary":{"en":"Discord's scylla-authentication ScyllaDB cluster holds user session data and sits behind the Rust authentication service that validates every API request. Like Discord's other Scylla clusters, it replicates data across three zones of the cloud provider and uses quorum reads so that it can lose one zone, and each node mirrors fast NVMe Local SSDs, which are cleared on reboot, with a slower persistent disk in a RAID array. Syncing that RAID takes about 40 minutes at instance startup before Scylla can start. From 3 November the persistence infrastructure team upgraded the operating system of the Scylla clusters one zone at a time: detach the persistent disks, terminate the instances, start new instances with the upgraded OS, rebuild the RAID, bring Scylla back and wait a set time before the next zone. While a zone is out, the cluster has a third less compute and no room for another failure, and the detached capacity cannot return for at least 45 minutes. More than a hundred nodes had been upgraded this way. Because scylla-authentication had not had a full zonal restart recently, the team first took zone [b] offline for ten minutes as a test, saw no degradation, and started the upgrade at 9:16 AM.\n\nZone [b] finished at 10:42 AM. One of its two nodes, scylla-authentication-b-2, had rebuilt its RAID much more slowly than the other because one of its NVMe Local SSDs was degraded, which hurt that node's disk I/O. The operator checked the cluster and advanced to the next zone, and at 10:52 AM the script drained zone [c]. The cluster was left with one degraded node and one healthy node in zone [b], both with fairly empty row caches, zone [c] offline and two healthy nodes in zone [d]. Discord had found that for some clusters the ScyllaDB row cache hit rate must reach a certain level before restarting nodes is safe, and the procedure had not checked the hit rate of the restarted zone [b] nodes; the earlier ten-minute test had given false confidence. Discord's write-up names the cluster as underprovisioned. It overloaded, authentication lookups timed out, and application retries made the overload worse.\n\nDiscord shed load by turning off typing events and read markers at 11:05 AM, which restored authentication for about half of users. Restarting nodes to clear abandoned queries risked breaking quorum completely, so at 11:35 AM, with the zone [c] RAID rebuild five minutes from done, the team chose to wait. The two zone [c] nodes came back at 11:41 AM, the two zone [b] nodes were restarted one at a time, and by 11:43 AM user activity was back to normal. Right after the incident the cluster was doubled in size, and after some analysis scylla-authentication-b-2 was rebuilt on new disks. The outage affected availability only; the authentication service returned no incorrect results, and no outside actor or unauthorized access was involved.","ko":"Discord 의 scylla-authentication 클러스터는 사용자 세션 정보를 담고, Rust 로 만든 인증 서비스가 그 앞에서 모든 API 요청의 인증을 확인한다. 이 클러스터는 표준 구성대로, 빠르지만 재부팅하면 지워지는 NVMe 로컬 SSD 와 느리지만 지워지지 않는 영구 디스크를 RAID 로 미러링한다. 데이터는 세 존에 복제하고 쿼럼 읽기를 써서, 존 하나를 잃어도 요청을 처리하도록 설계됐다. 인스턴스가 뜰 때 영구 디스크의 데이터를 NVMe 로 복사하는 RAID 동기화가 40분쯤 걸리고, 이것이 끝나야 Scylla 가 시작한다.\n\n11월 3일부터 영속성 인프라 팀은 존을 하나씩 내려 디스크를 떼고 인스턴스를 종료한 뒤, 새 운영체제의 인스턴스에 디스크를 다시 붙이는 방식으로 Scylla 클러스터들의 운영체제를 업그레이드했다. 존 하나를 내리면 연산 용량이 3분의 1 줄고 여유가 없어져서, 다른 존에 문제가 하나만 더 생겨도 쿼럼을 잃는다. 디스크를 뗀 뒤에는 RAID 재구축 때문에 적어도 45분 동안 용량을 되돌릴 수 없다. 팀은 인증 클러스터를 업그레이드하기 전에 존 b 를 10분 동안 내려 성능을 시험했고 문제가 없었다. 9:16 AM 에 업그레이드를 시작해 10:42 AM 에 존 b 를 마쳤다. 이때 scylla-authentication-b-2 의 RAID 재구축이 유난히 느렸지만 팀은 이상한 점으로만 보고 넘겼다. 운영자는 클러스터가 정상인 것을 확인하고 다음 존으로 넘겼고, 10:52 AM 에 존 c 의 연결이 모두 비워지면서 장애가 시작됐다.\n\n원인은 여러 가지가 겹친 것이었다. 클러스터는 용량이 부족했다. scylla-authentication-b-2 의 NVMe 로컬 SSD 하나가 성능이 떨어져 디스크 I/O 가 나빴다. 이 클러스터는 행 캐시 적중률이 일정 수준이 돼야 노드를 안전하게 재시작할 수 있다. 그런데 팀은 앞선 시험으로 잘못된 확신을 얻어, 방금 재시작한 존 b 노드의 캐시 적중률을 확인하지 않았다. 애플리케이션의 재시도 폭주가 부하를 더 키웠다. 존 c 는 디스크가 이미 떼어져 다시 올리려면 45분쯤 기다려야 했다. 팀은 11:05 AM 에 입력 중 표시와 읽음 표시를 꺼 부하를 덜었고 사용자의 약 50% 가 회복됐다. 노드를 재시작하면 쿼럼이 확실히 깨질 수 있어서, 팀은 재시작하지 않고 원인을 찾았다. 존 b 노드들이 과부하라는 것을 알아낸 11:35 AM 에는 RAID 재구축이 5분 남아 있어 기다리기로 했다. 11:41 AM 에 존 c 의 두 노드가 올라오자 존 b 노드를 한 대씩 재시작했고 11:43 AM 에 사용자 활동이 정상으로 돌아왔다. 장애는 서비스 가용성에만 영향을 줬고, 인증 서비스가 내놓은 결과의 정확성에는 영향이 없었다. 외부 공격이나 무단 접근 때문도 아니었다."},"trigger":{"en":"During an OS upgrade that takes one zone of a ScyllaDB cluster offline at a time, the upgrade script drained all connections from zone [c] of scylla-authentication at 10:52 AM, while one node in the just-upgraded zone [b] had a degraded NVMe Local SSD.","ko":"2023년 11월 6일 운영체제 업그레이드 절차가 scylla-authentication 클러스터의 존 b 를 마친 뒤, 10:52 AM 에 스크립트가 존 c 의 연결을 모두 비우고 업그레이드를 시작했다. 존 b 에는 디스크 성능이 떨어진 노드가 있었다."},"severity":"unknown","symptoms":["service-unavailable","database-overloaded","high-latency"],"timeline":{"detected_after":"4m","resolved_after":"51m"},"date_kind":"incident","detection":{"en":"An incident response call had already started when the first alerts fired at 10:56 AM, four minutes after the start. The time spent by downstream service graph showed the authentication service spending far more time on user requests than normal, and the authentication alerts fired moments later.","ko":"첫 알림이 장애 시작 4분쯤 뒤인 10:56 AM 에 울렸지만, 팀은 그 전에 이미 사고 대응 통화를 열고 조사하고 있었다. 하위 서비스별 소요 시간 그래프가 인증 서비스를 가리켰고, 잠시 뒤 인증 알림이 울렸다."},"components":["database"],"root_cause":"capacity","remediation":[{"text":{"en":"Turned off sending typing events and marking messages as read to shed load from the authentication cluster","ko":"11:05 AM 에 인증 클러스터의 부하를 덜려고 입력 중 표시 이벤트와 메시지 읽음 표시를 껐다."}},{"text":{"en":"Waited for the zone [c] RAID rebuild instead of restarting nodes, and the two zone [c] nodes came back online at 11:41 AM","ko":"RAID 재구축이 끝나기를 기다려 11:41 AM 에 존 c 의 두 노드를 다시 올렸다."}},{"text":{"en":"Restarted the two zone [b] nodes one at a time","ko":"과부하였던 존 b 의 두 노드를 한 대씩 재시작했다."}}],"action_items":[{"text":{"en":"Double the size of the scylla-authentication cluster so each node takes half as many requests","ko":"사고 직후 scylla-authentication 클러스터를 두 배로 늘려 용량을 더했다."}},{"text":{"en":"Rebuild scylla-authentication-b-2 with new, non-degraded disks","ko":"scylla-authentication-b-2 를 성능이 떨어지지 않은 새 디스크로 다시 만들었다."}},{"text":{"en":"Build a way to detect disk degradation that is too subtle to affect overall latency but still threatens reliability","ko":"전체 지연에는 드러나지 않을 만큼 약하지만 서비스 신뢰성에 위험이 될 수 있는 디스크 성능 저하를 찾아내는 방법을 만든다."}},{"text":{"en":"Move upgrade operations into a more automatic control plane for the Scylla clusters that analyses cluster state, such as cache hit rate","ko":"Scylla 클러스터의 컨트롤 플레인을 더 자동화하고 업그레이드 작업을 그곳으로 옮겨, 캐시 적중률 같은 클러스터 분석을 업그레이드 절차에 넣는다."}},{"text":{"en":"Increase the redundancy of the scylla-authentication cluster; the options being explored, not yet decided, are a higher replication factor or a hot-standby cluster in another region","ko":"복제 계수를 늘리거나 다른 리전에 핫 스탠바이 클러스터를 두는 방안을 검토해, 이 작고 중요한 클러스터의 이중화를 늘린다."}}],"contributing":["no-spare-capacity","overlapping-failures","warm-cache-dependency","assumption-unverified","early-signal-ignored","retry-storm"],"recurrence_of":null,"symptoms_text":{"en":"On 6 November 2023 at 10:52 AM PST, when an upgrade script drained all connections from zone [c] of the scylla-authentication ScyllaDB cluster, Discord's availability, measured as the share of HTTP requests that return a 200-level response, fell at once to about 25%. Users could not connect, log in, read or send messages.\n\nThe first alerts fired at 10:56 AM, but an incident call was already running. A graph of time spent by downstream service showed that the Rust authentication service, which checks that every API request comes from an authenticated user, was taking far longer than normal on each request, and the authentication alerts fired moments later. The scylla-authentication cluster was saturated with queries and showed high latency; all four remaining nodes were overwhelmed, with load at 100% on some of their shards. Scylla's logs reported errors connecting to the two zone [b] nodes, scylla-authentication-b-1 and scylla-authentication-b-2.\n\nThe application retries requests that get server errors from the authentication endpoints, so once the cluster began timing out, the retries added a retry storm on top of the load. Turning off typing events and read markers at 11:05 AM brought authentication back for about 50% of users, and at 11:10 AM still only about half of users could use Discord.\n\nThe timing pointed to the authentication upgrade right away, but the script had already detached zone [c]'s data disks, so bringing that zone back meant about 45 minutes of instance provisioning and RAID rebuild. Restarting nodes to clear long-running queries abandoned by clients was considered, but with zone [c] offline a restart would break quorum, and restarting the wrong node could take the service down completely. A misleading error message in the authentication service sent the investigation on a detour. Earlier that morning, while zone [b] was being upgraded, scylla-authentication-b-2 had rebuilt its RAID array much more slowly than the other node, which the team had treated as a curiosity.","ko":"2023년 11월 6일 10:52 AM PST 에 업그레이드 스크립트가 scylla-authentication 클러스터의 존 c 연결을 모두 비우자, 2xx 응답 비율로 재는 Discord 의 가용성이 곧바로 약 25% 로 떨어졌다. 사용자는 접속, 로그인, 메시지 읽기와 보내기를 거의 할 수 없었다. 첫 알림은 4분쯤 뒤인 10:56 AM 에 울렸다.\n\n하위 서비스별 소요 시간 그래프에서 인증 서비스가 사용자 요청을 처리하는 데 평소보다 훨씬 오래 걸리는 것이 보였다. 시점이 겹쳐 팀은 진행 중이던 인증 클러스터 업그레이드를 곧바로 의심했고, 잠시 뒤 인증 알림이 울려 의심이 맞았음을 확인했다.\n\n인증 클러스터는 쿼리로 포화돼 지연이 높았다. 11:05 AM 에 입력 중 표시 이벤트와 메시지 읽음 표시를 끄자 사용자의 약 50% 가 다시 인증됐지만 완전히 회복되지는 않았다. 노드 네 대가 모두 과부하였고, 노드마다 일부 샤드의 부하가 100% 였다.\n\n서버 오류가 나면 애플리케이션이 인증 엔드포인트 요청을 다시 보냈다. 요청이 타임아웃되기 시작하자 재시도가 폭주해 Scylla 클러스터의 부하가 더 커졌다.\n\n인증 서비스의 오류 메시지가 엉뚱한 쪽을 가리켜 조사가 한 번 빗나갔다. 그 뒤 Scylla 로그에서 존 b 의 두 노드 scylla-authentication-b-1 과 scylla-authentication-b-2 에 연결하는 오류가 나오는 것을 보고 두 노드가 과부하임을 알았다.\n\n업그레이드 중 존 b 를 내렸을 때 클러스터의 지연과 오류율은 정상이었다. 다만 scylla-authentication-b-2 는 짝 노드보다 RAID 배열을 훨씬 느리게 다시 만들었다. 팀은 이를 이상한 점 정도로만 보고 넘겼다. 이 노드에 붙은 NVMe 로컬 SSD 하나가 성능이 떨어져 있었다."},"updated_at":"2026-11-14T12:33:52.160819Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0270","org_slug":"discord"}