{"id":"IL-0024","org":"Hugging Face","date":"2024-04-22","docs":[],"title":{"en":"Expensive cache-backed API calls and uncancelled database requests overloaded MongoDB and took the Hugging Face Hub down three times","ko":"무거운 API 요청이 MongoDB 에 과부하를 걸고 취소되지 않은 요청이 쌓여 Hugging Face Hub 가 사흘 동안 세 번 멈췄다"},"domain":["ai-infra"],"impact":{"scope":"The Hugging Face Hub website was slowed down or inaccessible, in three outages between 22 and 24 April 2024","users":"Most users","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Finding the root cause took two to three days: the existing charts did not show it, and a per-URL request breakdown did. Not cancelling database work when a client goes away turns a strained database into a thundering herd. A close inspection of the database exposed architectural flaws and bottlenecks, such as a collection with large unused indexes, and taught the team which metrics need closer watching to anticipate crashes. Unrelated failures happening at the same time added to the stress and made restoring service harder.","ko":"Hub 팀은 모든 차트를 봐도 답이 없을 때 URL 별 요청 수라는 새 그래프를 만들어서야 원인을 찾았다. 클라이언트가 떠난 뒤에도 서버가 데이터베이스 요청을 계속 돌리면, 서비스가 느려졌을 때 사용자가 누르는 새로고침이 부하를 몇 배로 키운다. 무거운 요청 몇 가지가 데이터베이스 전체를 흔들 수 있으므로 요청별 타임아웃과 취소가 필요하다. 팀은 이번 일로 어떤 지표를 더 가까이 봐야 장애를 미리 막을 수 있는지 알게 됐다. 원인을 찾는 데 2-3일이 걸렸고, 관계없는 장애가 동시에 겹쳐 복구가 더 힘들었다."},"related":[],"sources":[{"url":"https://huggingface.co/blog/mcpotato/hub-incident-post-mortem-20240422","kind":"blog","license":"unknown","archived":"http://web.archive.org/web/20250901020143/https://huggingface.co/blog/mcpotato/hub-incident-post-mortem-20240422"}],"summary":{"en":"From 08:45 CET on 22 April 2024 until 10:03 on 24 April the Hugging Face Hub had an extended outage with three separate crashes, during which the website was slow or inaccessible for most users. The write-up names Gitaly, AWS WAF, MongoDB and MongoDB Atlas as parts of the Hub's production architecture, and the Hub itself runs on a Kubernetes cluster.\n\nThe cause was a set of very resource-intensive API calls that read from the *_info_cache collections in MongoDB; the call behind the 23 April crash used space_info_cache, and datasets_info_cache is one of the three collections that put a significant strain on the database. Requests to the lighteval/mmlu dataset revision endpoint rose sharply right before the first crash. Requests to the sentence-transformers/all-mpnet-base-v2 model revision endpoint, which lists 300+ associated spaces, lined up with the crash on 23 April, and traffic to that endpoint correlated with database network out, which had come before several of the crashes. A k6 script set up to send that one request from 512 virtual users over ten minutes made the Hub slow or unresponsive when the team ran it on 24 April.\n\nA slow database turned into a collapse because the Hub's Node.js code did not cancel database requests when users cancelled theirs. When a page was slow and users refreshed it, every earlier database request kept running to completion with nobody waiting for the answer, a thundering herd that snowballed once something hit the database hard.\n\nDuring the outage the team blocked the Java user agent at the firewall, disabled the quicksearch feature, scaled the MongoDB cluster by hand from tier 2 to tier 3, put the Hub into maintenance mode with a 503 page through the WAF and scaled the Hub's pods down to 0, and on 24 April set an aggressive rate limit. Afterwards it added timeouts to requests based on their usual completion time, reworked the queries that were slow or returned large bodies, removed old unused indexes, and planned to move the *_info_cache collections to Redis and make database requests abort when the client aborts.","ko":"2024년 4월 22일 CET 8:45 부터 24일 10:03 까지 Hugging Face Hub 에 긴 장애가 이어졌다. 그사이 Hub 는 세 번 크게 멈췄고, 대부분의 사용자에게 Hub 웹사이트가 느려지거나 열리지 않았다. Hub 는 MongoDB Atlas, Gitaly, AWS WAF 위에서 돈다.\n\n원인은 일부 API 요청이 데이터베이스에 주는 부담이었다. https://huggingface.co/api/models/sentence-transformers/all-mpnet-base-v2/revision/main 을 호출하면 이 모델과 연결된 Space 300여 개의 목록이 함께 나왔고, 이 호출은 space_info_cache 컬렉션을 썼다. 이 URL 로 가는 트래픽 증가는 데이터베이스 네트워크 송신량 증가와 정확히 맞아떨어졌고, 송신량 증가는 여러 장애에 앞서 나타났다. 팀은 k6 로 가상 사용자 512명이 10분 동안 이 URL 을 호출하는 스크립트를 돌려 Hub 가 느려지거나 멈추는 것을 재현했다. 첫 장애는 이 URL 때문이 아니었고, 직전에 요청이 크게 늘어난 https://huggingface.co/api/datasets/lighteval/mmlu/revision/main 이 계기였다. 이 호출은 데이터베이스에 큰 부담을 준 세 컬렉션 중 하나인 datasets_info_cache 를 썼다.\n\n상황을 더 나쁘게 만든 것은 Hub 의 NodeJS 코드였다. 사용자가 요청을 취소해도 Hub 는 데이터베이스 요청을 취소하지 않았다. 페이지가 느려 사용자가 새로고침하면, 이미 진행 중인 데이터베이스 요청은 응답을 받을 사람이 없어도 끝까지 돌았다. 그래서 같은 순간에 요청이 한꺼번에 몰리는 thundering herd 문제가 생겼다. 누군가 데이터베이스에 요청을 대량으로 보내는 것처럼 데이터베이스 상태가 좋지 않을 때는 처리되지 않은 요청이 계속 쌓여 결국 장애로 이어졌다.\n\n팀은 MongoDB 클러스터 tier 를 올리고, Java user-agent 를 막고, quicksearch 기능을 끄고, 유지보수 모드로 트래픽을 막고, Hub 파드를 0 으로 줄이는 방식으로 매번 복구했다. 24일 10:03 에 아주 엄격한 rate limit 을 건 뒤로는 Hub 가 더 멈추지 않았다. 이후 요청마다 평소 완료 시간에 맞춘 타임아웃을 넣고, 오래 걸리거나 응답 본문이 큰 요청을 찾아 최적화했으며, 잘못 설계된 데이터베이스 쿼리를 다시 짰다. 같은 시기에 관계없는 시스템 장애가 겹쳐 복구가 더 어려웠다."},"trigger":{"en":"Bursts of requests to revision endpoints that read heavily from the *_info_cache collections: a call to https://huggingface.co/api/datasets/lighteval/mmlu/revision/main rose sharply right before the first crash, and a call to https://huggingface.co/api/models/sentence-transformers/all-mpnet-base-v2/revision/main, a model with 300+ associated spaces, lined up with the crash at 21:30 on 23 April.","ko":"*_info_cache 컬렉션을 쓰는 무거운 API 요청이 갑자기 늘었다. 첫 장애 직전에는 https://huggingface.co/api/datasets/lighteval/mmlu/revision/main 호출이 크게 늘었고, 4월 23일 밤에는 https://huggingface.co/api/models/sentence-transformers/all-mpnet-base-v2/revision/main 요청이 늘었다."},"severity":"unknown","symptoms":["service-unavailable","high-latency","database-overloaded"],"timeline":{"detected_after":null,"resolved_after":"2d 1h 18m"},"date_kind":"incident","detection":{"en":"Instability started at 08:45 on 22 April and the Hub was unresponsive by 09:30; the team followed MongoDB Atlas metrics and a MongoDB support case. The root cause was found days later from a new graph of requests per URL.","ko":"장애는 4월 22일 8:45 부터 Hub 가 불안정해지다가 9:30 에 응답하지 않으면서 드러났다. MongoDB Atlas 지표에서 읽기 전용 노드 두 대가 계속 재시작하는 것이 보였다. 24일 10:03 에는 팀이 수상한 지표를 보고 Hub 가 다시 멈추기 전에 rate limit 을 걸었다. 근본 원인은 URL 별 요청 수 그래프를 새로 만든 뒤에 찾았다."},"components":["database","model-hub","cluster-autoscaler"],"root_cause":"software-bug","remediation":[{"text":{"en":"Added a firewall rule blocking all requests with a Java/* user agent","ko":"Java/* user-agent 를 단 요청을 모두 막는 방화벽 규칙을 넣었다."}},{"text":{"en":"Disabled the quicksearch feature on the Hub","ko":"Hub 의 quicksearch 기능을 껐다."}},{"text":{"en":"Scaled the MongoDB Atlas cluster by hand from tier 2 to tier 3","ko":"MongoDB Atlas 클러스터를 손으로 tier 2 에서 tier 3 으로 올렸다."}},{"text":{"en":"Switched the Hub to maintenance mode with a 503 page through AWS WAF and blocked incoming traffic","ko":"AWS WAF 로 유지보수 모드를 켜 503 페이지를 띄우고 들어오는 트래픽을 막았다."}},{"text":{"en":"Scaled all Hub pods down to 0 and brought them back","ko":"Hub 파드를 모두 0 으로 줄였다가 다시 올렸다."}},{"text":{"en":"Set an aggressive rate limit","ko":"아주 엄격한 rate limit 을 걸었다."}},{"text":{"en":"Added timeouts to requests and reworked database queries that were slow or returned large bodies","ko":"요청에 타임아웃을 넣고, 오래 걸리거나 응답 본문이 큰 데이터베이스 쿼리를 다시 짰다."}}],"action_items":[{"text":{"en":"Add timeouts to requests based on their usual completion time","ko":"요청마다 평소 완료 시간에 맞춘 타임아웃을 넣었다."}},{"text":{"en":"Optimise requests that took too long or returned a large body, and rework poorly designed database queries","ko":"장애 중 오래 걸리거나 응답 본문이 큰 요청을 찾아 최적화하고, 잘못 설계된 데이터베이스 쿼리를 다시 짰다."}},{"text":{"en":"Remove old unused indexes from the database","ko":"쓰지 않는 오래된 인덱스를 지워 데이터베이스를 정리했다."}},{"text":{"en":"Build new dashboards and monitoring metrics","ko":"장애 중 새 대시보드와 모니터링 지표를 만들었다."}},{"text":{"en":"Move the *_info_cache collections to Redis","ko":"*_info_cache 를 Redis 로 옮긴다."}},{"text":{"en":"Make it possible to abort any database request when the client aborts theirs","ko":"클라이언트가 요청을 취소하면 데이터베이스 요청도 취소할 수 있게 한다."}}],"contributing":["no-spare-capacity","retry-storm","overlapping-failures"],"recurrence_of":null,"symptoms_text":{"en":"At 08:45 CET on 22 April 2024 the Hugging Face Hub became unstable, and by 09:30 it was unresponsive. For most users the website was slow or could not be reached at all.\n\nIn the MongoDB Atlas metrics two read-only nodes were down and kept restarting. The database cluster autoscaled once, from tier 1 to tier 2, and was HEALTHY again at 07:33 UTC, but the Hub stayed unstable even though the database looked healthy. A spike of traffic from an internal source with a Java/17 user agent was suspected and blocked at the firewall at 10:22; that reduced the load but did not fix the problem. The nodes of the Hub's Kubernetes cluster had also not scaled automatically, because of a configuration issue.\n\nThe outage came back twice. At 21:30 on 23 April the number of database connections and the system memory rose sharply and the MongoDB primary ran out of memory; the cluster elected a new primary, the same thing happened, and it elected the previous primary again. At 08:00 on 24 April the Hub was slow and unresponsive with the same pattern, and at 10:03 suspicious metrics pointed to another crash.\n\nThe database metrics showed the *_info_cache collections were overused, with poor average latency and very high network out. Going through all the existing charts and graphs showed nothing else, and identifying the root cause took two to three days; it came only after the team built a new graph that broke requests down by URL.","ko":"2024-04-22 CET 8:45 부터 Hugging Face Hub 가 불안정해졌고, 9:30 에는 응답하지 않았다. 대부분의 사용자에게 Hub 웹사이트가 느려지거나 아예 열리지 않았다.\n\nMongoDB Atlas 지표를 보면 읽기 전용 노드 두 대가 내려가 계속 재시작하고 있었다. 클러스터는 한 번 자동으로 tier 1 에서 tier 2 로 커졌고, 팀은 이어서 손으로 tier 3 까지 올렸다. 내부 출처에서 Java/17 user-agent 를 단 트래픽이 치솟는 것이 보였다. 팀은 그 user-agent 를 막는 방화벽 규칙을 넣었지만, 부하만 줄었을 뿐 근본 문제는 그대로였다. 데이터베이스가 건강해 보인 뒤에도 Hub 는 불안정했다.\n\n장애는 되풀이됐다. 4월 23일 21:30 에는 연결 수와 시스템 메모리가 급격히 늘면서 primary 가 OOM 으로 죽었다. 클러스터가 primary 를 바꿨지만 같은 일이 반복됐고, 결국 예전 primary 가 다시 primary 로 뽑혔다. 4월 24일 8:00 에도 같은 패턴으로 Hub 가 느려지고 응답하지 않았고, 10:03 에는 지표가 다시 수상하게 튀었다.\n\n팀은 모든 차트와 그래프를 뒤져도 원인을 찾지 못했다. 데이터베이스 로그와 지표를 보면 *_info_cache 컬렉션이 지나치게 많이 쓰이고 있었다. 평균 지연 시간도 나빴고 네트워크 송신량은 매우 높았다. 원인은 URL 별 요청 수 그래프를 새로 만든 뒤에야 드러났고, 찾기까지 2-3일이 걸렸다."},"updated_at":"2026-11-10T00:00:37.709131Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0024","org_slug":"hugging-face"}