응용 계층을 설계할 때: 프로세스·소켓·전송 프로토콜 선택

반응형

컴퓨터 네트워크의 응용 계층을 처음 공부할 때 client-server, P2P, socket, TCP, UDP, HTTP를 한꺼번에 정리했다. 개념 목록으로만 보면 각각이 따로 노는 것처럼 보인다. 실제로는 application process가 다른 host의 process와 통신하기 위해 무엇을 정해야 하는지에 대한 연속된 선택이다.

application의 요구사항
        ↓
통신 구조와 protocol 설계
        ↓
socket API로 transport service 사용
        ↓
TCP·UDP·QUIC 등이 packet을 전달

이 글은 application layer의 역할과 transport 선택 기준을 이 흐름에 맞춰 다시 정리한 학습 노트다.

응용 계층은 사용자에게 가까운 protocol을 정의한다

응용 계층 protocol은 서로 통신하는 application이 이해할 message의 의미와 규칙을 정한다.

예를 들어 HTTP는 request method, target, header field, response status와 content 같은 의미를 정의한다. SMTP는 mail을 전달하기 위한 command와 reply를 정의한다. DNS는 name과 resource record를 질의하고 응답하는 형식을 정의한다.

application protocol을 설계할 때는 최소한 다음을 정해야 한다.

  • 어떤 message type이 있는가
  • message의 field와 encoding은 무엇인가
  • client와 server가 어떤 순서로 message를 주고받는가
  • timeout, retry, duplicate를 어떻게 처리하는가
  • 인증·권한·기밀성·무결성을 어디에서 보장하는가
  • version과 호환성을 어떻게 표현하는가

transport가 byte나 datagram을 전달해 주더라도 message의 업무 의미까지 결정해 주지는 않는다.

client와 server는 장치 종류가 아니라 역할이다

client는 보통 통신을 시작하고, server는 잘 알려진 address에서 요청을 기다린다. 하지만 한 장치가 영원히 client이거나 server인 것은 아니다.

web browser는 web server에 HTTP request를 보낼 때 client다. 같은 browser가 local extension이나 다른 process에 service를 제공하는 순간에는 server 역할을 할 수도 있다. 역할은 특정 통신과 protocol 안에서 정해진다.

client-server 구조에서는 대개 service가 지속적으로 도달 가능한 endpoint를 제공한다.

client A ─┐
client B ─┼─→ server
client C ─┘

장점은 data와 policy를 한곳에서 관리하기 쉽다는 점이다. 대신 traffic이 집중되므로 scale-out, load balancing, failure handling이 필요하다.

P2P도 중앙 요소가 전혀 없는 것은 아니다

peer-to-peer 구조에서는 참여 node가 resource를 요청하면서 동시에 제공할 수 있다.

peer A ↔ peer B
  ↕         ↕
peer C ↔ peer D

“항상 켜진 중앙 server가 없다”는 설명은 순수한 model을 이해하는 데는 도움이 되지만, 실제 P2P system 전체를 그대로 설명하지는 못한다. peer discovery, rendezvous, identity, NAT traversal, metadata 배포를 위해 중앙 service를 함께 쓰는 hybrid 구조가 흔하다.

따라서 client-server와 P2P는 둘 중 하나만 고르는 label이 아니라 다음 trade-off를 판단하는 출발점이다.

  • 상태와 authority를 어디에 둘 것인가
  • 참여 node가 얼마나 자주 연결되고 끊기는가
  • peer를 어떻게 발견하고 신뢰할 것인가
  • NAT와 firewall을 어떻게 통과할 것인가
  • data consistency와 abuse control을 누가 담당하는가

P2P의 구체적인 distribution 방식은 P2P 파일 분배 구조에서 이어서 정리했다.

process를 찾으려면 network address와 endpoint가 필요하다

network 통신의 실제 주체는 program 안에서 실행되는 process다. remote process에 도달하려면 보통 IP address와 transport protocol의 port number가 필요하다.

host를 찾는 단서        IP address
host 안의 endpoint 구분  transport protocol + port

한 host가 언제나 하나의 고유한 32-bit IPv4 address를 가진다고 말할 수는 없다. 한 장비에 address가 여러 개일 수 있고, IPv6를 사용할 수 있으며, NAT 뒤의 private address와 외부에서 보이는 address가 다를 수도 있다.

TCP connection은 일반적으로 다음 값의 조합으로 구분한다.

protocol,
source IP, source port,
destination IP, destination port

같은 server port에도 여러 client가 동시에 연결될 수 있는 이유다.

socket은 application과 transport 사이의 API 경계다

socket은 application process가 operating system의 networking 기능을 사용하는 interface다. application은 socket API를 통해 connection을 만들거나 datagram을 보내고 받는다.

application process
      ↕ socket API
operating system transport/network stack
      ↕ network interface
network

TCP server의 전형적인 흐름은 socket → bind → listen → accept → read/write다. TCP client는 socket → connect → read/write로 이어진다. UDP는 connection setup 없이 sendtorecvfrom 형태로 datagram을 주고받을 수 있다.

Python의 작은 TCP·UDP 예제는 socket programming 기록에 별도로 남겨 두었다.

socket이 message boundary를 항상 보존한다고 생각해서는 안 된다. TCP는 ordered byte stream이다. application이 send() 한 번 호출한 단위와 receiver의 recv() 한 번 결과가 일치한다는 보장이 없다. application protocol이 length prefix, delimiter, fixed length 같은 framing을 정해야 한다.

application이 transport에 요구하는 것

