English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

게스트
1 / ?
수업 목록으로

두 가지 트래픽 방향, 하나의 박스

환영합니다

대부분의 아키텍처 다이어그램은 트래픽이 한 방향으로 흐르는 것을 보여줍니다: 위에는 클라이언트, 아래에는 서버, 그리고 아래를 가리키는 화살표. 하지만 현실에서는 트래픽이 양방향으로 흐릅니다.

인그레스(Ingress): 외부 클라이언트가 이 경로를 통해 서비스로 접근합니다. 네트워크 가장자리에 위치한 리버스 프록시는 TLS를 종료하고, 요청을 라우팅하며, 접근 정책을 강제합니다.

에그레스(Egress): 이 경로를 통해 서비스가 외부 서비스로 접근합니다. 결제 프로세서 API 호출, 웹훅 대상 가져오기, 파트너에게 요청 전송 등이 해당됩니다. 종종 허용 목록(allowlist)이 있는 포워드 프록시 또는 NAT 게이트웨이를 통해 이루어집니다.

많은 아키텍처는 하나의 박스(box)가 양쪽 방향의 트래픽을 모두 처리하도록 시작합니다. 처음에는 잘 작동하지만, 내부 서비스가 충분히 쌓인 후에야 문제가 드러나기 시작합니다. 이러한 실패 모드는 은미하며, 관심사 분리(separation-of-concerns)의 중요성을 가르치는 중요한 교훈을 제공합니다.

이 레슨을 마치면 다음 사항을 이해하게 됩니다:

- 왜 인그레스(ingress)와 에그레스(egress)가 근본적으로 다른 트래픽 패턴을 가지며, 서로 다른 스케일링 축과 실패 모드를 갖는지

- 헤어핀 NAT(Hairpin NAT)과 왜 프록시가 자기 자신으로 연결하려 할 때 실패하는지

- 아키텍처의 갈림길: 하나의 박스가 두 개로 분리되는 과정과, 분리된 각 박스가 독점적으로 담당하게 되는 역할

- 보안 격리상의 이점: 각 쪽이 실제로 허용된 피어(peers)에 대해서만 잠금(lock down)을 설정할 수 있게 되는 것

- 단일 박스 설계가 분리가 필수적인 임계점을 넘어섰음을 어떻게 식별하는지

왜 방향에 따라 다른 도구가 필요한가

하나의 네트워크 경계에서의 두 가지 다른 워크로드

입력(Ingress) 트래픽 특성:

- 외부 당사자(광범위한 인터넷)에 의해 시작됨

- 볼륨이 사용자 기반 규모에 따라 확장됨

- TLS 종결, 요청 라우팅, 소스별 속도 제한

- 다층적 방어(Depth) 고려 사항: DDoS, 악용, 스크래핑

- 공용 IP가 누구로부터든 연결을 수락해야 함

출력(Egress) 트래픽 특성:

- 자체 서비스(알려진 소수의 클라이언트)에 의해 시작됨

- 서비스 간 호출 및 외부 API 호출 패턴에 따라 트래픽 양이 확장됨

- 원격 엔드포인트에서의 소스 IP 허용 목록 설정(파트너가 신뢰하는 고정된 아웃바운드 IP가 하나 있음)

- 다중 방어(Defense-in-depth) 고려 사항: 데이터 유출, 외부로 호출하는 손상된 내부 서비스

- 자체 서비스가 아닌 모든 연결을 거부해야 함

주요 비대칭성: 인그레스(Ingress)는 전 세계의 트래픽을 허용하는 반면, 에그레스(Egress)는 자체 서비스의 트래픽만 허용합니다. 이를 동일한 머신에 배치하면 해당 머신은 동시에 전 세계에서 접근 가능해야 하고(인그레스를 위해), 또한 자체 서비스로부터만 접근 가능해야 합니다(에그레스를 위해). 한쪽을 만족시키는 방화벽 규칙은 다른 쪽에 방해가 됩니다.

