LLM WikiAccess-protected knowledge portal

WIKI

TCP/IP와 OSI 모델: 패킷이 데이터베이스까지 가는 길

왜 DBA도 네트워크를 알아야 하는가 쿼리가 느리다. 원인을 찾으러 slow query log를 열었는데 DB 내부에는 아무 문제가 없다. 그런데 애플리케이션 측에서는 응답이 800ms다. 차이는 어디에 있는가. 네트워크다. 데이터베이스 운영자는 종종 "DB 안"과 "DB 밖"을 분리해서 생각한다. 하지만 실제 트랜잭션 지연의 상당 부분은 네트워크 구간에서 발생한다. 연결 풀이 고갈되어 connection queue가 쌓이는

경로human/study/content/networking-fundamentals/01-tcp-ip-osi-model.md
카테고리Study
태그#fundamentals #infra #model #mysql #networking #osi #study #tcp

왜 DBA도 네트워크를 알아야 하는가

쿼리가 느리다. 원인을 찾으러 slow query log를 열었는데 DB 내부에는 아무 문제가 없다. 그런데 애플리케이션 측에서는 응답이 800ms다. 차이는 어디에 있는가. 네트워크다.

데이터베이스 운영자는 종종 "DB 안"과 "DB 밖"을 분리해서 생각한다. 하지만 실제 트랜잭션 지연의 상당 부분은 네트워크 구간에서 발생한다. 연결 풀이 고갈되어 connection queue가 쌓이는 것도 네트워크 관련이고, replica lag이 순간적으로 치솟는 것도 I/O 문제 외에 네트워크 패킷 재전송이 원인인 경우가 있다. Cloud 환경에서 매니지드 DB와 애플리케이션이 다른 AZ에 있을 때 왜 지연이 생기는지도 네트워크 이해 없이는 설명하기 어렵다.

이 편은 OSI 모델과 TCP/IP의 내부 구조를 DBA·인프라 엔지니어의 시각에서 정리한다. 이론을 위한 이론이 아니라 실제 장애 분석과 성능 진단에 쓸 수 있는 수준까지 다룬다.


OSI 7계층 모델

OSI(Open Systems Interconnection) 참조 모델은 네트워크 통신을 7개의 추상 계층으로 나눈다. 실제 프로토콜 구현은 이 모델을 완전히 따르지 않지만, 문제를 계층별로 격리해서 생각하는 데 유용하다.

계층이름역할대표 프로토콜/기술
7응용(Application)사용자 및 애플리케이션과의 인터페이스HTTP, MySQL Protocol, PostgreSQL Protocol, DNS
6표현(Presentation)데이터 인코딩·암호화·압축TLS/SSL, MIME, JPEG
5세션(Session)연결 설정·유지·종료TLS handshake, NetBIOS
4전송(Transport)종단 간 데이터 전달, 오류 복구TCP, UDP, SCTP
3네트워크(Network)논리 주소 지정, 라우팅IP, ICMP, OSPF, BGP
2데이터링크(Data Link)인접 노드 간 프레임 전송, MAC 주소Ethernet, Wi-Fi (802.11), ARP
1물리(Physical)비트 스트림 → 전기·광 신호 변환케이블, 광섬유, 라디오파

실무에서 "계층 3 문제"라고 하면 라우팅·IP 주소 관련 문제, "계층 4 문제"라고 하면 TCP 연결·포트 관련 문제다. 장애 분석 시 어느 계층에서 멈추는지 확인하는 것이 첫 단계다.


TCP/IP 4계층 모델

실제 인터넷은 OSI가 아닌 TCP/IP 프로토콜 스택으로 동작한다. TCP/IP 모델은 OSI를 단순화해 4개 계층으로 정의한다.

OSI 7계층 7. 응용 (Application) 6. 표현 (Presentation) 5. 세션 (Session) 4. 전송 (Transport) — TCP/UDP 3. 네트워크 (Network) — IP 2. 데이터링크 — Ethernet/ARP 1. 물리 — 케이블·광섬유 TCP/IP 4계층 응용 계층 HTTP, FTP, DNS, MySQL Wire Protocol TLS (응용 계층에서 협상) 전송 계층 (Transport) 인터넷 계층 (Internet) — IP 네트워크 액세스 계층 Ethernet, Wi-Fi, ARP
TCP/IP 4계층과 OSI 7계층 매핑

