우리는 AWS EKS 기반으로 백엔드/DB 인프라를 운영하고 있다. 트래픽 증가와 서비스 규모 확장에 따라 서버 간 내부 통신 속도, 보안 강화, 비용 절감은 점점 더 중요한 주제가 되었다.
이번 글에서는 서버를 VPC의 Private Subnet 안에서 운영하면서 얻은 성능 향상과 비용 감소 효과, 그리고 실제로 수행한 레이턴시 측정 결과를 공유한다.
서버를 Private Network에 배치해야 하는 이유가 무엇일까?
1. 비용
외부에서 API를 호출할 때는 트래픽이 NAT를 거치게 되면서 NAT Gateway 비용이 증가하게 된다.
특히 API Response의 길이가 길어지면 그만큼 비용이 더 증가할 가능성이 높다.
하지만 AWS는 VPC 내부에서 오가는 트래픽에 대해서는 요금을 부과하지 않는다.
따라서 굳이 트래픽이 외부망을 거칠 필요가 없다면 내부에서만 데이터를 주고받는 것이 비용을 더 아낄 수 있는 좋은 방법이다.
2. 보안
퍼블릭 서브넷에 존재하는 서버는 Public IP에 의해 외부에 노출될 가능성이 있다.
반면 Private Subnet의 서버는 외부에서 직접 접근이 절대 불가능하고, 보안그룹 및 NACL 정책을 더 단순하게 관리 가능하다.
백엔드 서버는 원래 외부에 직접 접근하는 것이 불가능해야 하기 때문에, Private Subnet에 배치하는 것이 당연하다고 생각한다.
프론트엔드에서 접근하는 백엔드 서버는 로드밸런서를 통해 접근하는 것이 옳은 접근 방법이라고 생각한다.
- 사실 어차피 백엔드 서버는 로드밸런서를 통해서라도 접근 가능하기 때문에 보안이 비용/성능과 비교해서 그렇게 큰 문제는 아니다.
하지만 DB는 다르다.
DB는 민감한 데이터들이 많이 저장돼 있기 때문에 어떤 경우에도 직접 접근이 가능하면 안 된다.
심지어 우리 개발자들도 인터넷 상에서도 접근이 불가능하다.
백엔드 서버 말고는 DB에 직접 접근할 일이 없으므로, DB는 반드시 백엔드 서버와 같은 Private Network에 위치해야 DB를 외부에 노출시키지 않고 안전하게 운영할 수 있다.
서비스 초창기에 배포와 관리의 간편성을 위해 Public IP가 있는 EC2에 배포했었는데, 지금 생각하면 무척 위험한 선택이라는 것을 깨닫고 있다.
- 물론 인스턴스 자체는 pem 키가 있어야 하고, DB 자체에도 접근하기 위해서는 인증을 받아야 하긴 하지만, 지금의 생각으로는 아예 접근이 불가능해야 한다고 생각한다.
3. 성능
실제로 개발을 할 때 로컬에서 호출하는 것이 더 빠르다고 느꼈을 것이다.
원인은 운영 DB와 로컬 DB의 차이, 도메인 레이턴시 등 여러 요인이 있겠지만, 실제 환경과 가장 큰 차이는 네트워크의 차이가 아닐까 싶다.
외부 네트워크를 타는 순간, 거쳐야 하는 작업이 상당히 많다. 도메인부터 NAT 등 내부 네트워크로 접근하기 위해 상당한 작업이 필요하다.
하지만 내부에서 충분히 처리가 가능하다면 내부에 전부 몰아넣고, 그 안에서 통신하는 것이 훨씬 간편하다.
게다가 내부에서는 https가 아닌 http로 통신이 가능하니 더 가볍고 빠르게 통신이 가능하다.
이론적으로 생각해도 VPC를 잘 활용해야 한다는 사실은 알겠지만, 실제로 어느 정도 효과가 있을까?
실제 효과를 검증하기 위해 간단한 실험을 해보았다.
실제 우리 운영 서버 API를 외부/내부에서 각각 호출해서 API Response Time을 측정해보기로 했다.
API를 호출하는 간단한 Python Script를 짜서, 동일한 API를 10회 호출하고, 그 시간을 확인하는 방식으로 진행했다.
실험 1 : 외부에서 API 호출하기

