1. 들어가며
이번 조사에서는 서비스를 처음부터 직접 설계한다고 가정하고, 단일 서버 환경에서 시작해 단계별로 발생하는 문제와 해결 과정을 하나씩 따라가 보았다. 그동안 컴플라이언스 관점에서 “가용성을 확보해야 한다”, “단일 장애점을 제거해야 한다”와 같은 통제 항목들을 체크리스트 형태로만 접해왔다. 그러다 보니 실제 네트워크 구조 내에서 서버가 어떻게 작동하는지에 대한 실증적인 이해가 부족했음을 느꼈다. 이에 따라 본 조사에서는 인프라의 단계별 확장 과정을 파악하고, AWS의 어떤 인스턴스와 서비스들이 각 역할을 수행하는지 구체적으로 알아보고자 하였다.
2. 하나의 서버에서 시작
먼저 제일 단순한 구조부터 시작한다. 서버 한 대에 웹 서버, 애플리케이션, DB를 전부 설치하는 것이다. 모든 서비스를 처음 만들 때는 이게 제일 빠르고 간단한 방법이다.

만약 사용자가 10명에서 10000명으로 늘어난다고 생각해보자. 예전과 달리 서버가 느려졌는데, 웹 처리가 느린 건지, 애플리케이션 로직이 느린 건지, DB 조회가 느린 건지 전혀 구분이 안 된다. 심지어 하나를 고치려고 서버를 재시작하면 나머지 기능까지 같이 멈춰버렸다.
원인을 따져보니 당연한 결과일 것이다. 웹 서버는 HTTP 요청 처리나 정적 파일 응답을 하면서 주로 네트워크 I/O를 쓰고, 애플리케이션은 비즈니스 로직 연산 때문에 CPU를 많이 쓰고, DB는 데이터 조회·저장을 하느라 디스크 I/O와 메모리를 주로 쓴다. 성격이 완전히 다른 세 가지 작업이 한 서버의 자원을 공유하고 있으니, 원인 분리도 안 되고 장애도 전파되고 개별 확장도 불가능한 게 당연했다.
그래서 역할이 다른 작업을 물리적으로 분리하기로 했다.
Web은 Presentation Tier, Application은 Application Tier, DB는 Data Tier로 나누는 것이다.

여기서 궁금했던 게 하나 있었다. "굳이 서버를 나누지 않고, 단일 서버 내에서 프로세스만 분리해도 되지 않을까?" 싶었는데, 찾아보니 두 가지 분리 방식이 있었다.
- 논리적 분리: 같은 서버 안에서 별도 프로세스를 띄우는 것
- 물리적 분리: 서버 자체를 나누는 것
논리적 분리만으로는 프로세스는 나뉘어도 CPU·메모리·디스크 같은 물리 자원은 여전히 공유하고, 서버 자체가 죽으면 다 같이 죽는다는 한계가 있었다. 그래서 실제로 정상적인 서비스를 위해서는 서버 세 대로 나누는 물리적 분리인 3-Tier 아키텍처 구성이 필수적이게 되는 것이다.
3. Vertical Scaling & Horizontal Scaling
웹서버와 DB는 여전히 여유가 있는데, 사용자의 접속량이 늘어나면서 과도한 CPU 연산량으로 인해 Application 서버만 CPU 100%를 찍게 되었다. 처음에는 더 좋은 서버로 교체했는데, 잠깐 버티다가 또 한계가 왔고, 교체할 때마다 서비스를 내려야 하는 문제가 생겼다.
이게 Vertical Scaling의 한계이다. 기존 서버에 프로세서, 메모리, 디스크 같은 하드웨어 리소스를 추가하는 방식이라 설정이 단순하고 데이터 일관성을 유지하기 쉽다는 장점이 있지만, 결국 하드웨어 자체의 물리적 상한이 있고, 교체하려면 다운타임이 필요하다는 게 한계점이다.
반면에 Horizontal Scaling은 서버 사양을 올리는 대신 같은 사양의 서버를 여러 대 두고, 로드밸런서가 요청을 나눠주는 방식이다. 이 방식은 거의 한계 없는 확장성을 가질 수 있고, 높은 가용성과 단일 장애점 제거가 가능하다는 게 큰 장점이다. 다만 아키텍처 구조가 복잡해지고 네트워크 통신 비용이 늘어난다는 점의 한계가 있다.

