운영한던 서비스의 아키텍처를 횡설수설 설명하고 나면 위 질문이 올 때가 있었다. 만약 비용이 문제가 없고 서버를 마음대로 구성해봐라! 했으면 나는 어떻게 했었을까? 사실 진지하게 생각해본적은 없었다. 그래서 이제 생각해보려고 한다.
들어가기 전에 내가 그냥 혼자 생각했던 구조는 뭐... 대충
- 프론트 web 서버 1대
- API 서버 2대 이상?
- 로드밸런서 1대?
- DB 서버 2대(이중화 또는 백업용),
- 캐시, 메지징 큐 등 뭐 이것저것 서버 1대
- CI/CD 구축할 서버도 1대..?
이정도..? 라고 했는데... 그냥 내 뇌피셜이었다. 그러니 이제 그 근거를 찾아가보자.
정말 이거면 될까요?
1. 단일 서버인 경우
일단, 각 서버별 환경에서 이야기해보자.
내가 회사에서 사용하던 단일 서버 환경에서 여러 개 인스턴스를 띄워 무중단 배포나 부하 분산 효과를 얻을 수 있겠지만 물리 자원이 한계에 달하면 성능 향상에 한계가 있다. 대규모 트래픽과 안정성을 위해서는 여러 대의 서버로 스케일 아웃 하는 것이 필요하다.
| 데이터베이스 | 1 | 서비스 데이터 영속화, 트랜잭션 관리 |
| API 서버 | 2 이상 | REST API 및 비즈니스 로직 처리, 동시에 여러 요청 분산 |
| 웹 서버 | 1 | 정적 파일 서빙, 클라이언트 요청 라우팅 |
| 캐시 | 1 | 빈번한 데이터 캐싱, 응답 속도 개선 |
| 메시징 큐 | 1 | 비동기 작업 처리, 외부 서비스 연동, 이벤트 처리 |
단일 서버 환경이지만, 역할별로 각 컴포넌트를 독립적으로 운용할 수 있게 구성할 수 있다. 서버 내 여러 프로세스를 분리해 단일 서버라도 동시 요청 분산과 비동기 처리, 성능 최적화가 가능하고 컴포넌트 장애 시 영향 범위를 최소화한다.
- 역할 분리 명확: 각 서비스의 기능을 명확하게 분리하여 유지보수성과 확장성 확보
- 프로세스/포트 분리: API 서버를 2개 이상 인스턴스로 띄워 단일 서버 환경에서도 간단한 로드밸런싱 또는 무중단 배포 가능
- 캐시와 메시징 활용: 확장성이 필요한 부분은 별도 프로세스로 분리하여 성능을 최적화
- 요구사항 고려: 초기엔 비용-운영 효율성이 높으나, 장기적으로 트래픽 증가나 장애 대응 시 서버 분산(멀티 서버, 클라우드 오토스케일링 등)으로 확장이 쉽도록 각 컴포넌트 설계를 유연하게
초기에는 단일 서버 환경에서 각 역할별 인스턴스를 독립적으로 운용했습니다. 데이터베이스 1개, API 서버 1개, 웹 서버 1개를 동일 서버에서 관리하였고, 모든 컴포넌트는 독립적으로 관리/모니터링하도록 구성했습니다. 추후 성능 이슈나 장애 대응 필요성이 발생할 때, 이 구조를 기반으로 컴포넌트 별 서버 분리, 클라우드 확장 등으로 진화시킬 수 있습니다.
2. 다중 서버로 구성하는 경우
단일 서버 환경에서 초기 비용과 운영 효율성을 챙겼다면 이제 서비스가 커져 사용자가 늘고 트래픽이 증가했을 때는 어떻게 해야할까? 단일 서버 프로세스로 분리했던 컴포넌트들을 이제 각 서버로 분리해야할 것이다. 확장성, 안정성, 장애 대응, 성능 최적화 등에 맞춰 역할별 분리와 확장성 중심의 구조로 설계해보자.
- 역할별(계층별) 분리: 웹, API, DB, 캐시, 메시징 등을 별도 서버 또는 컨테이너로 분리하여 독립 운용
- 수평 확장 구조: 트래픽 및 요구사항 증가에 따라 인스턴스를 쉽게 추가할 수 있도록 설계
- 고가용성/장애 대응: 데이터베이스, 캐시, 메시징 등 주요 컴포넌트는 복제, 페일오버*, 클러스터링* 등으로 이중화
- 네트워크 및 보안: 로드밸런서, 방화벽, 프라이빗 서브넷*, VPN 등 인프라 보안 설계 포함
* 페일오버: 시스템, 네트워크, 또는 서비스에서 장애 발생 시 자동으로 예비 시스템으로 전환되는 기능
* 클러스터링: 데이터베이스를 여러 서버에 분산하여 처리 (특정 기준으로 여러 서버에 나누어 저장하는 것은 샤딩)
* 프라이빗 서브넷: 외부에서 접근이 불가한 네트워크 영역
| 로드밸런서 | 2 (이중화*/HA*) | 트래픽 분산, 장애 시 자동 페일오버 |
| Web 서버 | 2 이상 | 정적 파일 제공, 가벼운 라우팅, 가용성*/확장성 확보 |
| API 서버 | 2 이상 (트래픽 기반) | REST API, 비즈니스 로직, 무상태(state-less) |
| DB 서버 | 2 이상(Master/Slave, Cluster) | 트랜잭션/영속 데이터, 이중화 및 복제 필수 |
| 캐시 서버 | 2 (Master/Replica) | Redis 등, 빠른 데이터 조회, 장애 대응 |
| 메시징 큐 | 1~2(Cluster/Replica) | RabbitMQ/Kafka, 비동기/이벤트 처리 |
| 스토리지 | 별도 관리 | 객체/파일 저장, 클라우드 스토리지 등 |
| 모니터링/로그 | 별도 에이전트/서버 | 시스템/앱 상태 감시, 장애 예측, 추적성 확보 |
* HA; High Availability: 고가용성
* 이중화: 서비스의 가용성을 높이기 위해 서버를 다중화 하는 것
* 가용성: (하나에 문제가 생기면 다른 하나를 사용하여) 서비스가 정상 유지되는 정도
서비스 각 역할을 분리하고, 확장성과 고가용성을 고려해 아키텍처를 설계합니다.
L4/L7 로드밸런서 2대(이중화), API 서버 2대 이상, 웹 서버 2대, 데이터베이스는 Master/Slave 혹은 클러스터 형태로 2대 이상, 캐시는 Redis Master/Replica 구조, 메시징 큐는 이중화 구성, 스토리지와 로그/모니터링 서버는 별도 분리합니다.
각 구성요소는 무상태(State-less)로 관리하고, 서버/서비스 장애 시 자동으로 대체 노드가 역할을 수행해 서비스 다운타임을 최소화합니다. 트래픽 증가 시 API/Web 서버 인스턴스를 수평으로 확장할 수 있도록 설계합니다.
- 로드밸런서: 모든 트래픽의 입구, 상태 체크 및 자동 장애 조치
- 무상태 API/Web 서버: 서버 확장이 용이하며, 요청이 특정 서버에 국한되지 않음
- DB/캐시 이중화: 데이터 안정성, 장애 복구 보장(Master-Slave, ReplicaSet 등)
- 메시징 큐/비동기 처리: 트래픽 처리
- 자동화 배포/스케일링: CI/CD, 인프라 오토스케일링, IaC* 도입으로 운영 효율화
- 보안 및 모니터링: 네트워크 분리, 방화벽, 접근 통제, 실시간 장애 감시 등
* IaC; Infrastructure as Code: 수동 프로세스가 아닌 코드를 통해 인프라를 관리하고 프로비저닝*하는 것
* 프로비저닝: 사용자가 요청한 IT 자원을 사용할 수 있는 상태로 준비하는 것
역할별 분리와 다중화/이중화를 통해 성능, 확장성, 안정성 등을 확보할 수 있습니다.
3. 정리
하드웨어 + 컴포넌트 관점에서 서버 아키텍처에 대해 알아보았다. 일단 아키텍처에 대해 대답할 수 있는 건 이렇게 정리해본다.
클라이언트 - API 서버 - 캐시 - 외부 API 연동 - DB 이렇게 구성되어 있고, 단일 서버에서 클라이언트, API 서버(내장 캐시, 외부 API 연동), DB 이렇게 컴포넌트들이 각 프로세스로 동일 서버에서 관리되었습니다.
클라이언트는 HTTP 기반 REST API로 서버와 통신하고,서버는 API 요청을 처리하며, 성능 최적화를 위해 내장 캐시(예: Spring 내장 캐시)를 사용한 뒤 최종으로 DB에 접근합니다.
적은 비용과 운영 효율을 위한 선택이었고, 트래픽이 늘어나면 각 컴포넌트를 별도의 서버 또는 클라우드 인스턴스로 분리하고, 수평 확장 및 부하 분산 구조로 전환하여 대응할 수 있습니다.
다음엔 L4/L7 로드밸런서가 뭐고 둘은 뭐가 다른지에 대해서도 정리해야지.
'개발 > CS' 카테고리의 다른 글
| [아키텍처] 운영하던 서비스의 서버 아키텍처를 설명해주세요 (3) | 2025.07.20 |
|---|---|
| Binary Search VS Linear Search (0) | 2022.04.17 |
| Arrays (0) | 2022.04.17 |
| [cs50] 비트와 바이트 (0) | 2021.09.08 |
| [cs50] 1.2 - 기억장치 (0) | 2021.08.02 |