성장 경로: 작은 프로젝트는 트래픽 양이 적고 파트너 IP 허용 목록이 짧아 두 역할을 하나의 IP와 하나의 도구 뒤에 숨길 수 있습니다. 프로젝트가 성장함에 따라 두 역할 간의 마찰이 증가하며, 결국 특정 실패 모드(헤어핀 NAT)가 분리를 강제하게 됩니다.

인그레스와 에그레스: 다른 소스, 다른 대상, 다른 요구 사항

어떤 스타트업은 단일 VM에 단일 공개 IP를 사용하여 모든 것(인그레스 리버스 프록시, 에그레스 포워드 프록시 / NAT, 내부 서비스)을 실행하고 있습니다. 초기 단계이므로 이 방식이 괜찮아 보입니다. 이 회사가 성장함에 따라 이 설계가 겪게 될 두 가지 구체적인 실패 모드 또는 운영상의 문제를 명시하고, 각각에 대해 근본적인 원인을 설명하십시오.

분리를 강제하는 버그

정제된 장애 사례

프로덕션 환경에서 실제로 발생하는 아키텍처적 갈림길을 상상해 보세요. 아래에 언급된 이름들은 변경되었지만, 그 구조는 현장에서 팀들이 직면하는 상황과 동일합니다.

한 조직은 203.0.113.5에 단일 프록시 서버를 운영합니다. 이 서버는 인그레스(사용자를 위한 포트 443)와 에그레스(외부 호출을 위한 내부 서비스용 포트 1080 SOCKS5)를 처리합니다. 내부 서비스들은 프라이빗 서브넷에 위치하며, 모든 아웃바운드 트래픽을 203.0.113.5:1080의 해당 SOCKS5 프록시를 통해 라우팅합니다.

같은 203.0.113.5 뒤에 호스팅되는 서비스 중 하나는 api.example.com입니다. 공개 DNS는 api.example.com을 203.0.113.5로 해석합니다.

이제 다른 내부 서비스가 api.example.com을 호출해야 합니다. 해당 서비스의 아웃바운드 경로는 다음과 같습니다:

1. 내부 서비스가 api.example.com을 203.0.113.5로 해석합니다

2. 내부 서비스가 203.0.113.5:1080의 SOCKS5 에그레스 프록시를 통해 요청을 전송합니다

3. 프록시가 자기 자신에서 203.0.113.5:443으로 연결을 열려고 시도합니다

4. 연결 거부(Connection refused). 패킷은 동일한 NAT를 빠져나와 다시 진입해야 하므로, 대부분의 네트워크 스택은 이를 거부합니다. 프록시는 자신의 공개 IP를 통해 자신과 연결할 수 없습니다.

이것이 헤어핀 NAT(Hairpin NAT)입니다: NAT를 빠져나와 동일한 NAT를 다시 진입해야만 목적지에 도달할 수 있는 패킷을 말합니다. 라우팅 계층에 특별한 헤어핀 지원이 없으면 패킷이 드롭됩니다.

왜 늦게 드러나는가

프로젝트 초기에는 모든 내부 서비스가 다른 내부 서비스와 사설 호스트네임(internal-api.local)으로 통신하거나, 자체 조직의 공개 서비스로 콜백을 수행하지 않았습니다. 헤어핀 경로는 단순히 존재하지 않았습니다.

그런데 새로운 기능이 서비스 A가 api.example.com(공개 호스트네임)을 호출하도록 요구했습니다. 헤어핀 경로가 활성화되었습니다. 연결 거부. 장애 발생.

해결책은 증상을 패치했습니다(api.example.com의 공개 IP 대신 사설 IP를 리졸버가 반환하도록 강제). 근본 원인: 단일 머신이 너무 많은 역할을 수행하고 있었습니다.

Hairpin NAT: packet exits & cannot re-enter the same NAT

아키텍처의 갈림길

하나의 박스가 둘로

깔끔한 해결책: 프록시를 두 대의 서버로 분리합니다.

Ingress 서버(공개 IP 203.0.113.5):

- 포트 80, 443에서 Caddy / 리버스 프록시

- 공개 DNS 레코드가 여기로 가리킴

- api.example.com, app.example.com 등을 호스팅

Egress 서버(다른 공개 IP 203.0.113.99):

