🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

AWS 고가용성과 내결함성 아키텍처 설계 기초 - 슬라이드 1/7
A

AI Generated

2025. 12. 23. · 3 Views

AWS 고가용성과 내결함성 아키텍처 설계 기초

서비스가 멈추지 않는 시스템을 만들고 싶으신가요? AWS의 글로벌 인프라를 활용한 고가용성과 내결함성 아키텍처 설계 원칙을 실무 중심으로 배워봅시다. 초급 개발자도 쉽게 이해할 수 있도록 스토리와 비유로 풀어냈습니다.


목차

  1. AWS 글로벌 인프라 구조 이해
  2. 리전과 가용 영역 개념
  3. 고가용성 설계 원칙
  4. 내결함성이란
  5. 멀티 AZ 배포 전략
  6. 단일 장애 지점 제거하기

1. AWS 글로벌 인프라 구조 이해

스타트업에 입사한 지 한 달 된 이개발 씨는 오늘 처음으로 서비스 배포를 맡게 되었습니다. CTO님께서 "AWS 서울 리전에 배포해주세요"라고 말씀하셨는데, 리전이 뭔지 잘 모르겠습니다.

검색해보니 AWS에는 전 세계에 수십 개의 리전이 있다는데, 왜 이렇게 복잡하게 나눠놓은 걸까요?

AWS 글로벌 인프라는 전 세계에 분산된 데이터센터 네트워크입니다. 마치 글로벌 택배 회사가 전국 각지에 물류센터를 두는 것처럼, AWS도 전 세계 주요 지역에 데이터센터를 운영합니다.

이를 통해 사용자와 가까운 곳에서 빠르게 서비스를 제공하고, 장애가 발생해도 다른 곳에서 서비스를 계속할 수 있습니다.

다음 코드를 살펴봅시다.

# AWS 리전 목록 조회하기
import boto3

# AWS EC2 클라이언트 생성
ec2_client = boto3.client('ec2', region_name='ap-northeast-2')

# 사용 가능한 모든 리전 조회
regions = ec2_client.describe_regions()

# 리전 정보 출력
for region in regions['Regions']:
    print(f"리전 이름: {region['RegionName']}")
    print(f"엔드포인트: {region['Endpoint']}")
    print("---")

이개발 씨는 선배 개발자인 박클라우드 씨에게 물어봤습니다. "선배님, 리전이 정확히 뭔가요?" 박클라우드 씨가 커피를 한 모금 마시고는 친절하게 설명을 시작했습니다.

"좋은 질문이에요. AWS를 제대로 이해하려면 글로벌 인프라 구조를 먼저 알아야 합니다." AWS 글로벌 인프라의 핵심 개념 AWS의 글로벌 인프라는 크게 세 가지 계층으로 이루어져 있습니다.

첫 번째는 리전(Region), 두 번째는 가용 영역(Availability Zone, AZ), 세 번째는 **엣지 로케이션(Edge Location)**입니다. 쉽게 비유하자면, 글로벌 프랜차이즈 커피 체인을 생각해보세요.

리전은 각 나라의 본부와 같습니다. 서울 리전, 도쿄 리전, 싱가포르 리전처럼 지리적으로 완전히 분리된 독립적인 거점이죠.

각 리전 안에는 여러 개의 가용 영역이 있는데, 이는 마치 한 도시 안의 여러 지점과 같습니다. 엣지 로케이션은 고객과 가장 가까운 곳에서 콘텐츠를 전달하는 소형 배송 거점 같은 역할을 합니다.

왜 이렇게 복잡하게 나눠놓았을까요? 이개발 씨가 고개를 갸우뚱합니다. "그냥 하나의 큰 데이터센터로 운영하면 안 되나요?" 박클라우드 씨가 웃으며 대답합니다.

"예전에 그런 방식으로 운영하던 회사들이 있었어요. 하지만 심각한 문제들이 있었죠." 첫 번째 문제는 **지연 시간(Latency)**입니다.

만약 한국 사용자가 미국에 있는 단일 데이터센터에 접속한다면 어떻게 될까요? 물리적인 거리 때문에 응답 시간이 수백 밀리초 이상 걸립니다.

웹페이지를 클릭할 때마다 0.5초씩 기다려야 한다면 사용자 경험이 매우 나빠지겠죠. 두 번째 문제는 데이터 주권과 규제입니다.

많은 나라에서 자국민의 개인정보는 반드시 자국 내에 저장하도록 법으로 정하고 있습니다. 한국의 개인정보보호법, 유럽의 GDPR이 대표적인 예입니다.

세 번째 문제는 재해 복구입니다. 하나의 데이터센터에만 의존한다면, 그곳에 자연재해나 대규모 장애가 발생하면 전 세계 서비스가 모두 멈춥니다.

리전의 특징 현재 AWS는 전 세계에 30개 이상의 리전을 운영하고 있습니다. 각 리전은 완전히 독립적으로 운영됩니다.

서울 리전(ap-northeast-2)에서 장애가 발생해도 도쿄 리전(ap-northeast-1)은 아무런 영향을 받지 않습니다. 마치 서울 지사에 정전이 발생해도 도쿄 지사는 정상 운영되는 것과 같은 이치입니다.

리전을 선택하는 기준 그렇다면 어떤 리전을 선택해야 할까요? 첫째, 사용자와의 거리를 고려합니다.

한국 사용자가 주 고객이라면 서울 리전을 선택하는 것이 당연합니다. 지연 시간을 최소화할 수 있으니까요.

둘째, 비용을 고려합니다. 같은 EC2 인스턴스라도 리전마다 가격이 다릅니다.

서울 리전이 버지니아 리전보다 약간 비싼 편입니다. 셋째, 서비스 가용성을 확인합니다.

최신 AWS 서비스는 대부분 버지니아 리전에서 먼저 출시되고, 나중에 다른 리전으로 확대됩니다. 넷째, 규제 요구사항을 충족해야 합니다.

금융 서비스처럼 규제가 엄격한 산업에서는 반드시 특정 리전을 사용해야 할 수 있습니다. 코드로 살펴보기 위의 코드를 자세히 살펴보겠습니다.

먼저 boto3는 AWS의 공식 Python SDK입니다. 이를 사용하면 Python 코드로 AWS 서비스를 제어할 수 있습니다.

ec2_client를 생성할 때 region_name='ap-northeast-2'를 지정했습니다. 이는 서울 리전을 의미합니다.

describe_regions() 메서드는 현재 사용 가능한 모든 리전 정보를 가져옵니다. 반환되는 데이터에는 각 리전의 이름과 API 엔드포인트 주소가 포함됩니다.

실무에서의 활용 실제 글로벌 서비스를 운영하는 회사들은 어떻게 할까요? 예를 들어 한국, 일본, 미국에 고객이 있는 서비스라면 세 개의 리전에 동일한 애플리케이션을 배포합니다.

그리고 Route 53(AWS의 DNS 서비스)의 지리적 라우팅 기능을 사용해, 한국 사용자는 자동으로 서울 리전으로, 일본 사용자는 도쿄 리전으로 연결되도록 설정합니다. 넷플릭스, 에어비앤비 같은 글로벌 서비스들이 이런 방식으로 운영됩니다.

전 세계 어디서 접속하든 빠른 응답 속도를 경험할 수 있는 이유입니다. 주의사항 초보 개발자들이 흔히 하는 실수가 있습니다.

