글로벌 사용자를 대상으로 하는 서비스를 만들고자 한다면 프론트 서버, 백엔드 서버, DB를 어느 리전에 둬야 하는지 고민하게 된다. 단순히 "사용자와 가까운 곳"만 기준으로 삼으면 충분하지 않다. 실제 응답 속도는 사용자와 서버 사이의 거리뿐 아니라, 백엔드 서버와 DB 사이의 왕복 지연에도 크게 영향을 받기 때문이다.
지연 시간은 요청과 응답이 오가는 시간이다. 사용자가 프론트 서버와 가깝더라도, 그 뒤에서 백엔드 서버와 DB가 멀리 떨어져 있으면 전체 응답 시간은 충분히 느려질 수 있다. 그래서 서버 위치를 결정할 때는 사용자, 프론트 서버, 백엔드 서버, DB 사이의 실제 요청 경로를 함께 봐야 한다.
핵심은 "누가 백엔드 API를 호출하는가"와 "백엔드가 DB와 얼마나 자주 통신하는가"이다. 이 두 질문에 따라 백엔드 서버를 어디에 두는 것이 유리한지가 달라진다.
먼저 프론트 서버가 백엔드 API를 호출하는 구조를 보자.
이 구조는 SSR, 서버 컴포넌트, BFF처럼 프론트 서버가 화면에 필요한 데이터를 모아 사용자에게 전달할 때 흔하다.
이때 프론트 서버와 백엔드 서버가 멀리 떨어져 있으면, 프론트 서버가 백엔드까지 긴 왕복을 해야 한다. 사용자는 가까운 프론트 서버에 접속했더라도, 그 뒤에서 프론트와 백엔드가 멀리 통신하느라 응답을 기다리게 된다.
따라서 프론트 서버가 백엔드를 호출하는 구조라면, 프론트 서버와 백엔드 서버를 같은 리전 또는 가까운 리전에 두는 것이 유리하다. 내부 API 호출 지연이 줄어들고, 서버에서 화면을 조립하는 시간도 짧아진다.
반대로 브라우저가 백엔드 API를 직접 호출하는 구조라면 기준이 달라진다.
이 경우에는 프론트 서버와 백엔드 서버의 거리보다, 사용자와 백엔드 서버의 거리가 더 중요하다. 예를 들어 사용자 대부분이 미국에 있다면, 백엔드는 미국 또는 가까운 아메리카 리전에 두는 편이 응답 속도에 유리하다.
하지만 여기서도 한 가지를 더 봐야 한다. 백엔드 서버는 DB와 한 번만 통신하는 경우가 드물다는 점이다.
백엔드 서버는 요청을 처리하면서 DB를 여러 번 호출하는 경우가 많다. 세션을 확인하고, 사용자 정보를 읽고, 데이터를 조회하고, 권한을 검증하는 식으로 하나의 요청 안에서 여러 번 왕복이 발생한다.
예를 들어 게시글 상세 페이지를 조회한다고 하면 다음과 같은 작업이 필요할 수 있다.
- 게시글 조회
- 작성자 정보 조회
- 댓글 조회
- 좋아요 여부 조회
- 조회수 업데이트
이처럼 하나의 요청 안에서도 서버와 DB 사이에는 여러 개의 쿼리와 응답이 오간다. 반면 사용자와 프론트 서버 사이의 통신은 CDN, 브라우저 캐시, 서버 렌더링 등의 방식으로 어느 정도 줄일 수 있다. 하지만 백엔드 서버는 요청을 처리할 때마다 DB와 통신해야 하는 경우가 많다.
그래서 전체 응답 시간을 줄이려면, 통신이 더 자주 발생****하는 백엔드 서버와 DB 사이의 거리를 줄이는 것이 더 직접적인 효과를 낼 때가 많다.
백엔드 서버와 DB가 멀리 떨어져 있으면 쿼리 지연도 누적된다. 예를 들어 두 서버 사이의 왕복 시간이 50ms이고, 하나의 요청 처리 중 DB 쿼리를 순차적으로 10번 실행한다고 가정해 보자.
50ms * 10회 = 약 500ms
여기에 실제 쿼리 실행 시간, 데이터 전송 시간, 애플리케이션 로직 처리 시간까지 더해진다. 즉, 쿼리 자체가 빠르더라도 네트워크 왕복 비용만으로 전체 응답이 느려질 수 있다.
연결 비용도 있다. DB와 통신할 때는 단순히 쿼리만 보내는 것이 아니라 상황에 따라 다음 과정이 필요할 수 있다.
- TCP 연결 수립
- TLS 보안 연결 수립
- DB 인증
- 세션 및 연결 설정
실제 운영 환경에서는 커넥션 풀을 사용해 이 비용을 줄이지만, 그렇다고 물리적 거리가 사라지는 것은 아니다. 커넥션 풀을 사용해도 다음 문제는 여전히 남는다.
- 서버와 DB 사이의 네트워크 왕복 시간
- 커넥션 풀 고갈
- 장거리 연결에서 발생하는 패킷 손실과 재전송
즉, 커넥션 풀은 연결 생성 비용을 줄여줄 뿐이고, 장거리 통신 자체의 비용까지 없애주지는 못한다.
이런 이유로 대부분의 웹 서비스는 다음 원칙에서 출발하는 것이 현실적이다.
백엔드 API 서버와 주 DB는 같은 리전에 둔다. 프론트 정적 자산은 CDN을 통해 사용자 가까이 제공한다.
이 방식은 백엔드와 DB 사이의 잦은 통신을 빠르게 유지하면서도, 이미지·JS·CSS 같은 프론트 자산은 전 세계 사용자에게 비교적 빠르게 전달할 수 있게 해 준다.
구조에 따라 우선순위를 다시 정리하면 다음과 같다.
- 프론트 서버가 백엔드를 호출하는 SSR·BFF 구조라면, 프론트 서버와 백엔드도 가깝게 둔다.
- 브라우저가 백엔드를 직접 호출하는 구조라면, 백엔드는 주요 사용자와 가까운 곳에 둔다.
- 다만 특별한 요구가 없다면, 여전히 백엔드와 DB를 먼저 같은 리전에 두는 것이 기본값이다.
- 사용자가 여러 지역에 분포하면 CDN, 엣지, 멀티 리전, 읽기 복제본 같은 확장 전략을 검토한다.
혼합 구조라면 어떻게 해야 할까? 예를 들어 SSR도 활용하고 브라우저에서 백엔드를 직접 호출하는 방식도 함께 사용한다면, 처음부터 모든 구간을 동시에 최적화하려고 하기보다 기본 축을 먼저 정하는 편이 낫다.
이 경우에는 프론트 서버, 백엔드 서버, DB를 같은 주요 리전에 두고, 정적 자산만 CDN으로 전 세계에 제공하는 방식이 가장 무난한 출발점이다. 이후 브라우저 직접 호출 지연이 실제로 문제 될 만큼 커지면, 그때 백엔드와 DB를 지역별로 확장하는 전략을 고려할 수 있다.
즉, "글로벌 서비스이니 프론트 서버를 무조건 사용자 가까이에 둬야 한다"라고 단순화해서 생각하면 안 된다. SSR 비중이 크다면 프론트와 백엔드의 거리도 중요하고, 데이터 접근이 많다면 백엔드와 DB의 거리도 더 중요해질 수 있다.
배치 전략을 판단할 때는 막연한 인상보다 실제 요청 흐름과 측정값을 기준으로 봐야 한다.
요청 구간별 지연 시간
- 사용자 ↔ 프론트 서버의 왕복 시간
- 프론트 서버 ↔ 애플리케이션 서버의 왕복 시간
- 애플리케이션 서버 ↔ DB의 왕복 시간
- 외부 API나 메시지 브로커 등 다른 시스템과의 통신 시간
- 각 구간의 지연 시간이 전체 응답 시간에서 차지하는 비중
DB 통신 비용
- 요청 한 건당 DB 쿼리 실행 횟수
- 쿼리가 순차적으로 실행되는지 여부
- 쿼리 실행 시간과 네트워크 왕복 시간의 구분
- DB 연결 생성 시간
- 커넥션 풀 대기 시간과 연결 재사용률
- 트랜잭션 처리에 걸리는 시간
사용자에게 전달되는 실제 성능
- 전체 요청의 응답 시간
- 평균값뿐 아니라 p50, p95, p99 응답 시간
- 첫 응답까지 걸리는 시간(TTFB)
- 콘텐츠 전송에 걸리는 시간
- 타임아웃, 재시도, 연결 실패 발생률
- 지역별 응답 시간 차이
비교 조건
- 동일한 요청과 동일한 데이터로 측정했는가?
- 동일한 트래픽과 부하 조건에서 비교했는가?
- 캐시 적중과 캐시 미적중 상황을 구분했는가?
- 서버와 DB 간 네트워크 경로가 실제 운영 환경과 같은가?
- 단일 측정값이 아니라 일정 시간 동안 반복 측정했는가?
결론: 서버 위치를 결정하는 기준은…
서버 위치는 프론트와 DB 중 하나만 보고 정하는 문제가 아니다. 또한 사용자 위치에 무조건 가깝게 두는 것도 항상 정답은 아니다. 중요한 것은 요청이 실제로 어떤 경로로 흐르는지, 그리고 백엔드가 DB와 얼마나 자주 통신하는지 함께 보는 것이다.
대부분의 경우에는 다음 원칙으로 시작하는 것이 현실적이다.
- 백엔드 서버와 주 DB를 같은 리전에 둔다.
- 사용자는 CDN과 캐시로 가깝게 연결한다.
- SSR 구조라면 프론트 서버와 백엔드도 가깝게 둔다.
- 최종 결정은 실제 측정값과 트래픽 패턴을 기준으로 내린다.