AWS 기술 블로그
Amazon RDS Proxy를 활용한 롯데이커머스의 Amazon RDS 커넥션 불균형 해결 사례
이커머스 플랫폼 운영 시 할인 행사로 인해 특정 기간 대규모의 사용자 요청이 유입될 수 있습니다. 데이터베이스로 Amazon Aurora를 사용하는 경우 다수의 읽기 복제본 인스턴스로 확장하여 대규모 요청을 처리할 수 있습니다. 이때, 각 데이터베이스와 애플리케이션 간 커넥션의 효율적인 재사용을 위해 데이터베이스 커넥션 풀을 많이 활용하곤 합니다. 이런 노력이 애플리케이션의 블루/그린 배포 전략과 만나게 될 경우 예상치 못하게 대량의 데이터베이스 커넥션이 특정 읽기 복제본으로 몰리는 문제가 발생하곤 합니다. 이 게시물에서는 롯데이커머스가 겪었던 이러한 문제에 대해 소개하고, Amazon RDS Proxy를 적용하여 해결한 과정을 설명합니다.
롯데이커머스는?
다양한 업종의 롯데그룹 관계사와 고객들을 지원하기 위해 롯데이커머스는 수차례 변신을 경험했습니다. 1996년 자체 전산실 운영을 시작으로 2000년 국내 첫 IDC 입주, 2015년 AWS 도쿄 리전에서 서비스 운영, 2016년 AWS 서울 리전에서 서비스 운영을 거쳐 2020년에 롯데그룹의 이커머스 플랫폼인 롯데온을 AWS 환경에서 오픈했습니다. 현재 롯데온은 마이크로서비스 아키텍처(MSA)로 Amazon Elastic Kubernetes Service(EKS) 상에서 운영 중이며 지속적인 배포와 유연한 확장성, 높은 안정성의 장점을 기반으로 비즈니스를 가속화하고 있습니다.
롯데온에서 운영하는 각 서비스는 프로그래밍 언어인 Java로 개발되어 있으며 Amazon Aurora MySQL을 운영 데이터베이스로 사용하고 있습니다.
Amazon Aurora MySQL 소개
Amazon Aurora MySQL은 오픈소스 MySQL과 완벽하게 호환되며, OLTP(Online Transaction Processing) 워크로드에 적합한 완전 관리형 관계형 데이터베이스 엔진입니다. Amazon Aurora와 같은 클라우드 네이티브 데이터베이스를 사용하면 하드웨어 프로비저닝, 데이터베이스 설정, 패치 및 백업과 같은 소모적인 운영 업무를 자동화하면서도 상용 데이터베이스의 1/10의 비용으로 성능 집약적인 애플리케이션 및 중요한 워크로드를 지원할 수 있습니다. IDC 조사에 따르면 Amazon Aurora를 사용하는 고객은 단 3년 만에 439%의 투자 수익을 달성한 것으로 기록되었습니다. 이러한 이유로 기존 모놀리식 아키텍처에서 벗어나 마이크로 서비스로 전환할 때 크게 비용을 절감할 수 있고 혁신의 속도를 높일 수 있습니다.
Amazon Aurora의 데이터베이스 볼륨은 3개의 가용 영역에서 6개의 데이터 복사본을 배포하여 데이터 유실을 방지하고, 클러스터 내 인스턴스들은 공유 클러스터 스토리지 볼륨을 통해 데이터를 공유합니다. 이러한 아키텍처의 이점으로 최대 15개의 읽기 전용 복제본을 지원하여 읽기 성능을 높임과 동시에 인스턴스 장애 시 다중 AZ 기능으로 3개의 가용 영역 중 하나에 생성된 읽기 복제본 중 하나로 장애 조치를 자동화합니다.
롯데 이커머스에서 Amazon Aurora를 선택한 두 가지 이유가 있습니다. 첫째로 적은 인력으로 대규모의 데이터베이스를 운영해야 하는 상황에서 운영 부담을 최소화해야 했습니다. 둘째로 이커머스를 사용하는 고객은 항상 최신의 데이터를 이용할 수 있어야 하는데 Amazon Aurora는 공유 클러스터 스토리지 볼륨 아키텍처로 데이터의 빠른 동기화가 가능하다는 것이었습니다.
커넥션 불균형 문제 발생
애플리케이션에서 데이터베이스로 SQL 문을 쿼리할 때마다 커넥션을 새로 생성하는 것은 사용자의 요청 응답에 지연을 발생시킵니다. 일반적으로 애플리케이션 내에서 다수의 커넥션을 미리 생성해 놓고, 재사용하는 커넥션 풀을 사용합니다. 롯데이커머스에서는 Amazon EKS 클러스터에서 운영되는 수십 개의 애플리케이션들이 커넥션 풀을 사용하여 데이터베이스로 커넥션을 확보해 놓습니다. 이런 이유로 커넥션 풀 사이즈를 30개로 지정한 애플리케이션 프로세스가 10개 실행 중이라면 총 300개의 데이터베이스 커넥션이 생성됩니다.
게다가 롯데이커머스에서는 애플리케이션 배포 시 블루/그린 배포 전략을 사용하기 때문에 애플리케이션 배포가 진행될 때 대량의 데이터베이스 커넥션이 생성됩니다. 블루/그린 배포 전략은 새로운 버전의 애플리케이션을 미리 준비해놓고 한번에 전환하는 전략을 의미합니다. 일시에 대량의 커넥션 생성되는 경우에 일부 읽기 복제본 인스턴스로 커넥션이 집중되면서 SQL 쿼리 요청이 해당 인스턴스들에서 주로 발생하게 되어 CPU 사용량이 급증하는 문제가 발생했습니다.
그 결과 롯데온을 이용하는 고객은 데이터베이스의 성능 저하로 인한 응답 지연으로 불편함을 겪게 되었습니다. 참고로 위와 같은 지표는 Amazon Aurora의 모니터링 탭에서 지표를 확인할 수 있고, 향상된 모니터링 및 성능 개선 도우미를 사용하면 더 많은 지표를 확인할 수 있습니다. Amazon CloudWatch의 경보를 설정하면 발생한 문제에 대해 조기에 감지하여 대처할 수 있습니다.
커넥션 풀의 크기만큼 커넥션이 생성되고 나면 DataBase Connection Pool(DBCP) 설정 중 maxAge에 지정된 시간만큼 재연결 없이 커넥션을 유지하게 됩니다. 여기서 maxAge란 커넥션 풀에 미리 생성된 커넥션들이 유지될 수 있는 최대 시간을 의미합니다. 즉, 인스턴스의 커넥션 분포에 불균형이 발생한 후 maxAge 시간만큼 불균형 현상이 유지된다는 것을 의미합니다.
고객은 할인 행사를 대비해 읽기 전용 복제본 수를 15대까지 확장하더라도 커넥션이 집중된 인스턴스로 쿼리가 대다수 요청되면서 응답 지연 문제를 겪게 되었습니다. maxAge로 지정된 시간은 해당 커넥션으로 쿼리를 실행하면 maxAge의 시간 카운팅이 초기화됩니다. 이런 이유로 동시에 커넥션이 생성되었더라도 만료되는 시간은 각기 달라집니다. 당시 고객은 maxAge 설정값을 30분으로 설정했기 때문에 배포 후 30분이 지난 시점부터 커넥션 불균형이 점차 완화되었습니다.
문제 해결을 위한 재현 테스트
고객은 커넥션이 원활하게 분산되지 않는 문제의 원인을 커넥션 풀의 성능 문제로 생각하여 고성능의 커넥션 풀을 제공하는 HikariCP를 적용하였습니다. HikariCP는 빠르고 안정적인 JDBC 커넥션 풀이며, Java 스프링 부트 2.0부터는 기본 JDBC 커넥션 풀로 채택된 라이브러리입니다.
고객은 HikariCP를 적용한 후 문제가 해결되었는지 확인하기 위해 동시 커넥션에 대한 테스트를 진행했습니다. 먼저 스레드를 100개를 생성하여 동시에 데이터베이스로 커넥션을 생성했고, 다음으로는 스레드별로 0.5초의 간격을 두고 데이터베이스에 커넥션을 생성하였습니다.
테스트 결과 동시에 데이터베이스 커넥션을 생성했을 때는 기존과 동일하게 커넥션이 특정 읽기 복제본 인스턴스로 집중되는 문제가 발생하였고, 0.5초의 간격을 설정한 경우 균등하게 분산되었습니다. 이를 통해 고객은 커넥션 풀의 성능 문제가 아니라 데이터베이스 커넥션 생성 시 일정 시간 간격을 둬야 한다는 것을 알게 되었습니다.
이는 Amazon Aurora가 읽기 전용 복제본으로 작업을 분산하는 방식과 관련이 있습니다. Amazon Aurora는 Select 쿼리의 경우 Reader 엔드포인트를 지정하여 클러스터의 읽기 전용 복제본 인스턴스 간에 작업을 분산합니다. 이때 각 읽기 전용 복제본 인스턴스는 고유한 IP 주소를 가지고 있고, 라운드로빈 DNS 해석(resolution)을 통해 읽기 전용 복제본 인스턴스가 선택됩니다.
여기서 DNS 해석이란, 도메인 네임을 IP 주소로 변환하는 것을 의미하며 DNS lookup이라고도 합니다. 도메인 네임에 등록된 다수의 IP 중 하나가 라운드 로빈 방식으로 선택되지만, DNS 캐싱과 클라이언트 측 캐싱으로 인해 커넥션이 고르게 분포되지 않을 수 있습니다. 특히 롯데이커머스의 상황처럼 블루/그린 배포 전략을 사용하고, 커넥션 풀을 사용하는 경우에는 불균형 현상이 더 심해질 수 있습니다. 커넥션 풀의 maxAge 설정값이 너무 길면 그 시간만큼 불균형이 유지되기 때문에 워크로드에 따라 적절한 값을 지정해야 합니다.
위 테스트 결과처럼 커넥션을 일시에 생성하지 않고 일정 간격을 두고 생성하면 문제는 해결되지만, 이 간격만큼 커넥션 생성 시간이 소요되기 때문에 결과적으로 배포가 늦어지는 또 다른 문제가 발생합니다. 게다가 애플리케이션 코드를 수정이 필요하고, 이로 인한 사이드 이펙트가 발생할 소지가 있기 때문에 다른 해결책이 필요했습니다.
Amazon RDS Proxy 적용
Amazon RDS Proxy는 데이터베이스 커넥션 풀을 제공하고, 커넥션 유실 없이 더 빠르게 페일오버를 가능하게 하는 완전 관리형 서비스입니다. Amazon RDS Proxy를 사용하면 더 이상 애플리케이션에서 커넥션 풀을 관리할 필요가 없습니다. 애플리케이션이 블루/그린으로 배포되더라도 커넥션 풀은 Amazon RDS Proxy가 관리하기 때문에 동시에 데이터베이스에 커넥션을 생성하는 문제는 발생하지 않습니다. 고객은 Amazon RDS Proxy를 적용하기 위해 성능 테스트를 진행했습니다.
부하 테스트를 통해 읽기 전용 복제본으로의 커넥션이 고르게 분포되는 것을 확인했습니다. 부하 테스트에서 Amazon RDS Proxy로 인해 기존 대비 2~7% 정도 성능 저하를 확인했지만, 데이터베이스 인스턴스의 CPU를 한계치까지 사용하는 부하 테스트인 점을 감안하여 운영 환경 적용에 문제는 없다고 판단하였습니다. 실제로 운영 환경에 적용한 후 성능 저하를 체감하지 못할 정도였습니다. Amazon RDS Proxy를 적용한 이후 DB 자원을 효율적으로 사용할 수 있게 되면서 읽기 전용 복제본 인스턴스 수를 축소하여 연간 약 1.17억 원을 절감할 수 있었습니다.
마무리
롯데이커머스 사례처럼 커넥션 풀과 블루/그린 배포 전략을 함께 사용하여 읽기 복제본 인스턴스로 대규모의 커넥션 생성 요청이 있는 경우 Amazon RDS Proxy가 애플리케이션 배포 방식과 상관없이 균일하게 커넥션을 분산할 수 있도록 합니다. 또한 Amazon RDS Proxy가 제공하는 빠른 페일오버를 통해 안정성 향상에도 도움이 됩니다.