TCP/IP 모델에서 OSI 5·6·7계층이 "응용 계층" 하나로 합쳐진다. TLS는 OSI 관점에서는 표현·세션 계층이지만, TCP/IP 구현에서는 응용 계층 라이브러리(OpenSSL, BoringSSL)로 처리된다.


IP 주소와 라우팅

IPv4와 CIDR

IPv4 주소는 32비트이며 점-십진수 표기법(dotted decimal)으로 표현한다. 192.168.1.100처럼 네 개의 8비트 옥텟을 점으로 구분한다.

CIDR(Classless Inter-Domain Routing) 표기법은 IP 주소에 서브넷 마스크 길이를 슬래시로 붙인다.

10.0.0.0/24
  ↑         ↑
  네트워크   서브넷 마스크 비트 수 (24 → 255.255.255.0)

사용 가능한 호스트 주소: 2^(32-24) - 2 = 254개
  (첫 번째: 네트워크 주소, 마지막: 브로드캐스트 주소)

Cloud VPC 설계에서 CIDR 블록 선택은 중요하다. 서브넷을 너무 작게 나누면 IP가 부족해지고, 너무 크게 나누면 라우팅 테이블이 복잡해진다. 예를 들어 AWS에서 DB 서브넷을 10.0.2.0/24(254개 IP)로 구성하면 RDS 인스턴스, 복제본, 내부 서비스 IP를 모두 여기서 할당한다.

라우팅 기초

패킷이 목적지까지 가려면 라우터가 라우팅 테이블을 보고 다음 홉(next hop)을 결정한다. 가장 긴 접두사(longest prefix match) 규칙에 따라 가장 구체적인 경로가 선택된다.

라우팅 테이블 예시:
  10.0.0.0/16    → VPC 내부 트래픽 (로컬 처리)
  0.0.0.0/0      → 인터넷 게이트웨이 (기본 경로)

목적지: 10.0.1.55
  → 10.0.0.0/16 매칭 (더 구체적) → VPC 내부 처리

DB 인스턴스와 애플리케이션이 같은 VPC 안에 있으면 패킷은 인터넷을 거치지 않고 내부 라우팅으로 처리된다. 레이턴시가 낮고 비용도 없다. 다른 VPC나 온프레미스에서 접근한다면 VPC Peering, Transit Gateway, 또는 VPN/Direct Connect를 통해 라우팅된다.


TCP: 신뢰성 있는 전송

TCP(Transmission Control Protocol)는 연결 지향, 순서 보장, 오류 복구, 흐름 제어 기능을 제공한다. 데이터베이스 프로토콜(MySQL Wire Protocol, PostgreSQL Frontend-Backend Protocol) 대부분이 TCP 위에서 동작한다.

3-way 핸드셰이크

클라이언트 (App) 서버 (DB) ─── 연결 수립 (3-way handshake) ─── SYN (seq=x) 클라이언트가 연결 요청. 초기 시퀀스 번호 x를 제안 SYN-ACK (seq=y, ack=x+1) 서버가 수락. 자신의 초기 시퀀스 번호 y를 제안 ACK (ack=y+1) 클라이언트가 확인. 연결 수립 완료 → ESTABLISHED ✅ 데이터 교환 (SQL 쿼리 / 결과) ─── 연결 종료 (4-way teardown) ─── FIN (클라이언트) 더 이상 보낼 데이터 없음 ACK (서버) FIN (서버) 서버도 보낼 데이터 없음 ACK (클라이언트) → TIME_WAIT → CLOSED
TCP 3-way 핸드셰이크와 4-way 종료

핸드셰이크의 핵심은 양방향 통신 채널을 확인하는 것이다. SYN-ACK 한 번에 할 수 있지 않냐고 생각할 수 있지만, 클라이언트→서버, 서버→클라이언트 두 방향 모두를 확인해야 하기 때문에 최소 3회가 필요하다.

TIME_WAIT 상태: 클라이언트가 마지막 ACK를 보낸 후 2×MSL(Maximum Segment Lifetime, 보통 60초) 동안 대기한다. 이 상태 동안 같은 포트를 재사용할 수 없다. DB 연결을 초당 수천 개씩 새로 열고 닫으면 TIME_WAIT이 포트 부족을 일으킬 수 있다. 커넥션 풀이 필수인 이유 중 하나다.

