{"id":"IL-0483","org":"Replicate","date":"2023-05-11","docs":[],"title":{"en":"Replicate's website and API returned slow responses and HTTP 500s for two hours as PostgreSQL connections ran out","ko":"PostgreSQL 커넥션이 바닥나 Replicate 웹사이트와 API가 두 시간 가까이 느린 응답과 HTTP 500을 냈다"},"domain":["database"],"impact":{"scope":"replicate.com website and API: slow responses and HTTP 500 errors, predictions failing to run; webhook users saw relatively little disruption","users":"many customers","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"The system ran in a degraded state that looked successful until it tipped into a full failure. The same asynchronous update work that triggered the outage also partly protected customers who used webhooks, and the stacked INSERTs came directly from a latency improvement: removing 100-150ms brought two updates of one prediction to the database almost together.","ko":"Replicate는 이 장애에 복잡한 시스템 장애의 전형적인 특징이 있다고 보았다. 시스템은 성능이 떨어진 채로도 겉으로는 잘 돌다가 어느 순간 크게 무너졌다. 장애를 촉발한 방어 장치가 같은 장애를 일부 막아 주기도 했다. 변경은 새 위험을 만들지만 위험을 없애는 것도 변경이다. 한 가지를 빠르게 만든 성능 개선이 다른 곳을 훨씬 나쁘게 만들 수 있다."},"related":[],"sources":[{"url":"https://replicate.com/blog/new-status-page","kind":"blog","archived":"https://web.archive.org/web/20260612235634/https://replicate.com/blog/new-status-page"}],"summary":{"en":"Replicate's primary datastore is a PostgreSQL database, and starting a prediction depended on it directly. To keep predictions working during database maintenance or short outages, Replicate was adding caches and queues, and over 9 and 10 May it rolled out, behind feature flags, API service changes that wrote prediction state updates to the database asynchronously, outside the request handlers. A little after 14:00 UTC on 10 May the database primary was resized in just over a minute, and most users saw no disruption.\n\nThe asynchronous path removed about 100-150ms from creating a prediction, so two updates to the same prediction that used to arrive that far apart were now processed almost at the same time, and both tried to INSERT a row with the same unique prediction ID. Only one can succeed, and the queries contend for the unique index lock while the database decides, which makes all of them slower. The code fell back to updating the existing row when its INSERT failed, so users saw nothing at first, but slower INSERTs meant more parallel queries and more lock contention. A little after 05:00 UTC on 11 May normal traffic variation tipped this over, INSERT latency rose to tens of seconds, and from about 05:45 UTC the database connections were exhausted. After Crunchy Data helped rule out the database, Replicate switched all asynchronous prediction update features off with a feature flag at 07:31 UTC, and the database recovered within a few minutes.","ko":"Replicate 플랫폼의 중심에는 주 데이터 저장소인 PostgreSQL 데이터베이스가 있고, 예측 실행이 이 데이터베이스에 강하게 묶여 있었다. Replicate는 데이터베이스가 잠시 멈춰도 예측이 돌아가도록 캐시와 큐를 더하는 중이었다. 그 일환으로 예측 상태 업데이트를 API 요청 처리기 밖에서 비동기로 데이터베이스에 쓰는 변경을 배포했다. 그리고 5월 10일의 계획된 데이터베이스 유지 보수에 대비해 9일과 10일에 기능 플래그로 넓게 켰다. 10일 14:00 UTC가 조금 지나 프라이머리 크기를 1분 남짓 만에 바꿨고, 이때 대부분의 사용자는 영향을 받지 않았다.\n\n비동기 업데이트는 같은 예측 ID에 INSERT 쿼리를 동시에 보내는 위험한 패턴을 만들었다. 예측 생성 과정에서 약 100~150ms의 지연을 없애자, 그만큼 떨어져 처리되던 업데이트 두 건이 거의 동시에 처리되었다. 고유해야 하는 필드에 같은 값을 넣으려는 쿼리들은 고유 인덱스 잠금을 두고 경합했고, 그동안 모두 느려졌다. 코드는 INSERT가 실패하면 기존 행을 업데이트하도록 되어 있어 바로 문제가 드러나지 않았다. 그러나 시스템은 INSERT가 느려질수록 동시에 도는 쿼리가 늘고 경합도 커지는 불안정한 상태였다.\n\n5월 11일 05:00 UTC가 조금 지나 트래픽 변동으로 이 상태가 무너졌다. INSERT 지연이 수십 초로 뛰었고, 05:45 UTC쯤 커넥션 풀이 가득 차 웹사이트와 API가 느린 응답과 HTTP 500을 냈다. 팀은 전날의 크기 변경을 먼저 의심했고 Crunchy Data와 함께 데이터베이스 문제를 배제했다. 다른 방법을 다 써 본 뒤 07:31 UTC에 기능 플래그로 비동기 예측 업데이트 기능을 모두 껐고, 몇 분 안에 데이터베이스가 회복했다. 장애를 촉발한 그 비동기 코드 덕분에 웹훅을 쓰는 고객은 영향을 덜 받았다."},"trigger":{"en":"A little after 05:00 UTC on 11 May, normal variations in traffic pushed the stacking INSERT queries past their tipping point.","ko":"5월 9일과 10일에 기능 플래그로 넓게 켠 비동기 예측 상태 업데이트 기능이 같은 예측 ID로 INSERT 쿼리를 동시에 보내기 시작했다. 5월 11일 05:00 UTC가 조금 지나 평소 수준의 트래픽 변동이 이 불안정한 상태를 무너뜨렸다."},"severity":"unknown","symptoms":["high-error-rate","high-latency","lock-contention"],"timeline":{"detected_after":"1m","resolved_after":"2h"},"date_kind":"incident","detection":{"en":"Monitoring detected the saturated database connection pool almost immediately and paged an engineer at 05:46 UTC.","ko":"05:45 UTC쯤 데이터베이스 커넥션 풀이 가득 차자 모니터링 시스템이 거의 곧바로 이를 감지해 05:46 UTC에 엔지니어를 호출했다."},"components":["database"],"root_cause":"deploy-rollout","remediation":[{"text":{"en":"Switched off all asynchronous prediction update features with a feature flag at 07:31 UTC, after which the database recovered","ko":"07:31 UTC에 기능 플래그로 비동기 예측 업데이트 기능을 모두 껐다. 몇 분 안에 데이터베이스가 회복했고 서비스가 정상으로 돌아왔다."}}],"action_items":[{"text":{"en":"Keep the asynchronous prediction update feature disabled and redesign it so it no longer sends stacked INSERTs","ko":"비동기 예측 업데이트 기능을 꺼 둔 채로, 같은 예측 ID에 INSERT가 쌓이지 않도록 다시 설계한다."}},{"text":{"en":"Review lock contention and other database hotspots that could cause similar problems","ko":"방치하면 비슷한 문제를 일으킬 수 있는 잠금 경합과 그 밖의 데이터베이스 부하 집중 지점을 점검한다."}},{"text":{"en":"Publish detailed reports after major incidents","ko":"큰 장애가 나면 무슨 일이 있었고 무엇을 고치는지 담은 자세한 보고서를 공개한다."}}],"contributing":["delayed-effect-change"],"recurrence_of":null,"symptoms_text":{"en":"From 05:45 UTC on 11 May 2023, for about two hours, many Replicate customers got slow responses or HTTP 500 errors from the API and the replicate.com website and had trouble running predictions. Monitoring paged an engineer at 05:46 UTC, a minute after the database connection pool became fully saturated.\n\nIn the PostgreSQL database, INSERT latency jumped within a few minutes from about 1 millisecond to tens of seconds. More queries ran in parallel, each with its own database connection, until the maximum permitted number of connections was used up and new queries could not run at all. The website failed intermittently and was down more than it was up. Customers who received prediction updates by webhook instead of polling the API saw little disruption.\n\nThe first suspicion was the resize of the database primary the day before: perhaps the new primary had slower disks, or an auxiliary job on the new server was using disk I/O. The new asynchronous prediction update code looked an unlikely cause, because it had been enabled for more than 18 hours without visible problems. Replicate's database provider, Crunchy Data, responded within minutes and helped rule out problems with the database itself.","ko":"5월 11일 05:45 UTC쯤 데이터베이스 커넥션 풀이 가득 찼고, 모니터링이 이를 곧바로 감지해 05:46 UTC에 엔지니어를 호출했다. 많은 고객이 replicate.com 웹사이트와 API에서 느린 응답이나 HTTP 500 오류를 받았고, 예측 작업을 제대로 실행하지 못했다.\n\n05:00 UTC가 조금 지나 같은 예측 ID로 들어온 INSERT 쿼리들이 쌓이기 시작했다. 몇 분 사이에 INSERT 지연 시간이 약 1밀리초에서 수십 초로 뛰었다. 동시에 실행되는 쿼리가 늘면서 쿼리마다 커넥션을 하나씩 잡았고, 데이터베이스가 허용하는 최대 커넥션 수를 금세 다 썼다.\n\n커넥션이 남지 않자 새 쿼리는 아예 실행되지 못했다. 웹사이트는 엄밀히는 간헐적으로 실패했지만 이 시간 동안 열리는 때보다 안 열리는 때가 많았다. 예측 결과를 API 폴링 대신 웹훅으로 받는 고객은 영향을 비교적 적게 받았다.\n\n팀은 처음에 전날 데이터베이스 크기를 바꾸면서 무언가를 놓쳤다고 의심했다. 새 프라이머리를 더 느린 디스크로 만들었거나, 새 서버에서 다른 작업이 디스크 I/O를 쓰고 있을 가능성을 살폈다. 비동기 업데이트 코드는 장애 전까지 18시간 넘게 문제없이 켜져 있었기 때문에 원인일 가능성을 낮게 봤다. 데이터베이스 제공사 Crunchy Data가 몇 분 만에 응답했고, 팀과 함께 데이터베이스 쪽 문제를 배제했다."},"updated_at":"2026-11-14T12:34:12.884115Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0483","org_slug":"replicate"}