관리형 서비스 쓰다가 강제로 인프라 엔지니어가 되어버린 사연 : RDS Proxy Pinning

나누는꿀탐험가토리 · 2026.10.20

인프라 담당자가 없는 작은 팀의 구원투수, 관리형 서비스 소규모 개발팀을 이끌다 보면 늘 마주치는 현실적인 벽이 있습니다. 바로 "전담 인프라 엔지니어의 부재"입니다. 비즈니스 로직 짜고 배포하기에도 손이 모자란데, 서버 프로비저닝부터 모니터링, 페일오버 설계까지 신경 쓰는 건 솔직히 사치에 가깝습니다. 그래서 저는 AWS의 완전 관리형 서비스를 참 좋아합니다. 인프라 전문 지식이 깊지 않아도 주요 시스템을 알아서 굴려주니까요. 특히 평시와 피크 타임의 트래픽 격차가 예측 불가능할 정도로 큰 서비스에 RDS Serverless는 가뭄의 단비 같았습니다. 평소엔 자원을 아끼다가 트래픽이 몰리면 무중단으로 알아서 척척 스케일링해 주니, 기본 단가가 조금 나가더라도 유휴 자원 낭비를 줄이는 관점에서는 오히려 남는 장사라고 생각했습니다. 근데 완벽할 줄 알았던 Serverless의 한계가 있었습니다. Serverless가 아무리 트래픽에 맞춰 가변으로 컴퓨팅 파워를 늘려준다 해도, RDBMS 아키텍처의 근본적인 한계는 피할 수 없었습니다. 바로 쓰기(Write) 작업은 오직 단 하나의 인스턴스에서만 처리된다는 점입니다. 자연스럽게 Write DB의 최대 커넥션 수(환경에 따라 대략 5,000개 남짓)라는 천장이 명확해졌습니다. 트래픽이 일시적으로 폭증할 때 수많은 ECS 커넥션이나 람다가 한꺼번에 DB 커넥션을 맺으려 들면, 아무리 오토스케일링이 돌아도 커넥션 풀이 먼저 바닥나며 시스템 전체가 삐걱거리기 시작했습니다. 그래서 "아, 그럼 앞단에서 커넥션을 효율적으로 재사용해 주는 프록시를 두면 되겠구나!" 해결책은 명확해 보였습니다. RDS 바로 앞단에 RDS Proxy를 둔 것입니다. 애플리케이션이 생성하는 수많은 유휴 커넥션을 프록시가 대신 받아주고, 실제 DB 인스턴스로는 꼭 필요한 만큼의 커넥션만 맺어 풀(Pool)을 공유(Multiplexing)해 주는 구조. 이걸 도입하고 나니 커넥션 스파이크도 잡히고, 이제 인프라 고민은 완전히 끝난 줄 알았습니다. 최근 모니터링 지표를 뜯어보다가 이상한 점을 발견했습니다. 커넥션 풀을 효율적으로 돌려쓰라고 붙여둔 프록시인데, 특정 상황에서 여전히 커넥션이 고갈 직전까지 가거나 제대로 반환되지 않는 현상이 발생하는 겁니다. 그 범인은 바로 RDS Proxy의 피닝(Connection Pinning, 세션 고정) 현상이었습니다. RDS Proxy의 핵심은 "쿼리가 끝나면 DB와의 커넥션을 다른 요청이 쓸 수 있게 즉시 반환하는 것(멀티플렉싱)"입니다. 그런데 애플리케이션에서 아래와 같은 패턴을 쓰면, 프록시는 커넥션을 공유하지 못하고 해당 클라이언트에 딱 붙여버립니다(Pinning). ⚬ 애플리케이션 레벨의 Prepared Statement 사용 ⚬ 세션 변수 조작 (SET 명령어로 타임존, 문자셋 등 변경) ⚬ 임시 테이블(Temporary Table) 생성 ⚬ 트랜잭션 격리 수준 변경이나 잠금(Lock) 관련 구문 즉, 애플리케이션 코드는 쿼리를 다 던지고 "나 이제 커넥션 안 써" 하고 풀을 반납했다고 생각하지만, 프록시 입장에서는 세션이 계속 사용될것이라 판단해 해당 백엔드 커넥션을 만료되거나 세션이 완전히 끊길 때까지 계속 붙잡고 있는 것이었습니다. 결국 프록시가 제 역할을 못 하고 커넥션을 독점하는 '피닝'이 누적되면서, 알수없는 순간에 사용가능한 풀이 극단으로 낮아져 장애 까지 이어진..상황 관리형서비스를 쓰면 분명 빠른 도입과 초기의 안정적인 운영은 되지만 결국 알아야하는건 알아야한다는것... 슬프다

댓글

0

최신순