4. 서버를 늘렸지만 부하 분산이 일어나지 않는다면?
Application 서버를 두 대로 늘렸지만, 이상하게도 트래픽은 여전히 첫 번째 서버로만 쏠리고 두 번째 서버는 아무런 요청을 받지 못하는 현상이 발생했다.
이유는 단순했다. 서버의 수량을 늘리는 것과 그 서버들에 요청을 분산하는 것은 별개의 문제이기 때문이다. Web 서버의 설정에 특정 App 서버의 IP 주소가 하드코딩되어 있으면, 서버를 아무리 증설해도 모든 트래픽은 기존 주소로만 흘러가게 된다.
이 문제를 해결하기 위해서는 서버 앞단에 로드밸런서(Load Balancer)를 배치하면 된다. 로드밸런서가 중계 역할을 하면서, Web 서버는 이전과 달리 로드밸런서의 단일 대표 주소만 가지고 있으면 된다. 이후 들어오는 모든 요청은 로드밸런서가 판단하여 하위 서버들로 알아서 균등 분산한다.
대표적인 분배 방식은 다음과 같다.
- Round Robin: 모든 정상 서버에 순차적으로 요청을 균등 배분
- Least Connection: 현재 연결 세션 수가 가장 적은 서버로 배정
- IP Hash: 사용자의 IP 기준으로 항상 같은 서버로 고정 배정
이렇게 로드밸런서를 두면서, 여러 서버를 마치 한 대인 것처럼 사용자에게 보여줄 수 있다.
#셋 중에 가장 효율적인 분배 방식이 무엇일까??
Least connection: 일반적인 웹, 앱 서비스는 보통 least connection이 유리하다. 실제 서버가 과부하가 걸렸는지 등 현재 부하 상태를 실시간으로 반영하기 때문에 대다수의 앱에서 가장 균등하고 효율적으로 쓰일 수 있다. Least connection은 로드밸런서의 옵션에서 설정할 수 있다.
예를 들어 AWS의 ALB는 기본적으로 Round Robin으로 동작하고, 설정 메뉴에서 Least Outstanding Requests 알고리즘으로 전환할 수 있다. 이름이 Least Connection과 달라서 처음엔 헷갈렸는데, 찾아보니 완전히 같은 개념은 아니었다. 전통적인 Least Connection은 서버에 열려 있는 연결 수를 기준으로 판단하는 반면, ALB의 Least Outstanding Requests는 서버가 아직 응답하지 않은 요청 수를 기준으로 판단한다. AWS가 Least Connection이라는 일반 개념을 HTTP 요청 단위에 맞게 더 정교하게 구현한 버전인 셈이다.
5. Stateful의 한계와 Stateless 구조로의 전환
로드밸런서를 도입하자 상태값 불일치(State Inconsistency) 문제가 발생했다. 요청이 App서버 1에서 App서버2로 전달될 때, App서버2가 이전 처리 상태를 인식하지 못하는 현상이다.
원인은 App서버1이 상태 정보를 자체 메모리에 보관하는 Stateful 방식이었기 때문이다. 서버마다 보유한 데이터가 달라 시스템의 일관성이 깨지게 된 것이다.
이를 해결하기 위해 서버를 Stateless 구조로 전환했다. 상태 정보를 서버 내부가 아닌 외부 중앙 저장소(Session Store)에서 관리하게 되면, 어떤 서버로 요청이 가도 동일한 상태를 참조할 수 있다.

6. Load Balancer의 Health Check
특정 App 서버 하나가 다운되었을 때의 대처가 새로운 문제로 떠올랐다. 로드밸런서가 서버의 장애 사실을 알지 못한 채 다운된 서버로 계속 요청을 보내면서, 사용자 일부가 지속적으로 응답 오류를 경험하게 되었다. 원인은 로드밸런서가 단순히 '트래픽을 분산하는 역할'만 수행하고, '서버의 정상 작동 여부를 감시하는 역할'은 수행하지 않았기 때문이다.
이를 해결하기 위해 로드밸런서에 Health Check를 설정했다. 로드밸런서가 주기적으로 각 App 서버에 헬스 체크 요청을 보낸 뒤, 정상 응답을 보낸 서버로만 트래픽을 분배하고 응답이 없거나 에러를 반환하는 비정상 서버는 분배 대상에서 제외하는 방식이다. Health Check를 통해 서버 장애 발생 시에도 사용자 영향 없이 시스템이 자동 복구 및 우회될 수 있도록 고가용성을 확보했다.

7. Failure Domain Problem
App 서버는 이중화했지만, DB를 그냥 App서버 1과 같은 서버에 뒀다. App서버 1을 재시작했더니 DB도 같이 내려갔고, DB에 의존하던 App서버 2까지 같이 멈추게 되었다.
이렇게 하나의 장애가 미치는 영향 범위를 Failure Domain(장애 도메인)이라고 부른다. DB처럼 모든 App 서버가 공통으로 의존하는 핵심 자원은 물리적으로 분리된 별도의 영역에 위치시켜, 단일 장애점(SPOF)이 전체 시스템으로 번지는 것을 막아야 한다.
추가적으로 ISMS-P 2.9.2(성능 및 장애관리) 항목은 정보시스템의 가용성을 보장하기 위해 장애 탐지 및 대응 절차를 수립할 것을 요구한다. 하지만 단순한 문서상의 사후 대응 절차를 넘어, Failure Domain을 미리 분리해 두는 아키텍처 설계 그 자체가 장애 영향 범위를 근본적으로 최소화하는 가장 실질적인 가용성 확보 방안이 될 수 있겠다는 생각을 하게 되었다.