서울 리전에서 생성한 EC2 인스턴스를 도쿄 리전에서 바로 사용하려고 하는 것입니다. 리전 간에는 리소스가 공유되지 않습니다.

서울 리전의 EC2 인스턴스는 서울 리전에서만 존재합니다. 다른 리전으로 옮기려면 AMI(Amazon Machine Image)를 복사하는 과정이 필요합니다.

마무리 박클라우드 씨의 설명을 들은 이개발 씨는 고개를 끄덕였습니다. "아, 그래서 처음 AWS 계정을 만들 때 리전을 선택하라고 하는 거였군요!" AWS 글로벌 인프라를 이해하는 것은 클라우드 아키텍처의 첫걸음입니다.

리전의 개념을 제대로 이해하면, 나중에 배울 고가용성 설계가 훨씬 쉬워집니다.

실전 팁

💡 - AWS 콘솔 우측 상단에서 언제든지 리전을 변경할 수 있습니다. 실수로 다른 리전에서 작업하지 않도록 항상 확인하세요.

  • 비용 최적화를 위해 개발/테스트 환경은 저렴한 리전을, 운영 환경은 사용자와 가까운 리전을 사용하는 전략도 있습니다.

2. 리전과 가용 영역 개념

이개발 씨는 서울 리전에 첫 번째 EC2 인스턴스를 성공적으로 배포했습니다. 그런데 CTO님이 코드 리뷰에서 이렇게 말씀하셨습니다.

"좋아요, 하지만 단일 AZ에만 배포하면 위험해요. 최소 2개 이상의 AZ에 배포해야 합니다." AZ가 뭔지, 왜 여러 개가 필요한지 궁금해졌습니다.

**가용 영역(Availability Zone, AZ)**은 하나의 리전 내에서 물리적으로 분리된 독립적인 데이터센터 그룹입니다. 마치 한 도시 안의 여러 소방서처럼, 하나가 문제가 생겨도 다른 곳에서 서비스를 계속할 수 있도록 설계되었습니다.

서울 리전에는 4개의 AZ가 있으며, 각각은 수 킬로미터 이상 떨어져 있지만 고속 네트워크로 연결되어 있습니다.

다음 코드를 살펴봅시다.

# 서울 리전의 가용 영역 조회하기
import boto3

ec2_client = boto3.client('ec2', region_name='ap-northeast-2')

# 가용 영역 정보 조회
azs = ec2_client.describe_availability_zones()

# 각 AZ 정보 출력
for az in azs['AvailabilityZones']:
    print(f"AZ 이름: {az['ZoneName']}")
    print(f"AZ ID: {az['ZoneId']}")
    print(f"상태: {az['State']}")
    print(f"리전: {az['RegionName']}")
    print("---")

# 결과: ap-northeast-2a, 2b, 2c, 2d

이개발 씨는 다시 박클라우드 씨를 찾아갔습니다. "선배님, AZ가 정확히 뭔가요?

그리고 왜 여러 개에 배포해야 하나요?" 박클라우드 씨가 화이트보드를 꺼내며 설명을 시작했습니다. 가용 영역의 물리적 구조 하나의 리전은 여러 개의 가용 영역으로 구성됩니다.

서울 리전(ap-northeast-2)의 경우 4개의 AZ가 있습니다. ap-northeast-2a, 2b, 2c, 2d로 표시되죠.

각 AZ는 실제로는 하나 이상의 데이터센터로 이루어져 있습니다. 중요한 점은, 각 AZ가 물리적으로 수 킬로미터 이상 떨어져 있다는 것입니다.

같은 건물에 있지 않습니다. 왜 이렇게 멀리 떨어뜨려 놓았을까요?

화재, 홍수, 정전 같은 물리적 재해가 발생해도 한 AZ만 영향을 받고 다른 AZ는 안전하도록 하기 위해서입니다. AZ 간의 네트워크 연결 "그런데 선배님, 그렇게 멀리 떨어져 있으면 통신이 느리지 않나요?" 좋은 질문입니다.

AWS는 AZ 간에 전용 고속 광케이블로 연결해놓았습니다. 덕분에 AZ 간 네트워크 지연 시간은 1밀리초 미만입니다.

사실상 같은 데이터센터에 있는 것처럼 빠르게 통신할 수 있습니다. 이는 마치 서울과 수원 사이에 초고속 전용 도로를 만들어놓은 것과 같습니다.

물리적으로는 떨어져 있지만, 이동 시간은 매우 짧습니다. 왜 여러 AZ를 사용해야 할까? 단일 AZ에만 애플리케이션을 배포하면 어떻게 될까요?

2021년 11월, AWS 버지니아 리전의 한 AZ에서 대규모 장애가 발생했습니다. 전력 공급 문제였죠.

이 AZ에만 의존하던 많은 서비스들이 몇 시간 동안 중단되었습니다. 하지만 멀티 AZ로 구성된 서비스들은 자동으로 다른 AZ로 트래픽을 전환해서 정상 운영을 계속했습니다.

실제 운영 환경에서는 최소 2개 이상의 AZ를 사용하는 것이 표준입니다. 더 높은 가용성이 필요하다면 3개 이상을 사용합니다.

AZ의 독립성 각 AZ는 완전히 독립적인 전력, 냉각, 네트워크 인프라를 갖추고 있습니다. ap-northeast-2a에서 정전이 발생해도, ap-northeast-2b는 자체 전력 공급 시스템을 가지고 있어서 영향을 받지 않습니다.

마치 아파트 동마다 별도의 전기 배전반을 쓰는 것과 같은 원리입니다. 코드 분석하기 위의 Python 코드를 살펴보겠습니다.

describe_availability_zones() 메서드는 현재 리전의 모든 AZ 정보를 가져옵니다. 반환되는 데이터에는 AZ 이름, 고유 ID, 현재 상태(available/unavailable), 속한 리전 이름이 포함됩니다.

중요한 점은 AZ 이름이 계정마다 다르게 매핑된다는 것입니다. 제 계정의 ap-northeast-2a가 물리적으로는 당신 계정의 ap-northeast-2b와 같은 데이터센터일 수 있습니다.

AWS가 특정 AZ로 트래픽이 몰리는 것을 방지하기 위해 이렇게 설계했습니다. 정확한 물리적 위치를 알고 싶다면 ZoneId를 사용해야 합니다.

이것은 모든 계정에서 동일합니다. 실무 활용 사례 전형적인 웹 애플리케이션을 멀티 AZ로 구성한다면 어떻게 할까요?

**Application Load Balancer(ALB)**를 생성하고, 최소 2개의 AZ에서 활성화합니다. 그리고 각 AZ에 EC2 인스턴스를 배포합니다.

ALB는 자동으로 두 AZ의 인스턴스에 트래픽을 분산합니다. 만약 ap-northeast-2a의 인스턴스가 다운되면?

ALB가 즉시 감지하고 ap-northeast-2c의 인스턴스로만 트래픽을 보냅니다. 사용자는 전혀 눈치채지 못합니다.

데이터베이스는 어떻게 할까요? RDS Multi-AZ 옵션을 활성화하면, 주 데이터베이스는 한 AZ에, 대기 복제본은 다른 AZ에 자동으로 배치됩니다.

주 데이터베이스에 장애가 발생하면 1~2분 내에 자동으로 대기 복제본으로 전환됩니다. 비용 고려사항 "선배님, 그럼 여러 AZ를 쓰면 비용이 배로 드나요?" 인스턴스 비용은 당연히 늘어납니다.