- 포트 1080에서 SOCKS5 / 포워드 프록시

- 방화벽은 내부 서브넷 IP로의 incoming 연결만 허용합니다

- 내부 서비스는 모든 outbound 트래픽을 이 주소를 통해 라우팅합니다

이로 인해 얻는 것:

1. Hairpin 문제 해결. 내부 서비스가 api.example.com을 호출하면, outbound 트래픽은 203.0.113.99(egress)를 통해 라우팅된 후 203.0.113.5(ingress, 다른 IP)로 정상적으로 연결됩니다. 두 IP가 서로 다른 머신에 존재하므로 NAT 루프가 사라집니다.

2. 보안 격리. Egress 서버의 방화벽은 소수의 내부 IP로만 제한할 수 있습니다. Ingress 서버의 방화벽은 대외적으로 열려 있습니다. 두 개의 독립적인 규칙 집합이 각각 하나의 역할을 명확하게 표현합니다.

3. 독립적인 확장성. Ingress 대역폭은 사용자 수에 따라, egress 대역폭은 내부 서비스 활동에 따라 확장됩니다. 한쪽을 업그레이드하되 다른 쪽에는 영향을 주지 않습니다.

4. 장애 격리. 잘못 구성된 egress가 더 이상 공개 사이트를 깨뜨리지 않습니다. 공개 사이트 대상 DDoS 공격이 더 이상 egress 대역폭을 고갈시키지 않습니다.

5. 명확한 멘탈 모델. 각 머신은 하나의 역할만 수행합니다. 엔지니어는 egress를 생각하지 않고 ingress 문제를, 반대로 ingress를 생각하지 않고 egress 문제를 추론할 수 있습니다.

분리(split) 이후에도 내부 서비스는 여전히 `api.example.com`을 호출해야 합니다. 내부 서비스에서 API 백엔드까지의 새로운 패킷 경로를 단계별로 설명해 주세요. 다음을 포함해야 합니다: 내부 서비스가 처음 연결하는 IP, 해당 머신이 요청을 어떻게 처리하는지, 다음으로 어떤 IP로 보내는지, 그리고 응답이 어디로 가는지.

두 개의 축, 두 가지 크기 결정

독립적 확장성

분리 이전에는 어느 방향으로든 트래픽이 증가하면 동일한 머신에 부하가 걸렸습니다. 분리 이후에는 각 방향별로 자체 프로비저닝이 가능합니다.

인그레스 크기 설정: 사용자 수에 따라 확장됩니다. 용량 결정은 공개된 최상위 계층(더 많은 리버스 프록시 레플리카, 더 큰 VM, 앞단에 CDN 배치)에서 이루어집니다. 피크 시점의 사용자 트래픽을 기준으로 대역폭 예산이 계산됩니다.

에그레스 크기 설정: 내부 서비스에서 외부 API로 호출하는 볼륨에 따라 확장됩니다. 일반적으로 웹훅 전달, 결제 프로세서 호출, 또는 제3자 데이터 가져오기가 주요 요인입니다. 내부 호출 패턴을 기준으로 대역폭 예산이 계산됩니다.

장애 격리: 공개 인그레스에 대한 DDoS 공격이 더 이상 에그레스 대역폭을 소진하지 않습니다(결제 프로세서 호출은 그대로 통과하므로). 에그레스 프록시 충돌이 더 이상 공개 사이트를 다운시키지 않습니다(사용자는 여전히 사이트에 접근할 수 있으며, 내부 발신 호출만 실패합니다).

서로 다른 SLO: 인그레스 가용성은 사용자에게 중요합니다(가시적인 사이트 장애). 에그레스 가용성은 운영자에게 중요합니다(발견에 시간이 더 걸릴 수 있는 백그라운드 장애). 각 측면은 자체 SLO를 가질 수 있습니다.

다중 에그레스 서버

에그레스 역할이 자체 머신이 되면, 다음으로 자연스러운 단계는 HA를 위해 로드 밸런서 뒤에 여러 대의 에그레스 머신을 실행하는 것입니다. 각 새로운 내부 서비스는 단일 IP가 아닌 에그레스 호스트네임(로드 밸런싱 풀로 해석됨)을 가리키도록 설정됩니다.

