{"id":"IL-0316","org":"Railway","date":"2025-09-22","docs":[],"title":{"en":"Railway's control plane slowed and deployments stopped after a PgBouncer version jump used abnormal CPU and memory","ko":"밀린 배포가 한꺼번에 몰린 Control Plane 에서 새 버전 PgBouncer 가 CPU 와 메모리를 비정상적으로 많이 써 데이터베이스 연결이 타임아웃됐다"},"domain":["database"],"impact":{"scope":"Dashboard (project canvas stuck loading) and the deployment pipeline across Dashboard, GitHub webhooks and CLI; deployments suspended for non-Pro users and, for up to 20 minutes, for all users; running deployments and platform-level networking stayed online","users":"Users who opened the dashboard or started deployments during the incident","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Railway believes that without the breaking schema change reaching production the cascade would not have happened, that monitoring PgBouncer's own CPU, memory and pool metrics would have shown the performance regression earlier and shortened recovery, and that upgrading PgBouncer instances one at a time would have exposed the version-specific problem before it reached every instance.","ko":"Railway 는 호환되지 않는 스키마 변경이 운영에 닿지 않았다면 이번 연쇄 장애가 없었을 것으로 보았다. PgBouncer 의 성능 저하를 미리 알았다면 훨씬 빨리 복구할 수 있었다고 했다. PgBouncer 를 한꺼번에 올리지 않고 인스턴스마다 차례로 올렸다면 전체에 퍼지기 전에 버전별 성능 문제를 찾았을 것이라고도 했다."},"related":[],"sources":[{"url":"https://blog.railway.com/p/incident-report-sept-22-2025","kind":"blog","archived":"https://web.archive.org/web/20261023024734/https://blog.railway.com/p/incident-report-sept-22-2025"}],"summary":{"en":"The day began with a separate failure. During a code cleanup Railway removed an unused database column, a later code change unintentionally reverted part of that, and a core API that the dashboard relies on began to fail. From 11:05 UTC users reported that the project canvas would not load; the incident was declared at 11:14, a fix was deployed within 15 minutes and full restoration was reported at 11:45. The deployments that had queued meanwhile then started together, and from 11:48 the control plane showed high resource use and API latency. At 12:14 Railway linked the two problems and reopened the first incident.\n\nRailway suspended deployments in phases to drain the queue and scaled up the control plane's database, but the problems continued. The cause was PgBouncer. Railway had used an older Bitnami image of PgBouncer and, after Bitnami deprecated its public images, had moved to an internal mirrored repository, which advanced PgBouncer by several versions. Under load the new version used abnormally high CPU and memory, and Railway identifies a breaking default configuration change in PgBouncer as the likely cause. Railway rolled PgBouncer back to the previous stable version instead of adjusting the configuration, saw a 100x performance increase with all metrics back to nominal, and had deployments restored for all tiers by 14:01 UTC. At 21:27 a rare edge case in which private networks and their endpoints no longer appeared on the dashboard was fixed retroactively.","ko":"Railway 대시보드와 프로젝트 캔버스는 API 에서 데이터를 받는다. 팀은 코드 정리 중 쓰지 않는 컬럼을 지우는 스키마 변경을 했고, 뒤이은 코드 변경이 그 일부를 의도치 않게 되돌려 프런트엔드가 쓰는 핵심 API 가 실패했다. 2025-09-22 11:05 UTC 에 캔버스가 열리지 않는다는 신고가 들어왔고, 11:14 UTC 에 부분 장애로 사고를 선언했으며, 15분 안에 수정을 배포해 11:45 UTC 에 해결로 표시했다.\n\n첫 문제가 풀리자 밀려 있던 배포가 한꺼번에 시작됐고, 이 부하를 Control Plane 이 감당하지 못해 데이터베이스 오류가 늘었다. 11:48 UTC 에 Control Plane 의 자원 사용과 API 지연이 비정상으로 올라 새 사고를 열었고, Free, Trial, Hobby 사용자의 배포를 멈췄다. 12:14 UTC 에 두 문제가 이어진 것을 알고 원래 사고를 다시 열었다. 12:25 UTC 에 Pro 를 포함한 모든 배포를 최대 20분 멈췄다. 12:44 UTC 에 Pro, 12:50 UTC 에 그 밖의 사용자 배포를 되살렸지만, 13:05 UTC 에 Control Plane 이 계속 불안정해 Pro 가 아닌 사용자의 배포를 다시 멈췄다. 그 사이 Control Plane 데이터베이스의 CPU, 메모리, IOPS 를 크게 늘리고 커넥션 한도를 조정했지만 성능 문제는 이어졌다.\n\n조사 끝에 커넥션 풀러인 PgBouncer 가 정상 범위를 넘는 CPU 와 메모리를 쓰는 것을 찾았다. Railway 는 오래된 Bitnami 이미지를 쓰다가 Bitnami 가 공개 이미지를 지원 중단하자 내부 미러 저장소로 옮겼다. 이 과정에서 PgBouncer 가 몇 버전 올라갔다. 새 버전은 부하가 걸리자 CPU 와 메모리를 비정상적으로 많이 써 지연과 데이터베이스 연결 타임아웃을 일으켰다. Railway 는 PgBouncer 의 기본 구성이 호환되지 않게 바뀐 것을 가능성이 높은 원인으로 보았다. 팀은 설정을 맞추는 대신 안정적이던 이전 PgBouncer 버전으로 곧바로 롤백했고, 성능이 100배 좋아지며 모든 지표가 정상으로 돌아왔다. 14:01 UTC 에 모든 사용자 등급의 배포가 돌아온 것을 확인했다. 21:27 UTC 에는 사설 네트워크와 그 엔드포인트가 대시보드에 보이지 않던 드문 경우를 뒤늦게 고쳤다."},"trigger":{"en":"After a dashboard outage caused by a schema change was fixed, a large backlog of queued deployments started at the same time and put the control plane and its database, behind a newly upgraded PgBouncer, under heavy load.","ko":"코드 정리 중 쓰지 않는 컬럼을 지우는 스키마 변경을 했는데, 뒤이은 코드 변경이 그 일부를 의도치 않게 되돌려 프런트엔드가 쓰는 핵심 API 가 실패했다. 이 문제를 고친 뒤 밀린 배포가 한꺼번에 시작되면서, 몇 버전 올라간 PgBouncer 를 쓰던 Control Plane 이 부하를 이기지 못했다."},"severity":"unknown","symptoms":["high-latency","intermittent-timeouts","deploys-failing"],"timeline":{"detected_after":null,"resolved_after":"2h 56m"},"date_kind":"incident","detection":{"en":"Users reported at 11:05 UTC that the project canvas failed to load; the control plane's abnormal resource consumption and elevated API latency were seen at 11:48 UTC and opened as a new incident.","ko":"11:05 UTC 에 사용자들이 Railway 프로젝트 캔버스가 열리지 않는다고 신고했다. 두 번째 문제는 11:48 UTC 에 Control Plane 의 자원 사용이 비정상으로 늘고 API 지연이 높아지면서 드러났다."},"components":["database","database-proxy"],"root_cause":"upgrade-breaking-change","remediation":[{"text":{"en":"Deployed a fix for the API failure caused by the schema change within 15 minutes","ko":"사고를 선언하고 15분 안에 수정을 배포해 프로젝트 캔버스 문제를 풀었다."}},{"text":{"en":"Suspended deployments for non-Pro users so Pro users could deploy and the queue could drain","ko":"먼저 Free, Trial, Hobby 등급 사용자의 배포를 멈춰 Pro 사용자는 평소대로 배포하게 하고 배포 대기열이 차츰 줄게 했다."}},{"text":{"en":"Suspended all deployments, Pro included, for up to 20 minutes during peak instability","ko":"가장 불안정할 때는 Pro 를 포함한 모든 새 배포를 최대 20분 멈춰 대기열을 더 줄였다."}},{"text":{"en":"Scaled up the control plane database's CPU, memory, connection limits and IOPS","ko":"Control Plane 데이터베이스의 CPU 와 메모리를 늘리고, 커넥션 한도를 조정하고, IOPS 용량을 늘렸다."}},{"text":{"en":"Rolled PgBouncer back to the previous stable version, which brought all metrics back to nominal","ko":"설정을 손보는 대신 안정적이던 이전 PgBouncer 버전으로 곧바로 롤백했고, 성능이 100배 좋아지며 모든 지표가 정상으로 돌아왔다."}},{"text":{"en":"Re-enabled deployments for all non-Pro users","ko":"롤백 뒤 Pro 가 아닌 사용자 모두의 배포를 다시 열었다."}},{"text":{"en":"Fixed the edge case in which private networks and their endpoints were missing from the dashboard","ko":"21:27 UTC 에 사설 네트워크와 그 엔드포인트가 대시보드에 보이지 않던 드문 경우를 뒤늦게 고쳤다."}}],"action_items":[{"text":{"en":"Re-engineer parts of the control plane to be more resilient, moving large parts of its storage layer away from Postgres","ko":"Control Plane 저장 계층의 큰 부분을 Postgres 밖으로 옮기는 재설계를 계속한다. 이 작업은 3분기 초에 시작했고, 한 리전의 Control Plane 장애가 플랫폼 전체에 번지는 것을 막고 지금의 Postgres 보다 몇 자릿수 높은 IOPS 를 낼 것을 목표로 한다."}},{"text":{"en":"Add CI validation that keeps disruptive schema changes out of production and automated schema compatibility checks before backend deployments","ko":"CI 파이프라인 검증을 강화해 중단을 일으키는 스키마 변경이 운영에 닿지 못하게 하고, 백엔드 배포 전에 스키마 호환성을 자동으로 검사한다."}},{"text":{"en":"Monitor and alert on PgBouncer node CPU, memory and connection pool utilization","ko":"PgBouncer 노드의 CPU, 메모리, 커넥션 풀 사용률을 모니터링하고 알림을 건다."}},{"text":{"en":"Upgrade PgBouncer in phases, instance by instance, instead of everywhere at once","ko":"PgBouncer 업그레이드는 한꺼번에 하지 않고 인스턴스마다 단계적으로 적용한다."}}],"contributing":["unpinned-version","no-staged-rollout","monitoring-blind-spot","default-config-unchanged"],"recurrence_of":null,"symptoms_text":{"en":"At 11:48 UTC on 22 September 2025, minutes after Railway had resolved a dashboard outage, its control plane showed abnormal resource consumption and elevated API latency. A large backlog of deployments queued during the first outage had started all at once, and the control plane began returning elevated database errors.\n\nUsers saw an infinite loading state on their project canvas and delayed deployments, because the dashboard needs control plane APIs for data such as service domains and private network endpoints. Railway suspended deployments for Free, Trial and Hobby users at 11:48, and they saw a \"Limited Access\" message when trying to deploy; at 12:25 it suspended deployments for all tiers, Pro included, for up to 20 minutes. Some users also had issues with \"Invalid database URL\" or missing Private Networking.\n\nThe team first treated it as load and scaled up the control plane database's CPU and memory, tuned its connection limits and expanded its IOPS. Performance problems continued. Deployments came back for Pro users at 12:44 and non-Pro users at 12:50, but were withdrawn again for non-Pro users at 13:05 because the control plane stayed unstable. Further investigation found PgBouncer, the connection pooler in front of the control plane database, using far more CPU and memory than normal, which showed as increased latency and database connection timeouts.","ko":"2025-09-22 11:05 UTC 에 Railway 프로젝트 캔버스가 열리지 않는다는 첫 신고가 들어왔다. 캔버스는 실제 오류를 보여 주지 않고 끝없이 로딩 상태에 머물렀다.\n\n11:35 UTC 에 첫 문제를 고치고 11:45 UTC 에 해결로 표시했다. 그러나 11:48 UTC 에 Control Plane 의 자원 사용이 비정상으로 늘고 API 지연이 높아졌다. 대시보드, GitHub 웹훅, CLI 어디서든 배포가 실패했고 대시보드 로딩 실패가 이어졌다. 팀은 이것을 새 사고로 열었다가 12:14 UTC 에 두 문제가 이어져 있다는 것을 알고 원래 사고를 다시 열었다.\n\n대시보드는 서비스 도메인과 사설 네트워크 엔드포인트 같은 핵심 데이터를 Control Plane API 에서 받기 때문에 제대로 열리지 않았다. 배포를 시작한 사용자는 \"Limited Access\" 메시지를 보았고, 일부 사용자는 \"Invalid database URL\" 문제를 겪거나 사설 네트워킹이 보이지 않았다.\n\n밀린 배포가 한꺼번에 시작되며 Control Plane 이 감당하지 못했고, 이것이 데이터베이스 오류 증가로 나타났다. Control Plane 의 API 서버에서는 CPU 와 메모리가 치솟았고, 지연이 늘며 데이터베이스 연결이 타임아웃됐다.\n\n팀은 처음에 Control Plane 데이터베이스의 용량을 의심해 CPU, 메모리, IOPS 를 늘리고 커넥션 한도를 조정했지만 성능 문제는 그대로였다. 더 조사하자 커넥션 풀링 계층인 PgBouncer 가 정상 범위를 넘는 CPU 와 메모리를 쓰고 있었다."},"updated_at":"2026-11-14T12:33:56.974221Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0316","org_slug":"railway"}