2개 AZ에 각각 인스턴스를 띄우면 인스턴스 2개 값을 내야죠. 하지만 AZ 간 데이터 전송 비용은 무료입니다.

같은 리전 내의 AZ 간 통신에는 요금이 부과되지 않습니다. 장애로 인한 매출 손실을 생각하면, 멀티 AZ 비용은 충분히 정당화됩니다.

1시간 서비스 중단이 수천만 원의 손실을 가져올 수 있다면, 인스턴스 비용 2배는 오히려 저렴한 보험입니다. 주의사항 초보자들이 자주 하는 실수가 있습니다.

"멀티 AZ로 설정했으니 장애에 완벽하게 대비했다"고 생각하는 것입니다. 멀티 AZ는 인프라 장애에 대비하는 것입니다.

애플리케이션 버그, 잘못된 배포, 보안 침해 같은 문제는 멀티 AZ로 해결되지 않습니다. 모든 AZ에 같은 버그가 있는 코드가 배포되어 있으니까요.

따라서 멀티 AZ는 고가용성 전략의 일부일 뿐, 전부가 아닙니다. 마무리 박클라우드 씨의 설명을 들은 이개발 씨는 고개를 끄덕였습니다.

"아, 그래서 프로덕션 환경에서는 항상 멀티 AZ를 쓰라고 하시는 거였군요!" 리전과 AZ의 개념을 제대로 이해하면, AWS 아키텍처 설계의 기본기가 탄탄해집니다. 다음에는 이를 바탕으로 고가용성 설계 원칙을 배워보겠습니다.

실전 팁

💡 - EC2 인스턴스를 생성할 때 서브넷을 선택하는데, 각 서브넷은 특정 AZ에 속합니다. 서브넷을 통해 간접적으로 AZ를 지정하는 것입니다.

  • 멀티 AZ 구성 시 홀수 개(3개, 5개)를 사용하면 네트워크 분할 시 과반수 투표로 의사결정을 할 수 있어 더 안정적입니다.

3. 고가용성 설계 원칙

어느 날 새벽 3시, 이개발 씨의 핸드폰이 울렸습니다. 모니터링 알람이었습니다.

"서버 다운!" 급하게 노트북을 켜고 확인해보니 EC2 인스턴스 하나가 멈춰 있었습니다. 다행히 금방 재시작했지만, 그 짧은 시간 동안 고객들의 불만 전화가 빗발쳤습니다.

CTO님이 아침에 말씀하셨습니다. "이제 고가용성 아키텍처로 전환할 때가 됐네요."

**고가용성(High Availability, HA)**은 시스템이 장애 없이 지속적으로 운영될 수 있도록 설계하는 것입니다. 마치 비상구가 여러 개 있는 건물처럼, 하나의 경로가 막혀도 다른 경로로 서비스를 계속할 수 있게 만듭니다.

일반적으로 99.99%(연간 약 52분 다운타임) 이상의 가용률을 목표로 합니다.

다음 코드를 살펴봅시다.

# Auto Scaling Group으로 고가용성 구성하기
import boto3

autoscaling = boto3.client('autoscaling', region_name='ap-northeast-2')

# Auto Scaling Group 생성 (멀티 AZ)
response = autoscaling.create_auto_scaling_group(
    AutoScalingGroupName='high-availability-asg',
    LaunchTemplate={
        'LaunchTemplateId': 'lt-xxxxx',
        'Version': '$Latest'
    },
    MinSize=2,  # 최소 2대 유지
    MaxSize=10,  # 최대 10대까지 확장
    DesiredCapacity=4,  # 평상시 4대 운영
    AvailabilityZones=[
        'ap-northeast-2a',
        'ap-northeast-2c'
    ],
    HealthCheckType='ELB',  # 로드밸런서 헬스체크
    HealthCheckGracePeriod=300  # 5분 유예기간
)

이개발 씨는 새벽 장애 사건 이후 박클라우드 씨에게 조언을 구했습니다. "선배님, 고가용성 시스템은 어떻게 만드나요?" 박클라우드 씨가 진지한 표정으로 말했습니다.

"좋은 질문이에요. 고가용성은 단순히 서버를 여러 대 띄우는 것 이상입니다.

체계적인 설계 원칙이 필요해요." 고가용성의 핵심 원칙 고가용성 시스템을 만들기 위한 세 가지 핵심 원칙이 있습니다. 첫째는 **중복성(Redundancy)**입니다.

모든 중요한 컴포넌트는 2개 이상 존재해야 합니다. 웹 서버 1대로 운영하지 말고 최소 2대 이상, 데이터베이스도 주-대기 구조로 복제본을 유지합니다.

둘째는 **자동 복구(Auto Recovery)**입니다. 사람이 개입하지 않아도 시스템이 스스로 문제를 감지하고 복구해야 합니다.

새벽 3시에 깨어나 서버를 재시작하는 일이 없어야 합니다. 셋째는 **부하 분산(Load Balancing)**입니다.

트래픽을 여러 서버에 골고루 분배해서 특정 서버에 부하가 몰리지 않도록 합니다. 가용률의 의미 "선배님, 99.99% 가용률이 뭔가요?

거의 100%인데 별 차이 없는 거 아닌가요?" 많은 사람들이 착각하는 부분입니다. 99%와 99.99%는 엄청난 차이입니다.

99% 가용률은 연간 약 3.65일(87.6시간)의 다운타임을 의미합니다. 한 달에 7시간 넘게 서비스가 멈출 수 있다는 뜻입니다.

쇼핑몰이라면 치명적이겠죠. 99.9%는 연간 약 8.76시간, 99.99%는 연간 약 52분, 99.999%는 연간 약 5분의 다운타임입니다.

나인(9)의 개수가 하나 늘어날 때마다 가용성이 10배 향상되고, 구축 비용과 복잡도도 크게 증가합니다. 대부분의 일반적인 웹 서비스는 99.9~99.99%를 목표로 합니다.

금융 거래 시스템이나 응급 서비스처럼 절대 멈춰서는 안 되는 시스템만 99.999% 이상을 추구합니다. 중복성 구현하기 중복성을 어떻게 구현할까요?

가장 기본은 서버 중복입니다. 웹 서버를 최소 2대 이상 운영하고, 앞단에 로드밸런서를 둡니다.

한 대가 다운되면 로드밸런서가 자동으로 나머지 서버로만 트래픽을 보냅니다. 데이터베이스도 중복이 필요합니다.

RDS Multi-AZ를 사용하면 주 데이터베이스와 대기 복제본이 자동으로 동기화됩니다. 주 데이터베이스 장애 시 자동으로 대기 복제본이 주 데이터베이스로 승격됩니다.

네트워크 경로도 중복으로 구성합니다. NAT Gateway도 각 AZ마다 별도로 생성합니다.

하나의 NAT Gateway에 장애가 발생해도 다른 AZ의 서버들은 계속 인터넷에 접근할 수 있습니다. 자동 복구 메커니즘 위의 코드에서 볼 수 있듯이 Auto Scaling Group이 자동 복구의 핵심입니다.

MinSize=2는 항상 최소 2대의 인스턴스가 실행되도록 보장합니다. 하나가 죽으면?

Auto Scaling이 자동으로 새 인스턴스를 시작합니다. HealthCheckType='ELB'는 로드밸런서의 헬스체크를 사용한다는 의미입니다.