8. 정리된 구조를 AWS 서비스로 매핑해보기
VPC (가상 네트워크): Web, App, DB가 속한 논리적으로 격리된 네트워크 공간. 서버들이 물리적으로 다른 곳에 있어도, 서로 통신하려면 논리적으로 하나의 네트워크 안에 있어야 한다.
ALB(로드밸런서): 트래픽을 여러 EC2 인스턴스로 분산하고 Health Check를 수행한다.
EC2(Web tier / App tier): Web tier는 사용자의 HTTP 요청을 받는 Presentation 계층, App tier는 비즈니스 로직을 수행하는 Application 계층이다.
Session Store: 로그인 상태 같은 세션 정보를 App 서버 외부에 저장하는 공유 저장소. 해당 기능이 없으면 여러 App서버 간 상태 불일치로 사용자 경험이 깨진다.
RDS(관계형 DB): 서비스의 핵심 데이터를 저장하는 Data 계층. Multi-AZ로 Primary/Standby를 이중화할 수 있다.
Route 53(DNS): 사용자가 입력한 도메인 이름을 실제 ALB 주소로 연결해주는 역할. 인프라 구조가 바뀌어도 사용자에게는 같은 도메인으로 접근이 유지돼야 한다.
이렇게 실제 클라우드 서비스 단위로 매핑해 보며 중요한 인사이트를 얻을 수 있었다. 바로 AWS가 관리해 주는 영역과 설계자가 직접 책임져야 하는 영역이 명확히 나뉜다는 점이다. 이게 정확히 어떤 개념과 연결되는지 좀 더 찾아봤다.
9. 컴플라이언스 관점에서 더 파본 것
추가적으로 공동 책임 모델에 대해 조사하기 위해 AWS 공식 Shared Responsibility Model를 살펴보았다.

AWS는 이 모델을 두 축으로 나눈다. 클라우드 자체의 보안(Security of the Cloud)은 AWS Region, 가용 영역, 데이터센터 같은 물리적 인프라부터 하드웨어, 네트워킹, 가상화 계층까지를 포함한다. 예를 들어 AZ 간 물리적 네트워크 이중화나 Route 53 같은 관리형 서비스의 고가용성이 여기 속한다. 반대로 클라우드 내부의 보안(Security in the Cloud)은 고객이 어떤 서비스를 선택했느냐에 따라 범위가 달라진다는 점이 흥미로웠다.
찾아보니 AWS는 서비스 종류에 따라 고객 책임 범위를 다르게 정의한다. EC2 같은 IaaS는 게스트 OS, 방화벽 설정, 애플리케이션 구성뿐 아니라 VPC 라우팅 테이블, 서브넷 구성, 보안 그룹 같은 네트워크 설계까지 고객이 직접 관리해야 한다. 반면 RDS나 ElastiCache 같은 관리형 서비스는 AWS가 OS와 플랫폼까지 대신 관리해준다. 다만 관리형 서비스라고 해서 고객 책임이 사라지는 것은 아니다. 예를 들어 RDS의 Multi-AZ는 기본값이 아니라 고객이 명시적으로 활성화해야 하는 옵션이며, 일단 활성화된 이후의 failover 메커니즘과 물리적 이중화 동작만이 AWS의 책임 영역이다. 즉 선택사항을 설정하고 켤 책임은 여전히 고객에게 남아있다.
이 구분을 이번 조사 내용에 대입해보니 정확히 맞아떨어졌다. Web/App 서버와 같은 EC2들을 Stateless하게 설계하고, Failure Domain을 분리하고, Health Check를 설정하는 작업은 전부 사용자인 본인이 선택한 서비스이고 본인이 직접 책임져야 하는 영역인 것이다. 반면 RDS의 Multi-AZ failover 메커니즘 자체나 ALB의 물리적 이중화는 AWS가 관리형 서비스로서 대신 짊어져주는 영역이었다. 다만 이런 기능들을 애초에 켜고 올바르게 설정하는 것은 여전히 본인의 책임이라는 점도 함께 짚어야 한다.
컴플라이언스 관점에서 이 구분이 왜 중요한지도 더 명확해졌다. 감사나 통제 점검에서 "이 시스템의 가용성은 누가 보장하는가"라는 질문의 답은, 그 시스템이 IaaS인지 관리형 서비스인지, 그리고 관리형 서비스라면 어떤 옵션이 활성화되어 있는지에 따라 완전히 달라진다. 결국 인프라 구조를 이해하지 못하면 우리가 통제해야 할 범위가 어디까지인지를 정확히 그릴 수가 없다는 사실을 이번 조사를 통해 체감했다.

