{"id":"IL-0574","org":"Safie","date":"2026-10-27","docs":["https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/rds-proxy-pinning.html","https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/rds-proxy-connections.html","https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/rds-proxy.monitoring.html"],"title":{"en":"Aurora MySQL writer CPU stuck near 100% minutes after Safie pointed production at a new Amazon RDS Proxy","ko":"운영 환경의 DB 접속 경로를 Amazon RDS Proxy로 바꾼 지 몇 분 만에 Aurora MySQL writer CPU가 100%에 이르고 에러가 났다"},"domain":["aws","database"],"impact":{"scope":"The platform services that use the main Aurora MySQL database returned errors until the rollback","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"The failure and the later problems were not bugs in RDS Proxy; the application's connection pool implementation and settings were exposed by putting a proxy in between. With a proxy, backend connections are shared, so reuse depends on matching session state, closed transactions and connection lifetimes within the database's own timeouts. Before introducing it, the team should have checked what the application pool runs when it returns a connection, how it sets connection lifetime and what it runs on connect, more than the proxy settings themselves.","ko":"이번 장애와 이후의 문제는 RDS Proxy의 버그가 아니었고, Proxy를 끼우면서 애플리케이션 커넥션 풀의 구현과 설정에 있던 문제가 드러난 것이었다. Proxy를 끼우면 백엔드 커넥션을 여러 클라이언트가 나눠 쓰므로, 세션 상태가 같은지, 트랜잭션이 닫혔는지, 커넥션이 DB 쪽 수명 안에 있는지가 모두 재사용 조건이 된다. 도입 전에는 Proxy 설정 값보다 애플리케이션 커넥션 풀이 커넥션을 반납할 때 무엇을 실행하는지, 커넥션 수명을 어떻게 정하는지, 접속할 때 무엇을 보내는지를 확인했어야 했다. 타임아웃과 상한은 애플리케이션, Proxy, 데이터베이스 순으로 아래 계층일수록 같거나 길게 맞춘다. 엔드포인트만 바꾸는 한 번의 전환은 실패하면 모든 서비스에 한꺼번에 번지므로 단계적으로 옮겨야 한다."},"related":[],"sources":[{"url":"https://zenn.dev/safie_inc/articles/27d27c61e3aa2a","kind":"blog","archived":null}],"summary":{"en":"Safie's platform runs as microservices that read and write the same Aurora MySQL database, with a large share of write transactions. max_connections was already at its maximum of 16,000 on an instance class large enough for it, and connections kept rising with users, so the team put Amazon RDS Proxy in front of the database to multiplex many client connections onto fewer database connections. The settings were estimated from SHOW PROCESSLIST counts per client host. After about a week in staging, where the expected drop in connections did not show but the application worked, the change went to production.\n\nMeasured demand from the applications was about 7,600 connections, but MaxConnectionsPercent of 21% let the proxy open only about 3,360 connections to Aurora, so switching the endpoint cut the usable connections from 16,000 to 3,360 and about 4,200 connections had to wait to borrow one. Because ConnectionBorrowTimeout equalled the application's 7-second socket timeout, the applications timed out first, dropped the connection and opened a new one. Setting up new connections costs CPU in MySQL, and as CPU saturated, connection setup slowed further and more timeouts followed in a loop. The team rolled back at once by returning the ECS Fargate tasks that used RDS Proxy to their previous version.\n\nThe team reproduced the failure on a copy of Aurora restored from a staging snapshot, loaded with Locust, and confirmed that raising MaxConnectionsPercent to 62% removed it. RDS Proxy was then moved in step by step with feature flags in Flipt per ECS task, read requests first. Months later, with reads fully moved, the multiplexing worked but the Aurora writer's connections had risen by 5,000, from 6,400 by day and 4,200 at night to 11,700 and 8,900, because the proxy kept idle backend connections up to MaxIdleConnectionsPercent. Lowering that limit far enough would have meant reopening thousands of connections at the burst that comes at a fixed time every hour, close to the original failure, so Safie withdrew RDS Proxy.","ko":"Safie의 플랫폼은 여러 마이크로서비스가 같은 Aurora MySQL에 읽고 쓰는 구조이고 쓰기 트랜잭션 비중이 크다. max_connections를 최대치인 16,000까지 쓸 수 있는 인스턴스 클래스로 이미 올렸는데도, 이용자가 늘며 커넥션 수가 계속 늘었다. 팀은 많은 클라이언트 커넥션을 적은 수의 DB 커넥션으로 묶는 RDS Proxy를 넣기로 했다. SHOW PROCESSLIST로 커넥션 출처를 집계해 MaxConnectionsPercent 21%, MaxIdleConnectionsPercent 10%, ConnectionBorrowTimeout 7초로 정했다. 스테이징에서 1주일쯤 돌렸을 때 커넥션 수 감소 같은 기대한 변화는 보이지 않았지만, 애플리케이션 동작에 문제가 없어 운영 환경에 배포했다.\n\n엔드포인트를 바꾸고 몇 분 뒤 에러 알림이 울렸고, 팀은 바로 ECS Fargate 태스크를 이전 버전으로 되돌렸다. 실제 커넥션 수요는 약 7,600개였는데 Proxy가 Aurora에 열 수 있는 상한은 16,000의 21%인 약 3,360개였다. 나머지 약 4,200개는 Proxy에서 커넥션을 빌리려고 기다렸다. 대기 시간과 애플리케이션 소켓 타임아웃이 같은 7초여서, 대기가 풀리기 전에 애플리케이션이 먼저 접속을 끊고 새로 접속했다. MySQL은 새 커넥션을 처리할 때마다 CPU를 썼다. CPU가 포화되자 접속이 더 늦어지고 타임아웃이 더 늘어나는 악순환이 이어졌다.\n\n팀은 스테이징 스냅샷으로 만든 검증용 Aurora에 Locust로 부하를 걸어 같은 장애를 재현했고, MaxConnectionsPercent를 62%로 올리자 사라지는 것을 확인했다. 이후 Flipt 피처 플래그로 조회 요청부터 비율을 나눠 옮겼다. 그 과정에서 두 문제를 고쳤다. 하나는 애플리케이션의 커넥션 풀이 커넥션을 반납할 때마다 세션을 리셋해 Proxy가 커넥션을 재사용하지 못하던 문제였다. 다른 하나는 Aurora의 wait_timeout 120초가 Proxy가 빌려준 커넥션을 끊던 문제였다. 그러나 Proxy가 한 번 연 커넥션을 유휴 예비 커넥션으로 계속 쥐고 있어 Aurora writer의 커넥션 수는 오히려 약 5,000개 늘었다. 매시 정해진 시각에 커넥션이 급증하는 탓에 예비 커넥션을 줄일 수도 없어, 팀은 RDS Proxy 도입을 접었다."},"trigger":{"en":"The production application endpoints were switched to the new RDS Proxy all at once, with MaxConnectionsPercent at 21%, MaxIdleConnectionsPercent at 10% and ConnectionBorrowTimeout at 7 seconds, the same as the application's socket timeout, after a week in staging had shown no problem.","ko":"운영 환경의 Aurora MySQL 접속 엔드포인트를 RDS Proxy로 바꿨다. Proxy는 MaxConnectionsPercent 21%로 Aurora에 커넥션을 약 3,360개만 열 수 있었고, ConnectionBorrowTimeout은 애플리케이션 소켓 타임아웃과 같은 7초였다."},"severity":"unknown","symptoms":["database-overloaded","high-error-rate"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":{"en":"Safie's alert monitoring system fired on errors a few minutes after the endpoint was switched to RDS Proxy.","ko":"운영 환경의 엔드포인트를 RDS Proxy로 바꾸고 몇 분 뒤 사내 알림 모니터링 시스템이 에러 알림을 냈다."},"components":["database-proxy","database"],"root_cause":"config-change","remediation":[{"text":{"en":"Rolled back the ECS Fargate tasks that used RDS Proxy to their previous version","ko":"그 자리에서 되돌리기로 하고, RDS Proxy를 보는 애플리케이션 서버인 ECS Fargate 태스크를 이전 버전으로 되돌렸다."}}],"action_items":[{"text":{"en":"Raise MaxConnectionsPercent to 62% and MaxIdleConnectionsPercent to 31%","ko":"검증 환경에서 설정 값만으로 장애가 재현되고 해소되는 것을 확인한 뒤 MaxConnectionsPercent를 62%로, MaxIdleConnectionsPercent를 31%로 바꿨다."}},{"text":{"en":"Choose between direct Aurora and RDS Proxy with a feature flag evaluated per ECS task, so the switch can be made in stages and undone without a deployment","ko":"애플리케이션 안에서 피처 플래그를 평가해 Aurora 직결과 Proxy 경유 중 어디로 접속할지 요청마다 정하게 했다. 플래그는 ECS 태스크 ID의 해시로 태스크 단위로 나눠 한 태스크 안에서 접속 대상이 섞이지 않게 했다."}},{"text":{"en":"Move read requests first and write requests afterwards","ko":"트랜잭션 중간에 커넥션이 끊길 때 영향이 큰 쓰기 요청은 뒤로 미루고, 조회용 GET 요청부터 옮긴다."}},{"text":{"en":"Raise the share in steps of 1%, 10%, 25%, 50%, 75% and 100%, checking proxy borrow wait, new backend connections, Aurora connections, CPU and latency and application errors before each step","ko":"옮기는 비율은 1%, 10%, 25%, 50%, 75%, 100%로 단계적으로 올린다. 단계마다 Proxy의 대기 시간과 새 백엔드 커넥션 수, Aurora의 커넥션 수와 CPU와 지연, 애플리케이션 에러 수를 보고 다음 단계로 간다."}}],"contributing":["retry-storm","staging-not-representative","no-staged-rollout"],"recurrence_of":null,"symptoms_text":{"en":"A few minutes after the production endpoint was switched to RDS Proxy, Safie's alert monitoring system fired on errors, and the CPU use of the Aurora MySQL writer was stuck near 100%.\n\nIn CloudWatch, new connection attempts (ConnectionAttempts), normally under 10,000, peaked at 264,000, and disconnected clients (AbortedClients) reached 258,000.\n\nThe first suspect was RDS Proxy connection pinning, but only about 1% of connections were pinned, which made it a weak explanation. Further investigation showed that the proxy's connection limit was less than half of the real connection demand.","ko":"운영 환경의 엔드포인트를 RDS Proxy로 바꾸고 몇 분 뒤 사내 알림 모니터링 시스템에서 에러 알림이 울렸다. Aurora writer의 CPU 사용률은 거의 100%에서 내려오지 않았다.\n\nCloudWatch 지표에서 새 접속 시도 수인 ConnectionAttempts는 평소 1만 미만이던 것이 최대 264,000까지 올랐고, 끊긴 클라이언트 수인 AbortedClients는 258,000이었다.\n\n팀은 처음에 RDS Proxy에서 커넥션이 pinning되는 현상을 의심했다. 그러나 실제로 pinning된 커넥션은 전체의 1% 정도여서 원인으로 보기 어려웠다."},"updated_at":"2026-11-14T12:34:22.107424Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0574","org_slug":"safie"}