인스턴스가 살아있어도 애플리케이션이 응답하지 않으면 비정상으로 판단하고 교체합니다. HealthCheckGracePeriod=300은 새로 시작된 인스턴스가 준비되는 시간을 5분간 기다려준다는 뜻입니다.

애플리케이션이 완전히 로드되기 전에 헬스체크를 하면 정상 인스턴스도 비정상으로 오판할 수 있으니까요. 부하 분산 전략 **Application Load Balancer(ALB)**는 여러 가지 라우팅 알고리즘을 제공합니다.

기본은 라운드 로빈입니다. 요청이 들어올 때마다 서버1, 서버2, 서버3 순서로 돌아가며 분배합니다.

간단하고 효과적입니다. 최소 연결(Least Outstanding Requests) 알고리즘도 있습니다.

현재 처리 중인 요청이 가장 적은 서버로 새 요청을 보냅니다. 요청 처리 시간이 들쭉날쭉한 경우 유용합니다.

실무 사례 대형 이커머스 회사의 아키텍처를 예로 들어보겠습니다. 프론트엔드 웹 서버는 3개 AZ에 각각 최소 2대씩, 총 6대 이상 운영합니다.

Auto Scaling으로 트래픽 증가 시 자동 확장됩니다. 블랙프라이데이 같은 대목에는 자동으로 수십 대까지 늘어납니다.

데이터베이스는 RDS Multi-AZ로 구성하고, 읽기 전용 복제본(Read Replica)을 추가로 3~5개 운영합니다. 쓰기는 주 데이터베이스로, 읽기는 복제본으로 분산해서 부하를 나눕니다.

캐시 레이어로 ElastiCache for Redis를 사용하는데, 이것도 Multi-AZ 클러스터 모드로 운영합니다. 캐시 노드 하나가 죽어도 다른 노드가 즉시 승격됩니다.

비용과 복잡도의 균형 "선배님, 그럼 무조건 많이 복제하면 좋은 거 아닌가요?" 이론적으로는 그렇습니다. 하지만 현실에서는 비용과 복잡도를 고려해야 합니다.

스타트업 초기에는 99.9% 가용률로 시작하는 것이 합리적입니다. ALB + Auto Scaling으로 2개 AZ에 각각 최소 1대씩 배포하는 정도면 충분합니다.

월 수백만 원 정도의 비용으로 가능합니다. 서비스가 성장하고 매출이 늘어나면 점진적으로 99.99%를 목표로 업그레이드합니다.

더 많은 AZ, 더 많은 인스턴스, 더 정교한 모니터링을 추가합니다. 주의사항 고가용성 아키텍처를 구축했다고 해서 끝이 아닙니다.

정기적인 **장애 훈련(Chaos Engineering)**이 필수입니다. 넷플릭스는 Chaos Monkey라는 도구로 무작위로 프로덕션 서버를 종료합니다.

시스템이 정말 자동 복구되는지 실전처럼 테스트하는 것입니다. 또한 고가용성 시스템도 정기 점검이 필요합니다.

Auto Scaling 설정이 올바른지, 헬스체크가 제대로 작동하는지, 알람이 정상 발송되는지 주기적으로 확인해야 합니다. 마무리 박클라우드 씨가 마무리했습니다.

"고가용성은 기술이면서 동시에 문화입니다. 처음부터 완벽하게 만들 수는 없어요.

작은 장애를 경험하면서 점진적으로 개선해나가는 거죠." 이개발 씨는 이제 자신감이 생겼습니다. "다음번에는 새벽에 알람이 울려도 당황하지 않을 것 같아요!"

실전 팁

💡 - AWS Well-Architected Framework의 신뢰성 원칙을 참고하세요. 고가용성 설계의 모범 사례가 잘 정리되어 있습니다.

  • 처음부터 과도하게 설계하지 말고, 현재 트래픽의 2~3배를 처리할 수 있는 수준으로 시작한 후 점진적으로 확장하세요.

4. 내결함성이란

고가용성 아키텍처를 성공적으로 구축한 이개발 씨는 뿌듯했습니다. 그런데 어느 날 코드 배포 중 실수로 잘못된 버전을 올렸고, 모든 서버가 동시에 에러를 뿜어냈습니다.

Auto Scaling이 열심히 서버를 재시작했지만 소용없었습니다. 모든 서버가 같은 버그를 가지고 있었으니까요.

CTO님이 말씀하셨습니다. "고가용성만으로는 부족해요.

내결함성도 필요합니다."

**내결함성(Fault Tolerance)**은 시스템 일부에 장애가 발생해도 전체 서비스가 계속 작동할 수 있는 능력입니다. 마치 인체가 한쪽 폐에 문제가 생겨도 다른 쪽 폐로 호흡을 계속하는 것처럼, 시스템도 부분적인 장애를 견디며 기능을 유지합니다.

고가용성이 '멈추지 않기'라면, 내결함성은 '장애를 흡수하기'입니다.

다음 코드를 살펴봅시다.

# Circuit Breaker 패턴으로 내결함성 구현
import time
from enum import Enum

class CircuitState(Enum):
    CLOSED = "closed"  # 정상 상태
    OPEN = "open"      # 차단 상태
    HALF_OPEN = "half_open"  # 복구 시도 상태

class CircuitBreaker:
    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.timeout = timeout
        self.state = CircuitState.CLOSED
        self.last_failure_time = None

    def call(self, func):
        # OPEN 상태: 일정 시간 후 HALF_OPEN으로 전환
        if self.state == CircuitState.OPEN:
            if time.time() - self.last_failure_time > self.timeout:
                self.state = CircuitState.HALF_OPEN
            else:
                return {"error": "Circuit is OPEN"}

        try:
            result = func()
            # 성공하면 카운터 초기화
            if self.state == CircuitState.HALF_OPEN:
                self.state = CircuitState.CLOSED
            self.failure_count = 0
            return result
        except Exception as e:
            self.failure_count += 1
            self.last_failure_time = time.time()

            # 임계값 초과시 OPEN으로 전환
            if self.failure_count >= self.failure_threshold:
                self.state = CircuitState.OPEN

            return {"error": str(e)}

이개발 씨는 충격을 받았습니다. "선배님, Auto Scaling으로 고가용성을 만들었는데 왜 막지 못했죠?" 박클라우드 씨가 차분히 설명했습니다.

"고가용성과 내결함성은 다른 개념이에요. 둘 다 필요합니다." 고가용성 vs 내결함성 쉽게 비유해보겠습니다.

고가용성은 예비 전구를 준비하는 것입니다. 전구 하나가 나가면 즉시 다른 전구가 켜지도록 하는 것이죠.

하드웨어 장애, 네트워크 단절, AZ 장애 같은 인프라 문제에 대비합니다. 내결함성은 전구가 깜빡거리거나 불안정할 때도 조명이 계속 작동하도록 하는 것입니다.

소프트웨어 버그, 외부 API 지연, 일시적인 과부하 같은 애플리케이션 레벨 문제를 견뎌냅니다. 이개발 씨의 경우, 모든 서버가 살아있었지만(고가용성 OK) 애플리케이션 버그로 인해 서비스가 중단되었습니다(내결함성 실패).

내결함성의 핵심 패턴 내결함성을 구현하는 여러 패턴이 있습니다. 첫째는 **Circuit Breaker(회로 차단기)**입니다.

위의 코드가 바로 이 패턴입니다. 외부 서비스 호출이 반복적으로 실패하면, 일정 시간 동안 호출을 차단하고 즉시 에러를 반환합니다.