이 경우에는 간단하다. https://.../api/v1/... 형식으로 실제 프론트엔드 단에서 접근하는 형식으로 호출하면 된다.
결과는 아래와 같이 650-800 ms 정도 나온 것을 알 수 있다.

실험 2 : 내부에서 호출하기

같은 VPC 내에서 호출하기 위해, 같은 VPC 안에 있는 Inference Server Pod 안으로 들어가 API를 호출했다.
아래 커맨드로 컨테이너 내부에 들어갈 수 있다.kubectl exec -it {pod_name} -n {namespace_name} -- bash
그리고 k8s는 자체 dns를 제공하기에 클러스터 내부에서 서비스 이름으로 내부 컨테이너에 쉽게 네트워크 접근을 할 수 있다.
따라서 아래 같은 주소로 API를 호출하면 된다.http://user-service/api/v1/...
결과는 아래와 같이 30-100 ms 정도 나온 것을 알 수 있다.

한 눈으로 봐도 성능 차이가 눈에 보이는 것을 알 수 있다.
당연한 이야기지만, 많은 계층을 거치는 만큼 지연이 누적될 수밖에 없다.
백엔드 간 트래픽, 그리고 DB 호출은 내부 호출이기 때문에, 실제 운영 성능 향상 효과는 매우 크다.
특히 마이크로서비스 아키텍처(MSA)에서는 백엔드 간 호출이 많기 때문에 이 절감 효과는 더 크게 누적된다.
추가 개선 포인트
우리는 프론트엔드를 Amplify에서 운영하고 있다.
Next.js 프레임워크의 강력한 기능 중 하나인 Server Side Rendering이 있는데, SSR로 페이지를 구성할 경우, 페이지를 구성할 데이터와 html을 서버에서 구성하고 hydration을 하게 된다.
React와 다르게 Next.js는 서버이기 때문에, SSR 시 Fetch 하는 데이터 또한 외부에 노출시키지 않고 내부 VPC 내에서 호출이 가능하다.
하지만 내가 알기론 Amplify에서 운영되는 Next.js 앱을 특정 VPC에 속하게 할 수는 없다고 알고있다.
- Amplify의 내부 원리가 Lambda로 최적화하여 띄우는 것으로 알고 있는데, 자세한 Lambda나 Cloudfront 관련 설정을 할 수 없었다.
페이지의 초기 데이터 로드는 보통 크기가 큰 편이 많아 내부에서 호출하면 비용을 많이 아낄 수 있을 것이라고 생각했으나, Amplify의 커스텀 한계로 이는 활용하지 못 해 아쉬움이 남았다.
- 우리 서비스 특성 상, 초기 데이터가 채팅 데이터, 무한 스크롤 데이터 등 크기가 큰 것이 많아 SSR 시 내부 호출로 처리한다면 큰 이점이 있을 것이라고 생각했다. (아쉽)
백엔드 서버를 Private Subnet으로 이전하는 과정은 단순히 네트워크 구성을 바꾸는 작업이 아니라, 서비스의 체감을 바꾸는 중요한 결정이다.
외부 인터넷을 경유하던 호출을 모두 VPC 내부로 통합함으로써 우리는 응답 속도에서 예상보다 훨씬 큰 개선을 얻었고, 마이크로서비스 간 통신 비용 역시 눈에 띄게 감소했다.
특히 내부 호출이 많은 아키텍처에서는 이러한 변화가 전체 API 성능을 결정짓는 핵심 요소가 된다.
또한 성능뿐만 아니라 비용과 보안 측면에서도 명확한 이점을 제공했다.
NAT 사용량 감소는 곧바로 비용 절감으로 이어졌고, 외부 노출 범위가 줄어들면서 인프라 보안도 한층 강화될 수 있었다.
결국 Private Subnet 기반의 네트워크 설계는 서비스 규모가 커질수록 반드시 갖추어야 할 기반 구조이며, 우리가 구축하고 있는 시스템의 안정성을 크게 높여주는 필수 요소가 되었다.

답글 남기기