왜 계층이 필요한가
1장에서 우리는 인터넷이 전 세계를 연결하는 거대한 네트워크이며, 데이터는 패킷이라는 단위로 쪼개져 전달된다는 것을 확인했습니다.
그런데 잠시 생각해 보면, 이게 정말 복잡한 일이라는 걸 알 수 있습니다. 전기 신호를 비트로 변환하고, 그 비트들을 프레임으로 묶고, 프레임에 목적지 주소를 붙이고, 경로를 결정하고, 중간에 손실된 데이터를 재전송하고, 마지막으로 애플리케이션이 이해할 수 있는 형태로 해석해야 합니다.
이 모든 과정을 하나의 거대한 프로토콜로 처리하려고 하면 어떻게 될까요?
모놀리식 통신의 문제점
만약 네트워크 통신을 하나의 프로토콜이 전부 담당한다고 가정해 봅시다. 비트를 전기 신호로 변환하는 것부터, IP 주소를 기반으로 경로를 결정하는 것, 손실된 데이터를 재전송하는 것, HTTP 요청을 파싱하는 것까지 모두 하나의 거대한 규격 안에 들어 있습니다.
이런 구조에서는 어떤 문제가 생길까요?
유선 이더넷 대신 Wi-Fi를 사용하고 싶다면, 프로토콜 전체를 새로 정의해야 합니다. 물리적 전송 방식만 바꾸면 되는 일인데, 그것이 경로 결정이나 데이터 재전송 로직과 한 덩어리로 묶여 있기 때문에 부분 교체가 불가능합니다.
모놀리식 구조의 문제
┌───────────────────────────────────────┐
│ 전기 신호 변환 + 주소 지정 + 경로 결정│
│ + 재전송 + 암호화 + HTTP 파싱 │
│ 전부 한 덩어리! │
└───────────────────────────────────────┘
Wi-Fi로 바꾸려면? → 전체를 다시 만들어야!
암호화 알고리즘 바꾸려면? → 역시 전체를 다시!
계층화 구조
┌────────────────┐
│ HTTP 파싱 │ ← 이 계층만 수정
├────────────────┤
│ 재전송/순서 │ ← 독립
├────────────────┤
│ 경로 결정 │ ← 독립
├────────────────┤
│ 전기 신호 변환 │ ← Wi-Fi로만 교체하면 됨
└────────────────┘소프트웨어 공학에서 이런 구조를 모놀리식(Monolithic)이라고 부릅니다. 하나의 거대한 덩어리가 모든 책임을 지는 구조입니다. 그리고 소프트웨어 엔지니어링이 그랬듯, 네트워크도 이 문제를 계층화(Layering)로 해결했습니다.
계층화의 장점
계층화란 전체 통신 과정을 역할별로 나누어 독립적인 계층으로 분리하는 것입니다. 각 계층은 자기 역할에만 집중하고, 다른 계층의 내부 동작에는 관여하지 않습니다.
모듈성(Modularity): 각 계층은 독립적으로 설계하고 구현할 수 있습니다. 물리 계층을 설계하는 엔지니어가 HTTP 스펙을 알 필요가 없고, 웹 개발자가 전기 신호의 변조 방식을 이해할 필요가 없습니다.
대체 가능성(Replaceability): 특정 계층만 교체할 수 있습니다. 이더넷 대신 Wi-Fi로 바꿔도, 그 위의 IP 계층이나 TCP 계층은 아무것도 수정할 필요가 없습니다.
표준화(Standardization): 각 계층별로 명확한 인터페이스를 정의하면, 서로 다른 제조사의 장비와 소프트웨어가 호환됩니다.
"""
계층화는 프로그래밍의 추상화와 동일한 원리입니다.
"""
class PhysicalLayer:
"""물리 계층: 비트를 전기 신호로 변환"""
def send(self, bits):
print(f"[물리] {len(bits)} 비트를 전기 신호로 전송")
class DataLinkLayer:
"""데이터 링크 계층: MAC 주소로 로컬 전달"""
def __init__(self, physical):
self.physical = physical
def send(self, frame, dst_mac):
print(f"[데이터링크] MAC {dst_mac}로 프레임 전송")
self.physical.send(frame) # 하위 계층은 어떻게 전송하든 상관없음
class NetworkLayer:
"""네트워크 계층: IP 주소로 경로 결정"""
def __init__(self, datalink):
self.datalink = datalink
def send(self, packet, dst_ip):
# IP 계층은 물리 매체가 이더넷이든 Wi-Fi든 상관 안 함
next_hop_mac = self.resolve_mac(dst_ip)
print(f"[네트워크] IP {dst_ip}로 패킷 전송")
self.datalink.send(packet, next_hop_mac)
def resolve_mac(self, ip):
return "AA:BB:CC:DD:EE:FF" # ARP가 해결
# 이더넷 → Wi-Fi로 바꿔도 NetworkLayer 코드는 수정 불필요
phy = PhysicalLayer()
dl = DataLinkLayer(phy)
net = NetworkLayer(dl)
net.send(b"Hello", "10.0.0.1")이 예시에서 NetworkLayer는 DataLinkLayer가 이더넷인지 Wi-Fi인지 모릅니다. 오직 send(frame, mac) 인터페이스만 알면 됩니다. 이것이 계층화의 핵심입니다.
소프트웨어 설계와의 연결
프로그래머라면 계층화가 이미 익숙할 것입니다. 소프트웨어 아키텍처에서 같은 원리를 매일 사용하고 있기 때문입니다.
| 네트워크 계층화 | 소프트웨어 아키텍처 |
|---|---|
| 응용 계층 | Presentation Layer (UI) |
| 전송 계층 | Service Layer (비즈니스 로직) |
| 네트워크 계층 | Repository Layer (데이터 접근) |
| 물리 계층 | Database Driver (실제 저장소) |
웹 프레임워크에서 Controller → Service → Repository → Database 구조를 만드는 이유도 같습니다. 데이터베이스를 MySQL에서 PostgreSQL로 바꿔도 Service 코드는 수정 불필요합니다. 네트워크에서 이더넷을 Wi-Fi로 바꿔도 TCP 코드가 수정 불필요한 것과 동일합니다.
편지 보내기 비유로 계층 이해하기
계층의 동작을 직관적으로 이해하기 위해, 회사에서 다른 회사로 공식 문서를 보내는 과정을 생각해 봅시다.
[회사 A] [회사 B]
┌──────────┐ 논리적 통신 ┌───────────┐
│ 작성자 │ ←─────────────→ │ 수신자 │ 응용 계층
├──────────┤ ├───────────┤
│ 비서 │ ←─────────────→ │ 비서 │ 전송 계층
├──────────┤ ├───────────┤
│ 우편실 │ ←─────────────→ │ 우편실 │ 네트워크 계층
├──────────┤ ├───────────┤
│ 택배기사 │ ══ 물리적 운반 ══ │ 택배기사 │ 물리 계층
└──────────┘ └───────────┘작성자가 문서의 내용을 작성합니다. 이것은 애플리케이션 계층에 해당합니다.
비서가 문서를 봉투에 넣고, 받는 사람과 보내는 사람의 정보를 적습니다. 이것은 전송 계층입니다.
우편실에서 봉투에 우편번호와 주소를 적고, 우체국으로 보냅니다. 이것은 네트워크 계층입니다.
택배 기사가 트럭에 실어 물리적으로 운반합니다. 이것은 물리 계층입니다.
중요한 것은, 각 단계의 사람이 다른 단계의 세부 사항을 몰라도 전체 시스템이 정상적으로 동작한다는 점입니다. 작성자가 트럭의 배송 경로를 알 필요 없고, 택배 기사가 문서의 내용을 읽을 필요 없습니다.
또 하나 주목할 점은 피어 간 논리적 통신입니다. 회사 A의 작성자와 회사 B의 수신자는 마치 직접 대화하는 것처럼 느끼지만, 실제로는 여러 계층을 거쳐 물리적으로 전달됩니다. 네트워크에서도 마찬가지입니다. 브라우저의 HTTP 모듈은 서버의 HTTP 모듈과 직접 통신하는 것처럼 동작하지만, 실제로는 중간에 TCP, IP, 이더넷 계층을 모두 거칩니다.
계층 간 서비스와 인터페이스
각 계층은 상위 계층에 서비스를 제공하고, 하위 계층의 서비스를 사용합니다. 이 관계를 명확히 이해하는 것이 중요합니다.
| 관계 | 설명 | 예시 |
|---|---|---|
| 서비스 제공 | 하위 → 상위 | IP가 TCP에게 패킷 전달 서비스 제공 |
| 서비스 사용 | 상위 → 하위 | TCP가 IP의 패킷 전달 서비스 사용 |
| 인터페이스 | 계층 사이의 규약 | 소켓 API (응용↔전송 계층 인터페이스) |
프로그래밍에서 함수를 작게 나누고 각 함수가 하나의 책임만 가지게 설계하는 것처럼, 네트워크도 통신 과정을 계층으로 나누어 각 계층이 하나의 역할만 담당하게 만든 것입니다. 이것이 바로 관심사의 분리(Separation of Concerns)입니다.
문제 진단에서의 계층 활용
계층화의 실질적 가치는 문제를 격리할 수 있다는 데 있습니다.
# 1계층 (물리): 케이블이 연결되어 있나?
ip link show eth0
# state UP = 물리적 연결 정상
# 2계층 (데이터 링크): 같은 네트워크 내 통신이 되나?
arping -c 3 192.168.1.1
# MAC 주소 응답 확인
# 3계층 (네트워크): 다른 네트워크로 도달 가능한가?
ping -c 4 8.8.8.8
# IP 통신 확인 (DNS 우회)
# 4계층 (전송): 포트가 열려있나?
nc -zv example.com 443
# TCP 연결 가능 여부
# 7계층 (응용): HTTP 응답이 정상인가?
curl -v https://example.com
# HTTP 상태 코드와 헤더 확인ping은 되는데 curl이 안 된다면? 3계층까지는 정상이고 문제는 4~7계층에 있습니다. 이렇게 아래에서 위로 하나씩 확인하면 문제의 위치를 정확히 좁힐 수 있습니다.
다음 절에서는 이 계층화 원리를 가장 체계적으로 정리한 모델인 OSI 7계층을 살펴보겠습니다.