마치 전기 회로의 퓨즈가 과부하 시 자동으로 차단되는 것과 같습니다. 둘째는 **Timeout and Retry(타임아웃과 재시도)**입니다.

외부 API 호출에 타임아웃을 설정하고, 실패 시 지수 백오프 방식으로 재시도합니다. 무한정 기다리지 않고, 빠르게 실패하고 복구를 시도합니다.

셋째는 **Bulkhead(격벽)**입니다. 배의 격벽처럼 시스템을 여러 구획으로 나눕니다.

한 구획에 물이 차도 전체 배가 가라앉지 않도록 합니다. 넷째는 **Graceful Degradation(우아한 성능 저하)**입니다.

전체 기능을 중단하는 대신, 핵심 기능만 유지하고 부가 기능은 일시적으로 비활성화합니다. Circuit Breaker 상세 분석 위의 코드를 자세히 살펴보겠습니다.

Circuit Breaker는 세 가지 상태를 가집니다. CLOSED(정상) 상태에서는 모든 요청을 정상적으로 처리합니다.

하지만 실패 횟수를 카운트합니다. 실패가 failure_threshold(예: 5번)를 넘어서면 OPEN(차단) 상태로 전환됩니다.

이 상태에서는 실제 함수를 호출하지 않고 즉시 에러를 반환합니다. 장애가 발생한 서비스에 계속 요청을 보내봤자 시간만 낭비하고 시스템만 더 불안정해지니까요.

timeout 시간(예: 60초)이 지나면 HALF_OPEN(반개방) 상태로 전환됩니다. 이 상태에서는 조심스럽게 실제 요청을 시도해봅니다.

성공하면 CLOSED로 돌아가고, 실패하면 다시 OPEN으로 돌아갑니다. 실무 적용 사례 대형 쇼핑몰의 추천 시스템을 예로 들어보겠습니다.

메인 페이지에는 "당신을 위한 추천 상품"이 표시됩니다. 이것은 복잡한 ML 모델을 호출하는 무거운 작업입니다.

만약 추천 API가 느려지거나 장애가 나면 어떻게 될까요? 내결함성 없이 구현하면, 추천 API가 응답하지 않아 메인 페이지 전체가 로딩되지 않습니다.

사용자는 아무것도 볼 수 없습니다. 내결함성을 적용하면 어떻게 될까요?

추천 API 호출에 Circuit Breaker와 타임아웃(500ms)을 설정합니다. API가 응답하지 않으면 0.5초 후 타임아웃하고, 대신 캐시된 인기 상품 목록을 보여줍니다.

사용자는 개인화된 추천은 못 보지만, 메인 페이지는 정상적으로 볼 수 있습니다. 이것이 바로 Graceful Degradation입니다.

AWS에서의 내결함성 AWS는 여러 서비스로 내결함성을 지원합니다. **Amazon SQS(Simple Queue Service)**를 사용하면 서비스 간 결합도를 낮출 수 있습니다.

주문 서비스가 결제 서비스를 직접 호출하는 대신, 메시지 큐에 주문 정보를 넣습니다. 결제 서비스가 일시적으로 다운되어도 주문은 계속 접수되고, 결제는 나중에 처리됩니다.

AWS Lambda의 Reserved Concurrency를 사용하면 Bulkhead 패턴을 구현할 수 있습니다. 중요한 Lambda 함수에 전용 동시 실행 수를 할당해서, 덜 중요한 함수들이 리소스를 모두 차지하는 것을 방지합니다.

Amazon Route 53 Health Check와 장애 조치 라우팅으로 리전 레벨의 내결함성을 구현할 수 있습니다. 서울 리전 전체에 장애가 발생하면 자동으로 도쿄 리전으로 트래픽을 전환합니다.

마이크로서비스와 내결함성 마이크로서비스 아키텍처에서는 내결함성이 특히 중요합니다. 하나의 거대한 모놀리식 애플리케이션에서는 한 기능의 버그가 전체를 다운시킬 수 있습니다.

하지만 마이크로서비스로 나누면, 추천 서비스에 장애가 나도 주문 서비스, 결제 서비스는 계속 작동합니다. 단, 서비스 간 호출이 많아지므로 Circuit Breaker, 타임아웃 같은 내결함성 패턴을 필수적으로 적용해야 합니다.

비용과 복잡도 "선배님, 내결함성을 구현하려면 코드가 엄청 복잡해지지 않나요?" 맞습니다. 코드는 확실히 복잡해집니다.

하지만 요즘은 라이브러리가 잘 되어있습니다. Python에서는 pybreaker, tenacity 같은 라이브러리를 사용하면 Circuit Breaker와 Retry 로직을 쉽게 추가할 수 있습니다.

Java에서는 Netflix Hystrix, Resilience4j가 있습니다. 서비스 메시(Service Mesh)인 Istio나 AWS App Mesh를 사용하면, 애플리케이션 코드를 수정하지 않고도 인프라 레벨에서 내결함성 패턴을 적용할 수 있습니다.

주의사항 내결함성 패턴을 과도하게 적용하면 오히려 문제가 될 수 있습니다. 모든 함수 호출에 Circuit Breaker를 넣으면 디버깅이 어려워집니다.

진짜 장애인지, Circuit이 열려서 차단된 건지 구분하기 힘듭니다. 따라서 외부 서비스 호출, 데이터베이스 쿼리, 네트워크 I/O처럼 실패 가능성이 높고 시스템에 영향이 큰 부분에만 선택적으로 적용하세요.

마무리 박클라우드 씨가 정리했습니다. "고가용성은 하드웨어 장애를, 내결함성은 소프트웨어 장애를 다룹니다.

둘 다 필요해요." 이개발 씨는 이제 확실히 이해했습니다. "다음번 배포에는 Circuit Breaker를 꼭 추가하겠습니다!"

실전 팁

💡 - Netflix의 Chaos Monkey처럼 의도적으로 장애를 발생시켜 내결함성을 테스트하세요. 프로덕션에서 갑자기 장애가 나는 것보다 통제된 환경에서 미리 경험하는 게 훨씬 낫습니다.

  • Circuit Breaker의 임계값과 타임아웃은 실제 트래픽 패턴을 분석해서 설정하세요. 너무 낮으면 오탐이, 너무 높으면 장애 감지가 늦어집니다.

5. 멀티 AZ 배포 전략

이개발 씨의 서비스가 빠르게 성장했습니다. 이제 일일 사용자가 10만 명을 넘어섰습니다.

CTO님이 새로운 미션을 주셨습니다. "현재 단일 AZ 배포를 멀티 AZ로 전환해주세요.

다음 주까지요." 이개발 씨는 멀티 AZ의 개념은 알지만, 실제로 어떻게 구성하고 전환해야 할지 막막했습니다.

멀티 AZ 배포는 애플리케이션의 모든 계층을 2개 이상의 가용 영역에 분산 배치하는 전략입니다. 마치 중요한 문서의 백업을 여러 장소에 보관하는 것처럼, 서버, 데이터베이스, 로드밸런서를 각각 다른 AZ에 복제합니다.

이를 통해 하나의 AZ 전체가 장애를 겪어도 서비스는 계속됩니다.

다음 코드를 살펴봅시다.

# Terraform으로 멀티 AZ 웹 애플리케이션 구성
# Application Load Balancer - 멀티 AZ 설정
resource "aws_lb" "main" {
  name               = "multi-az-alb"
  load_balancer_type = "application"
  subnets            = [
    aws_subnet.public_2a.id,
    aws_subnet.public_2c.id
  ]
}