transport 선택은 protocol 이름부터 고르는 일이 아니다. application이 무엇을 잃어도 되는지, 얼마만큼 기다릴 수 있는지부터 적어야 한다.

질문 확인할 내용
신뢰성 loss·duplicate·reordering을 허용하는가
순서 모든 data가 전송 순서대로 도착해야 하는가
지연 deadline을 넘긴 data도 가치가 있는가
처리량 최소 throughput이 필요한가, 변화해도 적응 가능한가
message 경계 byte stream인가, datagram인가
연결 비용 handshake와 connection migration이 중요한가
보안 인증·기밀성·무결성을 어떻게 제공할 것인가

“data integrity가 중요하면 TCP, 속도가 중요하면 UDP”라는 한 줄 규칙만으로는 부족하다. TCP도 application latency나 최소 throughput을 보장하지 않고, UDP도 자동으로 빠른 결과를 보장하지 않는다. congestion, path quality, protocol 설계와 구현이 함께 결과를 만든다.

TCP: 신뢰할 수 있는 ordered byte stream

TCP는 두 endpoint 사이에 connection을 만들고, application에 ordered and reliable byte stream을 제공한다. sequence number, acknowledgment, retransmission과 flow control 등을 사용한다.

적합한 출발점은 다음과 같다.

  • byte가 빠지거나 순서가 바뀌면 안 된다.
  • application에서 loss recovery를 직접 설계하고 싶지 않다.
  • stream semantics가 잘 맞는다.

하지만 TCP가 보장하지 않는 것도 있다.

  • 일정한 latency
  • 일정한 최소 bandwidth
  • application message boundary
  • application-level transaction의 exactly-once 처리
  • 암호화와 peer identity 자체

TLS를 TCP 위에 사용하면 기밀성·무결성과 peer authentication을 더할 수 있다. 그래도 retry가 중복 업무 처리를 만들 수 있으므로 application-level idempotency는 따로 설계해야 한다.

UDP: 최소한의 datagram service

UDP는 connection establishment 없이 datagram을 전달한다. protocol 자체는 delivery, ordering, duplicate suppression을 보장하지 않는다. checksum으로 전송 중 손상을 탐지하는 기능은 있지만, 손실된 datagram을 재전송하지는 않는다.

적합할 수 있는 경우는 다음과 같다.

  • 늦게 도착한 data보다 새 data가 더 중요하다.
  • message boundary를 그대로 유지하고 싶다.
  • application이 loss·reordering·rate control을 직접 다룰 수 있다.
  • multicast 같은 UDP semantics가 필요하다.

UDP를 쓴다고 congestion control을 무시해도 되는 것은 아니다. RFC 8085는 UDP application이 congestion collapse를 피하도록 rate control, message size, loss 처리 등을 고려할 것을 요구한다.

QUIC: UDP 위에서 제공하는 secure multiplexed transport

현대적인 선택지에는 QUIC도 있다. QUIC는 UDP datagram 위에서 동작하지만 application에 secure connection과 여러 ordered stream을 제공한다. TLS handshake를 protocol에 통합하고, stream 사이의 application-level head-of-line blocking을 줄이며, connection migration을 지원하도록 설계됐다.

HTTP/3가 QUIC를 사용한다. 그렇다고 모든 application이 직접 QUIC를 구현해야 한다는 뜻은 아니다. 사용할 library와 platform support, operational visibility, middlebox 환경을 함께 봐야 한다.

transport application에 보이는 기본 형태 delivery·순서 보안
TCP byte stream reliable, ordered TLS 별도 조합
UDP datagram 보장하지 않음 application protocol이 결정
QUIC 여러 독립 stream 각 stream 안에서 reliable·ordered TLS 1.3 통합

HTTP를 예로 전체 흐름을 연결한다

browser가 HTTPS URL을 연다고 생각해 보자.

1. DNS로 host name에 대응하는 address를 찾는다.
2. TCP+TLS 또는 QUIC connection을 준비한다.
3. HTTP request message를 보낸다.
4. server process가 socket을 통해 request를 받는다.
5. HTTP response를 같은 protocol의 규칙으로 돌려준다.

DNS, transport, TLS, HTTP는 서로 다른 책임을 갖는다. “웹이 안 된다”는 같은 증상도 어느 단계가 실패했는지에 따라 진단 방법이 달라진다.

HTTP message와 connection semantics는 HTTP request와 response, mail protocol의 역할은 SMTP·POP3·IMAP에서 더 자세히 이어진다.

설계 전에 적어 볼 체크리스트

  1. communication을 시작하는 역할과 지속적으로 기다리는 역할은 누구인가?
  2. endpoint를 어떻게 발견하고 address가 바뀌면 어떻게 갱신하는가?
  3. message framing과 maximum size는 무엇인가?
  4. loss, duplicate, reordering과 retry를 어느 계층에서 처리하는가?
  5. timeout 뒤 결과가 늦게 도착하면 어떻게 처리하는가?
  6. authentication과 encryption은 어느 protocol이 담당하는가?
  7. connection과 request를 관측하기 위한 metric·log·trace는 무엇인가?
  8. version이 다른 peer가 만났을 때 어떻게 호환되는가?

응용 계층은 단순히 OSI model의 맨 위 칸이 아니다. 사용자에게 의미 있는 message를 정의하고, 아래 transport가 제공하는 service와 제공하지 않는 보장을 정확히 이해해 이어 붙이는 곳이다. protocol을 선택할 때 이 경계를 먼저 그리면 TCP와 UDP를 속도 비교 하나로 판단하는 실수를 줄일 수 있다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글