흐름 제어(Flow Control)

수신 측이 처리 못 할 만큼 빠르게 패킷을 보내면 버퍼가 넘쳐 패킷이 유실된다. TCP는 슬라이딩 윈도(sliding window)로 이를 방지한다.

수신자는 ACK 응답에 수신 윈도 크기(RWND)를 포함해 보낸다. 이 값이 "지금 나는 N바이트까지 받을 수 있다"는 신호다. 송신자는 이 크기를 넘지 않는 범위에서 데이터를 보낸다.

DB 서버가 바쁘거나 메모리가 부족할 때 RWND가 0으로 내려가는 "zero window" 상태가 발생할 수 있다. tcpdumpTCP ZeroWindow 패킷이 보인다면 DB 서버의 처리 능력이나 메모리가 병목이라는 신호다.

혼잡 제어(Congestion Control)

네트워크 자체가 혼잡해도 패킷이 유실된다. TCP는 혼잡 윈도(CWND)를 관리해 네트워크 상태에 맞게 전송 속도를 조절한다.

주요 알고리즘:

WAN을 통해 원격 DB에 접속하거나, 클라우드 리전 간 복제를 설정할 때 혼잡 제어 알고리즘을 이해하면 성능 차이의 원인을 이해하는 데 도움이 된다.


UDP: 왜 존재하는가

UDP(User Datagram Protocol)는 연결 수립 없이 패킷을 보낸다. 순서 보장도 없고, 재전송도 없다. 그렇다면 왜 쓰는가.

TCP의 핸드셰이크와 흐름 제어는 신뢰성을 주는 대신 레이턴시 오버헤드가 있다. 실시간성이 중요하고 약간의 패킷 유실이 허용되는 경우 UDP가 낫다.

특성TCPUDP
연결 수립필요 (3-way handshake)불필요
순서 보장
신뢰성○ (재전송)
흐름·혼잡 제어
오버헤드높음낮음
주요 사용HTTP, DB, 파일 전송DNS, 스트리밍, 게임, QUIC

DNS: 단일 요청-응답이라 TCP 오버헤드가 낭비다. UDP 53번 포트로 질의하고 응답이 크면(512바이트 초과) TCP로 fallback한다.

QUIC(HTTP/3): UDP 위에서 직접 신뢰성·암호화·멀티플렉싱을 구현한다. 커널 TCP 스택을 우회해 사용자 공간에서 혼잡 제어를 최적화할 수 있다. Google, Cloudflare가 주도하고 있으며 HTTP/3의 기반이다.

데이터베이스 프로토콜은 신뢰성이 필수이므로 대부분 TCP를 사용한다. 예외적으로 일부 캐시 시스템(Memcached)이 UDP를 지원하지만, 일반적으로 DB 통신에서 UDP를 선택하지는 않는다.


SQL 쿼리가 네트워크를 타는 방법

애플리케이션이 SELECT * FROM orders WHERE id = 42를 실행하면 어떤 일이 일어나는가.

애플리케이션 커넥션 풀에서 소켓 획득
TLS 암호화
MySQL Wire Protocol
응용 계층
TCP 세그먼트
포트 3306 → 임시포트
전송 계층
IP 패킷
src/dst IP + TTL
네트워크 계층
Ethernet 프레임
MAC 주소
데이터링크 계층
물리/가상 네트워크
(NIC → 스위치 → 라우터 → DB NIC)
역방향: 프레임→패킷→세그먼트 디캡슐화 DB 프로세스
쿼리 파싱·실행
지연(latency)이 발생하는 구간
연결 수립: TCP handshake ≈ 1 RTT TLS handshake ≈ 1-2 RTT 추가 패킷 재전송: 유실 시 RTT 지연 수신 버퍼 처리: RWND 병목 네트워크 홉: 라우터·스위치 처리 시간
SQL 쿼리의 네트워크 여정

커넥션 풀을 쓰면 TCP 핸드셰이크 비용은 연결 초기 한 번만 지불한다. 하지만 TLS는 세션 재개(session resumption)를 사용하지 않으면 풀 연결마다 handshake 비용이 든다. MySQL 8.0+, PostgreSQL 15+는 TLS 세션 재개를 지원한다.

쿼리 단위 레이턴시 분석:

총 쿼리 지연 = (network RTT) + (DB 서버 처리 시간)