# Auto Scaling Group - 멀티 AZ
resource "aws_autoscaling_group" "web" {
  name                = "web-asg"
  vpc_zone_identifier = [
    aws_subnet.private_2a.id,
    aws_subnet.private_2c.id
  ]
  target_group_arns   = [aws_lb_target_group.web.arn]

  min_size             = 2
  max_size             = 10
  desired_capacity     = 4
  health_check_type    = "ELB"

  # AZ 간 균등 분산
  enabled_metrics = ["GroupInServiceInstances"]
}

# RDS - Multi-AZ 설정
resource "aws_db_instance" "main" {
  identifier              = "multi-az-db"
  engine                  = "postgres"
  instance_class          = "db.t3.medium"
  multi_az                = true  # Multi-AZ 활성화
  availability_zone       = "ap-northeast-2a"  # Primary AZ
  backup_retention_period = 7
}

이개발 씨는 박클라우드 씨에게 도움을 요청했습니다. "선배님, 멀티 AZ 전환은 어디서부터 시작해야 하나요?" 박클라우드 씨가 화이트보드를 꺼내며 전체 그림을 그리기 시작했습니다.

멀티 AZ 아키텍처의 전체 구조 전형적인 3-tier 웹 애플리케이션의 멀티 AZ 구성을 보겠습니다. 맨 앞단에는 **Application Load Balancer(ALB)**가 있습니다.

ALB는 생성 시 최소 2개 AZ를 지정해야 합니다. 위 코드에서 public_2apublic_2c 서브넷을 지정했죠.

이 두 AZ에 ALB의 노드가 자동으로 배치됩니다. 중간 계층은 웹 서버들입니다.

Auto Scaling Group에 private_2aprivate_2c 서브넷을 지정하면, 인스턴스들이 두 AZ에 자동으로 분산됩니다. min_size=2로 설정했으므로, 각 AZ에 최소 1대씩 배치하려고 노력합니다.

데이터 계층은 RDS입니다. multi_az=true로 설정하면, 주 데이터베이스는 2a에, 대기 복제본은 자동으로 다른 AZ(2c)에 배치됩니다.

단계별 전환 전략 기존 단일 AZ 시스템을 멀티 AZ로 전환하는 과정을 살펴보겠습니다. 1단계: 네트워크 준비 먼저 VPC에 새로운 서브넷을 추가합니다.

기존에 2a AZ만 사용했다면, 2c AZ에 퍼블릭 서브넷과 프라이빗 서브넷을 생성합니다. CIDR 블록이 겹치지 않도록 주의하세요.

라우트 테이블도 설정합니다. 각 AZ의 프라이빗 서브넷은 해당 AZ의 NAT Gateway를 사용하도록 라우팅합니다.

이렇게 하면 하나의 NAT Gateway 장애가 다른 AZ에 영향을 주지 않습니다. 2단계: 로드밸런서 수정 기존 ALB에 새로운 AZ를 추가합니다.

ALB 콘솔에서 "Edit subnets"를 선택하고 2c AZ의 서브넷을 추가하면 됩니다. 이 작업은 무중단으로 가능합니다.

Target Group의 헬스체크 설정을 확인합니다. HealthCheckIntervalSeconds는 30초, UnhealthyThresholdCount는 2 정도가 적당합니다.

너무 민감하면 일시적인 지연에도 인스턴스를 제외해버립니다. 3단계: Auto Scaling 설정 업데이트 Auto Scaling Group의 서브넷 설정을 수정해서 두 AZ를 모두 포함시킵니다.

그리고 desired_capacity를 짝수로 설정합니다. 4대로 설정하면 각 AZ에 2대씩 배치하려고 시도합니다.

Auto Scaling은 기본적으로 AZ 간 균형을 맞추려고 노력합니다. 한 AZ에 3대, 다른 AZ에 1대처럼 불균형이 생기면 자동으로 조정합니다.

4단계: 데이터베이스 Multi-AZ 전환 RDS를 Multi-AZ로 전환하는 것은 신중해야 합니다. 전환 과정에서 짧은 다운타임(1~2분)이 발생합니다.

RDS 콘솔에서 "Modify"를 선택하고 "Multi-AZ deployment" 옵션을 활성화합니다. "Apply immediately"를 선택하면 즉시 전환되고, 아니면 다음 유지보수 시간에 전환됩니다.

전환 과정에서 AWS가 자동으로 다른 AZ에 대기 복제본을 생성하고, 데이터를 동기화합니다. 동기화가 완료되면 짧은 재시작과 함께 Multi-AZ 모드로 전환됩니다.

5단계: 검증 및 모니터링 모든 설정을 완료한 후 반드시 테스트합니다. CloudWatch에서 각 AZ별 인스턴스 개수를 모니터링합니다.

GroupInServiceInstances 메트릭을 AZ로 그룹핑하면 분포를 확인할 수 있습니다. 의도적으로 한 AZ의 인스턴스를 종료해봅니다.

Auto Scaling이 자동으로 새 인스턴스를 시작하는지, ALB가 나머지 AZ로 트래픽을 라우팅하는지 확인합니다. AZ 간 데이터 동기화 "선배님, 두 AZ에 서버가 있으면 사용자 세션은 어떻게 되나요?" 좋은 질문입니다.

이것이 바로 상태 관리(State Management) 문제입니다. Sticky Session을 사용하면 같은 사용자는 항상 같은 서버로 라우팅됩니다.

ALB의 Target Group에서 활성화할 수 있습니다. 하지만 이 방식은 해당 서버가 다운되면 세션이 손실됩니다.

더 나은 방법은 중앙 집중식 세션 저장소를 사용하는 것입니다. ElastiCache for Redis에 세션을 저장하면, 어떤 서버로 라우팅되어도 세션을 공유할 수 있습니다.

Redis도 Multi-AZ 클러스터로 구성하면 완벽합니다. 비용 최적화 멀티 AZ 배포는 당연히 비용이 증가합니다.

서버가 2배, NAT Gateway도 2개니까요. 하지만 비용을 절약하는 전략도 있습니다.

개발/스테이징 환경은 단일 AZ로 운영하고, 프로덕션만 멀티 AZ로 구성합니다. 개발 환경에서는 높은 가용성이 필요하지 않으니까요.

NAT Gateway는 비용이 꽤 나갑니다(시간당 약 $0.045 + 데이터 전송). 트래픽이 적다면 하나의 NAT Gateway를 공유하는 것도 고려할 수 있습니다.

물론 가용성은 조금 낮아집니다. 실무 경험담 실제로 멀티 AZ 전환을 진행한 회사의 사례를 들려드리겠습니다.

어느 날 AWS 서울 리전의 2a AZ에서 네트워크 장애가 발생했습니다. 약 2시간 동안 2a AZ의 일부 서비스가 불안정했죠.

단일 AZ로 운영하던 서비스 A는 완전히 다운되었습니다. 2시간 동안 매출이 0원이었습니다.

반면 멀티 AZ로 구성한 서비스 B는? 사용자들은 전혀 눈치채지 못했습니다.

ALB가 자동으로 2c AZ의 서버들로만 트래픽을 보냈으니까요. RDS Multi-AZ도 자동으로 장애조치(failover)되어 2c AZ의 대기 복제본이 주 데이터베이스로 승격되었습니다.

약 1분 30초의 전환 시간만 있었을 뿐입니다. 주의사항 멀티 AZ를 구성했다고 해서 완벽한 것은 아닙니다.