분산 시스템의 나머지 부분과 동일한 교훈입니다: 한 계층이 무상태(stateless)가 되고 고유한 역할을 가지면, 저렴하게 복제할 수 있습니다.

새로운 파트너 통합

귀하의 조직은 설계대로 ingress / egress 분리를 실행하고 있습니다. egress 서버에는 고정된 공용 IP(203.0.113.99)가 있으며, 이 IP는 세 개의 기존 파트너 API(결제 프로세서, SMS 게이트웨이, 이메일 제공업체)에 허용 목록(allowlist)으로 등록되어 있습니다.

제품 팀이 네 번째 통합을 추가하기를 원합니다: 전 세계 고객 엔드포인트로 콜백하는 웹훅(webhook) 전달 시스템입니다. 예상 트래픽: 분당 10,000회 호출, 최대 30,000회까지의 버스트(burst) 발생.

판단하세요: 이 새로운 통합은 기존 egress 서버에 속하는지, 아니면 별도의 egress 경로가 필요한지? 대역폭, 장애 격리, 그리고 어떤 경우에도 기존 파트너 허용 목록이 업데이트되어야 하는지 추론해 보세요.

성장하는 서비스를 위한 네트워크 경계 설계

종합

여러분은 왜 입구(ingress)와 출구(egress)에 서로 다른 도구가 필요한지, 실제 환경에서 분리를 강제하는 헤어핀 NAT 장애가 무엇인지, 그리고 분리가 완료된 후 독립적 확장성, 보안 격리, 장애 격리가 어떻게 확보되는지를 학습했습니다.

네 가지 원칙을 모두 적용해 보세요.

중소형 SaaS 기업은 사용자를 위해 세 개의 제품 서브도메인(app, api, admin)과 네 개의 외부 통합 서비스(Stripe, Twilio, SendGrid, 고객 웹훅 시스템)를 운영합니다. 현재 모든 트래픽은 하나의 공개 IP 주소 뒤에 있는 단일 프록시 머신을 통해 처리되고 있습니다. 내부 서비스가 api.example.com을 호출할 때 간헐적인 헤어핀 장애가 발생하는 보고가 접수되기 시작했습니다. 그들은 영구적인 해결책을 설계하고자 합니다.

이 회사를 위한 입구/출구(ingress/egress) 아키텍처를 제안하세요. 다음 사항들을 다루세요: 몇 대의 머신이 필요한지, 어떤 IP가 어떤 역할을 담당하는지, 각 서브도메인의 DNS가 어디를 가리키는지, 어떤 아웃바운드 통합(outbound integrations)이 출구 경로를 공유하는지(그리고 어떤 것이 분리되어야 하는지), 그리고 새로운 설계가 이전 설계에서는 가능하지 않았던 구체적인 모니터링 관심사 하나를 어떻게 활성화하는지.

이 과정의 다음 단계

이 과정의 다음 단계

분산 시스템에서 가장 깔끔한 관심사 분리(separation-of-concerns) 리팩터링 중 하나를 확인했습니다: 하나의 박스가 두 개로 나뉘어 각각 명확한 역할을 가지게 되었고, 시스템은 그 과정에서 확장성, 보안, 장애 격리 이점을 함께 상속받게 되었습니다.

다음 레슨(cs_distsys_failure_modes_and_blast_radius)은 장애 격리 추론을 확장합니다. 정제된 DNS-SERVFAIL 사후 분석 보고서를 읽고, 연쇄 장애 패턴을 식별하며, 사람을 지목하는 것이 아니라 시스템을 대상으로 한 무과실(blameless) 액션 아이템을 작성하게 됩니다.

동반 레슨: geometry_of_ingress_egress_separation는 이 분리를 이분 그래프로 재구성하고, 절단 꼭짓점(cut vertices), 네트워크 분할, 그리고 네트워크 경계에 대한 그래프 이론의 시사점을 탐구합니다.

잘하셨습니다. 다음으로 나아가시죠.