예:
  애플리케이션 → DB 응답: 50ms
  DB slow log:            5ms (DB 내부 처리)
  → 네트워크 구간 ≈ 45ms

  이 경우 쿼리 최적화보다 AZ 배치나 커넥션 풀 설정을 먼저 확인해야 한다.

네트워크 디버깅 도구

ping과 traceroute

# 연결 가능 여부 및 RTT 확인
ping -c 4 db.prod.internal

# 경로의 각 홉별 지연 확인
traceroute db.prod.internal
# Linux에서는 mtr이 더 자세한 정보 제공
mtr db.prod.internal

ping이 응답하지 않아도 DB가 동작 중일 수 있다. ICMP를 차단하는 방화벽·보안 그룹이 있으면 ping은 실패해도 TCP 연결은 된다.

ss와 netstat

ss(socket statistics)는 현재 연결 상태를 보는 데 유용하다. netstat의 현대적 대체도구다.

# TCP 연결 상태 전체 보기
ss -tnp

# 특정 포트(3306) 관련 연결만
ss -tnp | grep :3306

# TIME_WAIT 개수 확인
ss -tn state time-wait | wc -l

# 수신 큐가 쌓인 연결 확인 (Recv-Q > 0)
ss -tn | awk '$2 > 0'

Recv-Q가 쌓여 있다면 애플리케이션이 네트워크 데이터를 충분히 빠르게 읽지 못하는 것이다. DB 서버 자체가 과부하 상태일 때 발생한다.

tcpdump

실제 패킷을 캡처해서 분석한다. 프로덕션에서 사용할 때는 캡처 필터를 정확히 걸어야 오버헤드를 최소화할 수 있다.

# MySQL 포트(3306) 트래픽만 캡처
tcpdump -i eth0 -nn 'port 3306' -w /tmp/mysql.pcap

# 특정 DB 호스트와의 통신만
tcpdump -i eth0 -nn 'host 10.0.1.50 and port 3306'

# TCP 재전송 패킷 확인
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'

캡처한 .pcap 파일은 Wireshark로 분석한다. MySQL Wire Protocol 플러그인이 있어 SQL 쿼리 내용까지 보여준다(TLS 없는 경우).


Linux 네트워크 스택에서 중요한 커널 파라미터

DB 서버 운영 시 조정이 필요한 주요 커널 파라미터다.

# 최대 파일 디스크립터 수 (소켓도 FD를 사용)
net.core.somaxconn = 65535          # listen 백로그 크기
net.ipv4.tcp_max_syn_backlog = 65535

# TIME_WAIT 재사용
net.ipv4.tcp_tw_reuse = 1           # TIME_WAIT 소켓 재사용 허용
net.ipv4.tcp_fin_timeout = 30       # FIN_WAIT2 타임아웃 단축

# 수신·송신 버퍼 크기 (WAN 최적화)
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

# keepalive: 끊어진 연결 조기 감지
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5

tcp_keepalive_time은 애플리케이션이 비어 있는 연결을 유지하는 시간이다. DB 측 wait_timeout(MySQL) 또는 idle_in_transaction_session_timeout(PostgreSQL)과 함께 조정해야 한다. 애플리케이션 keepalive가 DB 서버 타임아웃보다 짧아야 연결이 끊기는 것을 방지할 수 있다.


실무 체크리스트: 네트워크 레이어 DB 장애 분석

DB 장애 시 네트워크 관련 가능성을 체크하는 순서다.

  1. ping/traceroute: 기본 연결성 확인. 응답하면 L3 이하는 정상.
  2. 포트 연결 확인: nc -zv db.host 3306 또는 telnet db.host 3306으로 TCP 연결 확인.
  3. ss로 연결 상태: ESTABLISHED 수가 갑자기 줄었는지, TIME_WAIT이 폭증했는지.
  4. Recv-Q 확인: DB 서버가 읽지 못하는 패킷이 쌓여 있는지.
  5. tcpdump: 패킷 재전송(TCP Retransmission), 제로 윈도(TCP ZeroWindow) 여부.
  6. 커넥션 풀 상태: 풀이 고갈됐는지 애플리케이션 사이드 지표 확인.
  7. 레이턴시 분리: 총 응답시간 - DB slow log 시간 = 네트워크 + 커넥션 오버헤드.

References