AZ 간 데이터 전송은 무료이지만, 리전 간 전송은 유료입니다. 실수로 다른 리전의 리소스에 접근하지 않도록 주의하세요.

또한 멀티 AZ는 인프라 장애만 해결합니다. 잘못된 코드 배포, 보안 침해, 설정 오류 같은 문제는 멀티 AZ로 막을 수 없습니다.

모든 AZ에 같은 버그가 배포되니까요. 마무리 박클라우드 씨가 마무리했습니다.

"멀티 AZ 전환은 한 번에 하는 게 아니라 단계적으로 진행하세요. 네트워크부터 차근차근 준비하면 리스크를 줄일 수 있습니다." 이개발 씨는 이제 자신감이 생겼습니다.

"다음 주까지 충분히 완료할 수 있을 것 같아요!"

실전 팁

💡 - 멀티 AZ 전환은 트래픽이 적은 새벽 시간에 진행하세요. 문제가 생겨도 영향을 최소화할 수 있습니다.

  • 전환 전에 반드시 데이터베이스 스냅샷을 생성하세요. 만약의 사태에 대비한 백업입니다.

6. 단일 장애 지점 제거하기

멀티 AZ 전환을 성공적으로 마친 이개발 씨는 뿌듯했습니다. 그런데 시니어 아키텍트 정전문 님이 아키텍처 리뷰를 하시더니 이렇게 말씀하셨습니다.

"좋아요, 하지만 여기 NAT Gateway가 단일 장애 지점(SPOF)이네요. 그리고 이 배치 서버도요." 이개발 씨는 당황했습니다.

멀티 AZ로 다 해결한 줄 알았는데, 아직도 취약점이 있다니요.

**단일 장애 지점(Single Point of Failure, SPOF)**은 시스템에서 하나만 존재하는 컴포넌트로, 이것이 고장 나면 전체 시스템이 멈추는 부분입니다. 마치 체인의 가장 약한 고리처럼, SPOF 하나가 무너지면 아무리 다른 부분이 튼튼해도 소용없습니다.

SPOF를 찾아서 제거하는 것이 고가용성 설계의 핵심입니다.

다음 코드를 살펴봅시다.

# SPOF 식별 및 제거 체크리스트 스크립트
import boto3
from collections import defaultdict

def find_spof_in_architecture():
    ec2 = boto3.client('ec2', region_name='ap-northeast-2')
    elb = boto3.client('elbv2', region_name='ap-northeast-2')
    rds = boto3.client('rds', region_name='ap-northeast-2')

    spof_report = defaultdict(list)

    # 1. NAT Gateway 중복성 확인
    nat_gateways = ec2.describe_nat_gateways()
    az_nat_count = defaultdict(int)
    for nat in nat_gateways['NatGateways']:
        if nat['State'] == 'available':
            az_nat_count[nat['SubnetId']] += 1

    if len(az_nat_count) < 2:
        spof_report['NAT Gateway'].append(
            "NAT Gateway가 단일 AZ에만 존재합니다"
        )

    # 2. Load Balancer AZ 분산 확인
    lbs = elb.describe_load_balancers()
    for lb in lbs['LoadBalancers']:
        az_count = len(lb['AvailabilityZones'])
        if az_count < 2:
            spof_report['Load Balancer'].append(
                f"{lb['LoadBalancerName']}: {az_count}개 AZ만 사용"
            )

    # 3. RDS Multi-AZ 확인
    databases = rds.describe_db_instances()
    for db in databases['DBInstances']:
        if not db['MultiAZ']:
            spof_report['Database'].append(
                f"{db['DBInstanceIdentifier']}: Multi-AZ 미사용"
            )

    # 4. 보고서 출력
    print("=== SPOF 분석 보고서 ===")
    for component, issues in spof_report.items():
        print(f"\n[{component}]")
        for issue in issues:
            print(f"  - {issue}")

    return spof_report

이개발 씨는 정전문 아키텍트에게 조언을 구했습니다. "팀장님, SPOF를 어떻게 찾고 제거하나요?" 정전문 님이 경험을 바탕으로 자세히 설명해주셨습니다.

SPOF의 숨은 위치 많은 개발자들이 웹 서버와 데이터베이스만 중복 구성하고 끝냅니다. 하지만 SPOF는 생각보다 많은 곳에 숨어있습니다.

첫 번째는 NAT Gateway입니다. 프라이빗 서브넷의 인스턴스들이 인터넷에 접근하려면 NAT Gateway를 거쳐야 합니다.

하나의 NAT Gateway만 있다면? 그것이 고장 나면 모든 서버가 외부 API를 호출할 수 없게 됩니다.

두 번째는 배치 작업 서버입니다. 많은 팀이 단일 EC2 인스턴스에서 cron으로 정기 작업을 돌립니다.

이 서버가 다운되면 일일 정산, 데이터 동기화 같은 중요한 작업이 멈춥니다. 세 번째는 모니터링 시스템입니다.

아이러니하게도 모니터링 서버 자체가 SPOF인 경우가 많습니다. 모니터링 서버가 다운되면, 다른 시스템의 장애를 감지할 수 없게 됩니다.

네 번째는 VPN 서버입니다. 회사에서 AWS 리소스에 접근할 때 VPN을 사용한다면, VPN 서버가 단일 인스턴스면 SPOF입니다.

다섯 번째는 DNS입니다. 자체 DNS 서버를 운영한다면 이것도 중복 구성이 필요합니다.

NAT Gateway SPOF 제거 가장 흔한 SPOF인 NAT Gateway부터 해결해보겠습니다. 올바른 구성은 각 AZ마다 별도의 NAT Gateway를 두는 것입니다.

2a AZ에 하나, 2c AZ에 하나를 생성합니다. 그리고 각 AZ의 프라이빗 서브넷 라우트 테이블을 수정합니다.

2a AZ의 프라이빗 서브넷은 2a AZ의 NAT Gateway를 사용하도록, 2c AZ는 2c AZ의 NAT Gateway를 사용하도록 라우팅합니다. 이렇게 하면 하나의 NAT Gateway가 장애를 겪어도, 다른 AZ의 서버들은 영향을 받지 않습니다.

비용이 걱정된다면? NAT Gateway는 시간당 약 $0.045입니다.

한 달에 약 $32 정도죠. 두 개를 쓰면 $64입니다.

장애로 인한 매출 손실을 생각하면 충분히 정당화됩니다. 배치 작업 SPOF 제거 배치 작업은 어떻게 중복 구성할까요?

같은 작업을 두 서버에서 동시에 실행하면 중복 처리되는 문제가 생깁니다. 여러 해결책이 있습니다.

Amazon EventBridge Scheduler를 사용하는 방법이 가장 간단합니다. EventBridge는 AWS 관리형 서비스로 자체적으로 고가용성이 보장됩니다.

정해진 시간에 Lambda 함수를 호출하거나 ECS 태스크를 시작하도록 설정할 수 있습니다. 직접 서버에서 실행해야 한다면 **분산 락(Distributed Lock)**을 사용합니다.

DynamoDB의 조건부 쓰기나 Redis의 SETNX 명령으로 락을 구현할 수 있습니다. 여러 서버가 동시에 실행을 시도하지만, 락을 획득한 하나만 실제로 실행됩니다.

