[태그:] 마이크로서비스

  • TCP/IP 그 이후의 이야기

    웹 아키텍처와 트래픽의 흐름, 그리고 프로토콜의 진화

    1. 트래픽의 관문 : 로브밸런서와 리버스 프록시

    사용자가 많아지면 서버 한 대로는 밀려드는 트래픽을 감당할 수 없다.
    이때 서버를 여러 대 두고 트래픽을 골고루 나눠주는 기술이 바로 로드밸런싱(Load Balancing)이다. 이 분산 작업을 네트워크의 어느 계층에서 하느냐에 따라 전략이 달라진다.

    L4 로드밸런서 (전송 계층)

    먼저 쓴 글처럼 TCP/UDP 포트 정보IP 주소만을 보고 트래픽을 분산한다. 데이터의 내용(HTTP 헤더 등)은 까보지 않기 때문에 처리 속도가 매우 빠르고 효율적이다. 단순히 “80번 포트로 들어온 요청이니까 A서버, B서버로 번갈아 가며 보내야지”라고 판단한다.

    L7 로드밸런서 (응용 계층)

    L7 로드밸런서는 패킷을 열어 HTTP URI, 헤더, 쿠키 정보까지 분석하여 트래픽을 분배한니다. 대표적인 예로 Nginx나 HAProxy가 있다. 서버 아키텍처를 기능별로 쪼개는 마이크로서비스 환경에서 특히 잘 사용된다.

    Nginx
    # Nginx를 활용한 L7 라우팅 예시
    server {
        listen 80;
    
        # /api/users 경로로 오면 인증 서버로
        location /api/users {
            proxy_pass http://auth_servers;
        }
    
        # /api/process 경로로 오면 데이터 처리 서버로
        location /api/process {
            proxy_pass http://processing_servers;
        }
    }

    위와 같이 클라이언트가 요청한 URL 경로(Path)에 따라 트래픽을 완전히 다른 백엔드 서버 그룹으로 찢어줄 수 있다. 백엔드 앞단에 서서 트래픽을 대신 받아주고 분배하는 이러한 Nginx의 역할을 리버스 프록시(Reverse Proxy)라고 부른다.

    2. 서버 내부의 통신 : Nginx 부터 프레임우크까지

    리버스 프록시를 통과한 HTTP 요청은 이제 애플리케이션 서버에 도착했다. 하지만 파이썬, 자바, Node.js 같은 프로그래밍 언어는 HTTP 통신 규약을 날것 그대로 이해하지 못한다. 중간에서 누군가 번역을 해줘야 한다.

    예를 들어, 클라이언트가 애플리케이션에 이미지를 업로드하고 이미지 내 텍스트를 추출(OCR)해 달라는 RESTful API 요청을 보냈다고 가정해 보자. 이 요청이 처리되는 파이프라인은 다음과 같다.

    웹 서버 (Web Server)

    가장 앞단에서 클라이언트를 맞이하는 Nginx나 Apache다. 정적 파일(HTML, CSS, 이미지)은 여기서 바로 반환하여 처리 속도를 높이고, 동적 처리가 필요한 API 요청만 뒤로 넘겨준다.

    WAS / 인터페이스 (WSGI/ASGI)

    웹 서버와 비즈니스 로직 사이를 연결한다. Python의 경우 Uvicorn이나 Gunicorn이 이 역할을 한다. 웹 서버로부터 받은 HTTP 요청을 프로그래밍 언어가 이해할 수 있는 딕셔너리나 객체 형태로 변환하여 넘겨준다.

    웹 프레임워크 (Application)

    데이터가 FastAPI, Spring Boot, Express 같은 프레임워크에 도착하면 여기서 라우팅 처리, 데이터베이스 조회, 복잡한 비즈니스 로직(이미지 처리 파이프라인 가동 등)이 수행된 후, 다시 역순을 거쳐 클라이언트에게 JSON 응답이 돌아간다.

    Plaintext
    [클라이언트] → [Nginx (웹 서버)] → [Uvicorn (ASGI 서버)] → [FastAPI (애플리케이션)]

    이 구조를 이해하면, 트래픽이 몰려 장애가 발생했을 때 Nginx의 커넥션 문제인지, 애플리케이션의 로직 병목인지 계층별로 나누어 진단할 수 있게 된다.

    3. 프로토콜의 미래: HTTP/3와 UDP의 재발견

    웹 생태계는 계속해서 더 빠르고 안정적인 통신을 원한다. 먼저 쓴 글에는 TCP가 ‘신뢰성’, UDP는 ‘속도’의 상징이라고 작성했다. 그래서 수십 년간 웹의 표준(HTTP/1.1, HTTP/2)은 TCP 위에서 돌아갔다.

    하지만 최근 구글, 메타 등 빅테크 기업을 중심으로 도입되고 있는 HTTP/3는 놀랍게도 TCP를 버리고 UDP 기반의 QUIC 프로토콜을 채택했다. 왜일까?

    TCP의 한계: HOL Blocking (Head-of-Line Blocking)

    TCP는 데이터가 반드시 ‘순서대로’ 도착해야 함을 보장한다. 만약 1, 2, 3번 패킷을 보냈는데 중간에 2번 패킷이 유실되면, 목적지에서는 2번 패킷을 다시 받을 때까지 무작정 기다려야 한다. 그 뒤에 도착한 3번 패킷은 죄 없이 대기해야 하는데 이를 HOL Blocking이라고 한다.

    QUIC: UDP에 신뢰성을 얹다

    초고속 모바일 시대에는 이 대기 시간이 너무 느리게 느껴진다. 그래서 엔지니어들은 과감한 결정을 한다. “운영체제(OS) 깊숙이 박혀있어 수정하기 힘든 TCP 대신, 텅 비어있는 UDP를 가져와서 애플리케이션 레벨에서 우리만의 새로운 신뢰성 제어 로직을 만들자!”

    • 빠른 연결: TCP의 3-way Handshake와 TLS(보안) Handshake를 하나로 합쳐 연결 시간을 극적으로 단축했다.
    • 독립적 스트림: 각 데이터 스트림을 독립적으로 처리하여, 사진 A의 패킷이 손실되더라도 사진 B의 패킷은 대기 없이 바로 렌더링되게 만들었다.

    결국 HTTP/3의 등장은, 앞서 다루었던 프로토콜의 특성들을 정확히 이해하고 있을 때 왜 이런 기술적 전환이 일어났는지 그 맥락을 완벽하게 파악할 수 있게 해 줍니다.

    마치며: 아키텍처의 퍼즐 맞추기

    1. L4/L7 로드밸런서는 각 계층의 정보를 활용해 트래픽을 효율적으로 분산한다.
    2. 서버에 도착한 데이터는 웹 서버 → 인터페이스(WAS) → 애플리케이션(프레임워크) 이라는 유기적인 파이프라인을 거쳐 처리된다.
    3. 웹 생태계는 TCP의 한계를 극복하기 위해 UDP 기반의 HTTP/3(QUIC)라는 새로운 혁신을 만들어내고 있다.

    하위 계층의 패킷 전달부터 상위 계층의 아키텍처 구조까지, 네트워크는 하나로 촘촘하게 이어져 있다. 당장 코드를 짜는 데 급급하기보다 데이터가 흘러가는 전체 파이프라인의 그림을 머릿속에 그릴 수 있다면, 더 견고하고 유연한 서비스를 설계하는 훌륭한 백엔드 개발자로 성장하실 수 있을 것이다.