Kubernetes CronJob을 사용한다면 자동으로 하나의 Pod만 실행되도록 보장됩니다. 로드밸런서 SPOF 위험 "팀장님, ALB는 AWS 관리형 서비스인데도 SPOF가 될 수 있나요?" 날카로운 질문입니다.

ALB 자체는 AWS가 관리하므로 자동으로 고가용성이 보장됩니다. 하지만 설정 실수로 SPOF가 만들어질 수 있습니다.

예를 들어 ALB를 단일 AZ에만 배치하면 SPOF입니다. 반드시 2개 이상의 AZ를 선택해야 합니다.

또한 Target Group에 등록된 인스턴스가 모두 한 AZ에만 있다면? 기술적으로는 다른 AZ에도 ALB 노드가 있지만, 모든 트래픽이 한 AZ로 집중됩니다.

그 AZ에 장애가 나면 서비스 전체가 멈춥니다. 데이터베이스 SPOF RDS Multi-AZ를 사용하면 데이터베이스 SPOF는 해결됩니다.

하지만 완벽한 것은 아닙니다. 장애 조치(failover) 과정에서 1~2분의 다운타임이 발생합니다.

DNS 레코드가 대기 복제본을 가리키도록 변경되는 시간이 필요하기 때문입니다. 더 높은 가용성이 필요하다면 Aurora Global DatabaseAurora Multi-Master를 고려하세요.

초 단위 장애 조치가 가능합니다. 모니터링 시스템 클라우드 환경에서는 모니터링 시스템도 SPOF 없이 구성할 수 있습니다.

CloudWatch를 사용하면 AWS가 고가용성을 보장합니다. 자체 Prometheus나 Grafana를 운영한다면 이것들도 멀티 AZ로 구성하거나, 관리형 서비스인 Amazon Managed GrafanaAmazon Managed Service for Prometheus를 사용하세요.

알람 시스템도 중요합니다. 단일 Slack 채널이나 이메일에만 의존하지 말고, SNS를 사용해 여러 채널로 알람을 보내세요.

전화, 이메일, SMS, Slack, PagerDuty 등 다양한 경로를 설정합니다. SPOF 체크리스트 위의 Python 코드는 자동으로 SPOF를 찾아주는 스크립트입니다.

NAT Gateway가 몇 개 AZ에 분산되어 있는지, Load Balancer가 여러 AZ를 사용하는지, RDS가 Multi-AZ 모드인지 자동으로 검사합니다. 이런 스크립트를 주기적으로 실행하면, 새로 추가된 리소스 중 SPOF가 있는지 조기에 발견할 수 있습니다.

CI/CD 파이프라인에 통합해서 배포 시마다 자동으로 검사하는 것도 좋은 방법입니다. 비용 대비 효과 "팀장님, 모든 걸 중복 구성하면 비용이 배로 들지 않나요?" 맞습니다.

SPOF 제거는 비용이 듭니다. 하지만 우선순위를 정할 수 있습니다.

**핵심 경로(Critical Path)**부터 SPOF를 제거하세요. 사용자 요청을 처리하는 경로에 있는 컴포넌트들이 최우선입니다.

웹 서버, 데이터베이스, 로드밸런서, NAT Gateway 등이죠. 관리용 도구나 개발 환경은 낮은 우선순위입니다.

사내 위키 서버가 잠깐 다운되는 것은 매출에 영향이 없습니다. 비용과 리스크를 저울질해서 합리적인 수준을 찾으세요.

실무 경험담 어느 스타트업의 실제 사례입니다. 그들은 배치 작업 서버를 단일 인스턴스로 운영하고 있었습니다.

어느 날 그 서버의 디스크가 가득 차서 다운되었습니다. 문제는, 그 서버에서 매일 밤 신규 가입자에게 환영 이메일을 보내는 작업이 돌고 있었다는 것입니다.

3일간 배치가 돌지 않아서, 그 기간 동안 가입한 1,500명의 고객이 환영 이메일을 받지 못했습니다. 일부는 "이 서비스 제대로 운영되는 거 맞나?"라며 탈퇴했습니다.

이 사건 이후 그들은 배치 작업을 EventBridge + Lambda로 전환했습니다. 비용은 오히려 줄었고(EC2보다 Lambda가 저렴), 가용성은 크게 향상되었습니다.

주의사항 SPOF를 과도하게 걱정하다가 과도한 엔지니어링을 하지 마세요. 스타트업 초기에 글로벌 멀티 리전 구성까지 할 필요는 없습니다.

현실적인 리스크를 평가하고, 비즈니스 상황에 맞는 수준을 선택하세요. 또한 SPOF 제거만으로는 부족합니다.

정기적인 장애 훈련, 모니터링, 백업 등 종합적인 접근이 필요합니다. 마무리 정전문 님이 조언을 마무리했습니다.

"SPOF 제거는 한 번에 완성되는 게 아니에요. 시스템이 성장하면서 계속 발견하고 개선하는 과정입니다." 이개발 씨는 이제 확신이 생겼습니다.

"주말에 NAT Gateway부터 중복 구성해보겠습니다!" 고가용성과 내결함성 아키텍처는 완벽한 상태가 없습니다. 지속적으로 개선하고, 장애에서 배우며, 점진적으로 발전시켜 나가는 것입니다.

실전 팁

💡 - AWS Well-Architected Tool을 사용하면 자동으로 아키텍처의 취약점을 분석해줍니다. SPOF 발견에 유용합니다.

  • 분기별로 "SPOF 헌팅 데이"를 정해서 팀 전체가 아키텍처를 점검하는 시간을 가지세요. 새로운 시각으로 보면 놓쳤던 SPOF를 발견할 수 있습니다.

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#AWS#HighAvailability#FaultTolerance#MultiAZ#CloudArchitecture#AWS,Architecture

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

VPC 네트워크의 기초 - CIDR과 서브넷 설계 완벽 가이드

초급 개발자를 위한 VPC와 서브넷 설계 입문서입니다. 도서관 비유로 CIDR 개념을 쉽게 이해하고, 실무에서 자주 사용하는 서브넷 분할 전략을 단계별로 배워봅니다. 점프 투 자바 스타일로 술술 읽히는 네트워크 입문 가이드입니다.

AWS 리소스 정리와 비용 관리 완벽 가이드

AWS 사용 후 리소스를 안전하게 정리하고 예상치 못한 과금을 방지하는 방법을 배웁니다. 프리티어 관리부터 비용 모니터링까지 실무에서 꼭 필요한 내용을 다룹니다.

AWS Certificate Manager로 HTTPS 인증서 발급 완벽 가이드

AWS Certificate Manager를 사용하여 무료로 SSL/TLS 인증서를 발급받고, 로드 밸런서에 적용하여 안전한 HTTPS 웹 서비스를 구축하는 방법을 초급자도 쉽게 따라 할 수 있도록 단계별로 안내합니다.

Route 53으로 도메인 연결 완벽 가이드

AWS Route 53을 사용하여 도메인을 등록하고 실제 서비스에 연결하는 전 과정을 실무 스토리와 함께 쉽게 배워봅니다. DNS의 기본 개념부터 레코드 설정, ELB 연결까지 초급 개발자도 쉽게 따라할 수 있도록 구성했습니다.

AWS RDS 관리형 데이터베이스 완벽 가이드

직접 데이터베이스를 설치하고 관리하는 것이 부담스러운 초급 개발자를 위한 RDS 가이드입니다. 데이터베이스 엔진 선택부터 인스턴스 생성, 보안 설정, 백업까지 실무에 필요한 모든 내용을 다룹니다.