독서(Reading)/시스템 성능 엔지니어링

시스템 성능 엔지니어링: 네트워크 기초 개념 정리

Chann._.y 2026. 6. 3.
728x90

브렌던 그렉의 『시스템 성능 엔지니어링』을 읽다 보면 네트워크 장에서 익숙하지만 정확히 구분하기 어려운 용어들이 많이 나온다. 예를 들어 전송, 버퍼, 윈도, TCP 오프로드, ICMP, CIDR, backlog 같은 단어들은 모두 들어본 적은 있지만, 막상 성능 문제를 분석할 때는 헷갈리기 쉽다.

이번 글에서는 지금까지 정리한 네트워크 관련 질문들을 하나의 흐름으로 묶어 정리한다.


1. “전송”이라는 번역어의 여러 의미

네트워크 문맥에서 한국어로 전송이라고 번역되는 영어 표현은 하나가 아니다.

대표적으로 다음 표현들이 있다.

영어 표현자연스러운 번역의미

transmission 전송, 송신 비트나 신호를 실제 매체에 실어 보냄
transport 전송, 운반 TCP/UDP 같은 종단 간 데이터 운반 기능
transportation 수송, 운송 사람이나 물건의 물리적 운송. 네트워크 용어로는 거의 쓰지 않음
transfer 전송, 이전 파일이나 데이터를 한 곳에서 다른 곳으로 옮김
forwarding 전달, 포워딩 라우터가 패킷을 다음 홉으로 넘김
delivery 전달, 배달 목적지에 도달함

예를 들어 전송 계층은 transport layer이고, 전송 지연은 transmission delay라고 한다.

transmission delay = packet size / link bandwidth

즉, transmission은 실제 링크에 비트를 밀어 넣는 행위이고, transport는 TCP/UDP처럼 종단 간 통신을 담당하는 계층적 개념이다.


2. NIC 버퍼와 전송 지연

NIC는 네트워크 인터페이스 카드(network interface card)다. NIC는 들어오거나 나가는 패킷을 바로 처리하지 못할 때 내부 버퍼에 잠시 저장한다.

애플리케이션
  ↓
커널 네트워크 스택
  ↓
NIC 송신 버퍼
  ↓
네트워크

버퍼가 작으면 순간적인 트래픽 증가를 흡수하지 못해 패킷이 드롭될 수 있다. 반대로 버퍼가 너무 크면 패킷이 큐에서 오래 기다리면서 지연시간이 커진다.

예를 들어 1Gbps 링크 앞에 10MB가 쌓이면 최악의 경우 뒤쪽 패킷은 대략 다음만큼 기다릴 수 있다.

10MB × 8 / 1Gbps = 약 80ms

이처럼 큰 버퍼가 패킷 손실은 줄일 수 있지만 지연을 증가시키는 현상을 버퍼블로트(bufferbloat)라고 한다.


3. on-CPU와 off-CPU

성능 분석에서는 시간이 어디에서 쓰였는지를 구분해야 한다.

on-CPU는 스레드가 실제 CPU 위에서 실행 중인 시간이다.

계산
파싱
압축
암호화
루프 실행
커널 코드 실행

반대로 off-CPU는 스레드가 CPU를 쓰지 못하고 기다리는 시간이다.

디스크 I/O 대기
네트워크 I/O 대기
락 대기
sleep
스케줄러 대기

예를 들어 요청 하나가 200ms 걸렸는데 CPU 사용 시간은 5ms뿐이라면, 나머지 195ms는 대부분 off-CPU 시간일 가능성이 크다.

요청 처리 시간 200ms
├─ on-CPU: 5ms
└─ off-CPU: 195ms

CPU flame graph는 주로 on-CPU 시간을 보여주고, off-CPU flame graph는 어디에서 블록되었는지 보여준다.


4. TCP 오프로드와 LSO

TCP 오프로드(TCP offload)는 TCP/IP 처리 중 일부를 CPU 대신 NIC가 처리하게 하는 기능이다.

대표적인 기능은 다음과 같다.

기능의미

checksum offload TCP/IP 체크섬 계산을 NIC가 수행
TSO / LSO 큰 TCP 데이터를 NIC가 작은 세그먼트로 분할
GRO / LRO 수신된 작은 패킷들을 큰 덩어리로 합침

LSO(Large Segment Offload)는 큰 TCP 데이터를 NIC가 MTU에 맞게 작은 TCP 세그먼트로 나눠 보내는 기능이다. 리눅스에서는 보통 TSO(TCP Segmentation Offload)라는 이름으로 자주 보인다.

LSO가 없으면 커널이 64KB 데이터를 1460B 단위로 쪼갠다.

커널:
64KB → 1460B → 1460B → 1460B ...

LSO가 있으면 커널은 큰 덩어리를 NIC에 넘기고, NIC가 실제 전송 직전에 나눈다.

커널:
64KB 덩어리 전달

NIC:
MTU에 맞게 TCP 세그먼트 분할

주의할 점은 tcpdump에서 64KB짜리 TCP 패킷이 보여도 실제 네트워크에 그 크기로 나간 것은 아닐 수 있다는 점이다. NIC가 분할하기 전의 큰 세그먼트를 캡처했기 때문이다.


5. 계층별 헤더와 실제 payload 크기

일반적인 Ethernet MTU는 1500바이트다. 이 1500바이트는 Ethernet header와 FCS를 제외한 L2 payload 크기다.

IPv4 + TCP 기준으로 애플리케이션이 한 세그먼트에 실을 수 있는 데이터는 보통 1460바이트다.

Ethernet MTU 1500
- IPv4 header 20
- TCP header 20
= TCP payload 1460 bytes

자주 쓰는 값은 다음과 같다.

조합애플리케이션 payload

IPv4 + TCP 1460B
IPv4 + UDP 1472B
IPv6 + TCP 1440B
IPv6 + UDP 1452B

Ethernet frame 전체 크기는 보통 다음과 같다.

Ethernet header 14B
+ MTU 1500B
+ FCS 4B
= 1518B

즉, MTU는 “IP 패킷이 들어갈 수 있는 공간”이고, 애플리케이션 데이터는 거기서 IP 헤더와 TCP/UDP 헤더를 뺀 값이다.


6. ICMP

ICMP(Internet Control Message Protocol)는 애플리케이션 데이터를 주고받는 프로토콜이 아니라, IP 네트워크에서 오류를 알려주고 상태를 진단하기 위한 제어 메시지 프로토콜이다.

대표적인 사용 예는 ping이다.

내 컴퓨터 → ICMP Echo Request → 상대 서버
내 컴퓨터 ← ICMP Echo Reply   ← 상대 서버

ICMP는 TCP/UDP처럼 포트를 사용하지 않는다. 대신 타입(type)코드(code)를 사용한다.

ICMP Type의미

0 Echo Reply
3 Destination Unreachable
8 Echo Request
11 Time Exceeded

ICMP는 traceroute, MTU 문제 진단, 목적지 도달 불가 확인 등에 중요하다.

특히 PMTUD(Path MTU Discovery)에서는 “패킷이 너무 커서 전달할 수 없다”는 ICMP 메시지가 필요하다. ICMP를 무조건 차단하면 특정 큰 패킷 전송이 멈추는 문제가 생길 수 있다.


7. TTL은 정말 Time인가?

IPv4의 TTL은 Time To Live의 약자다. 이름만 보면 시간 제한처럼 보이지만, 현재 네트워크에서는 사실상 홉 제한(hop limit)으로 동작한다.

라우터를 하나 지날 때마다 TTL은 1씩 감소한다.

TTL 64 → 63 → 62 → ... → 0

TTL이 0이 되면 라우터는 패킷을 버리고 보통 ICMP Time Exceeded 메시지를 보낸다.

IPv6에서는 이 의미를 더 명확히 하기 위해 TTL 대신 Hop Limit이라는 필드 이름을 사용한다.

IPv4: TTL
IPv6: Hop Limit

TTL의 목적은 라우팅 루프가 생겼을 때 패킷이 네트워크 안에서 영원히 떠돌지 않게 하는 것이다.


8. traceroute의 한계와 TCP/UDP traceroute

traceroute는 TTL을 1, 2, 3처럼 바꾼 여러 probe 패킷을 보내고, 중간 라우터가 돌려주는 ICMP Time Exceeded 메시지를 이용해 경로를 추정한다.

하지만 traceroute 결과가 “실제 모든 패킷이 항상 이 경로로 간다”는 뜻은 아니다.

이유는 다음과 같다.

ECMP/load balancing
정책 라우팅
ICMP 차단
ICMP rate limit
프로토콜별 다른 경로
probe마다 다른 포트 사용

실제 문제가 나는 트래픽이 TCP라면 TCP 기반 traceroute를 쓰는 것이 좋다.

traceroute -T -p 443 example.com

HTTPS 문제라면 TCP 443 기준으로 보는 것이 ICMP보다 현실적이다.

UDP 서비스라면 UDP 기반 traceroute를 사용한다.

traceroute -U -p 53 8.8.8.8
traceroute -U -p 443 example.com

선택 기준은 단순하다.

웹/SSH/DB 문제 → TCP traceroute
DNS/QUIC/게임/VoIP/VPN 문제 → UDP traceroute
단순 경로 힌트 → ICMP traceroute

9. IP class와 CIDR

예전 IPv4 주소 체계는 클래스풀 주소 체계(classful addressing)였다. IP 주소의 첫 번째 옥텟을 보고 A/B/C class를 나눴다.

Class범위기본 prefix

A 1.0.0.0 ~ 126.255.255.255 /8
B 128.0.0.0 ~ 191.255.255.255 /16
C 192.0.0.0 ~ 223.255.255.255 /24

하지만 이 방식은 주소 낭비가 심했다. 그래서 현재는 CIDR(Classless Inter-Domain Routing)을 사용한다.

CIDR은 /24, /16, /27처럼 prefix 길이로 네트워크 크기를 표현한다.

192.168.1.0/24
10.0.0.0/8
172.16.0.0/12

계산식은 다음과 같다.

주소 개수 = 2^(32 - prefix 길이)
사용 가능 호스트 수 = 주소 개수 - 2

예를 들어 /24는 다음과 같다.

2^(32 - 24) = 256개 주소
사용 가능 호스트 수 = 254개

요즘 실무에서는 “C class”라고 말하기보다 /24 네트워크라고 말하는 것이 더 정확하다.


10. 100.64.0.0/10과 CGNAT

100.x.x.x 전체가 private IP는 아니다. 정확히는 다음 범위만 특별하다.

100.64.0.0/10
= 100.64.0.0 ~ 100.127.255.255

이 대역은 RFC 1918 private IP가 아니라 Shared Address Space다. 주로 CGNAT(Carrier-Grade NAT) 용도로 사용된다.

진짜 RFC 1918 private IP는 다음 세 개뿐이다.

10.0.0.0/8
172.16.0.0/12
192.168.0.0/16

CGNAT(Carrier-Grade NAT)는 통신사나 대규모 네트워크 사업자가 여러 고객을 하나의 공인 IP 또는 적은 수의 공인 IP 뒤에 묶어 인터넷에 나가게 하는 대규모 NAT다.

내 기기
  ↓
집 공유기 NAT
  ↓
통신사 CGNAT
  ↓
공인 인터넷

CGNAT는 IPv4 주소 부족 문제를 완화하지만, 외부에서 내 장비로 직접 접속하기 어렵게 만든다. 그래서 NAS, 게임 서버, VPN 서버, P2P 연결 등에 문제가 생길 수 있다.


11. TCP backlog

TCP backlog는 서버가 TCP 연결 요청을 받을 때, 아직 애플리케이션이 처리하지 못한 연결을 쌓아두는 대기열이다.

TCP 연결 수립에는 두 종류의 큐가 관련된다.

SYN queue
  아직 3-way handshake가 끝나지 않은 연결 대기열

accept queue
  handshake는 끝났지만 애플리케이션이 accept()하지 않은 연결 대기열

서버 코드에서 listen()의 두 번째 인자가 backlog다.

listen(server_fd, 128);

리눅스에서는 이 값이 주로 accept queue 크기에 영향을 준다. 다만 실제 최대값은 커널 설정인 net.core.somaxconn에 의해 제한될 수 있다.

SYN queue와 관련된 설정은 다음이다.

sysctl net.ipv4.tcp_max_syn_backlog

accept queue가 꽉 차면 클라이언트 연결이 지연되거나 실패할 수 있다. 현재 listen queue 상태는 ss로 볼 수 있다.

ss -lnt

LISTEN 상태에서 Recv-Q가 Send-Q에 가까워지면 애플리케이션이 accept()를 충분히 빨리 처리하지 못하고 있을 가능성이 있다.


12. SYN cookie

SYN cookie는 SYN flood 공격을 받을 때 서버가 half-open 연결 상태를 메모리에 저장하지 않고도 TCP handshake를 처리할 수 있게 해주는 방어 기법이다.

일반적인 TCP handshake는 다음과 같다.

1. 클라이언트 → 서버: SYN
2. 서버 → 클라이언트: SYN-ACK
3. 클라이언트 → 서버: ACK

원래 서버는 SYN을 받으면 SYN queue에 연결 후보 상태를 저장한다. 그런데 공격자가 SYN만 대량으로 보내고 마지막 ACK를 보내지 않으면 SYN queue가 찰 수 있다.

SYN cookie는 이 상태를 저장하지 않고, SYN-ACK의 sequence number 안에 검증용 정보를 담는다.

서버 → 클라이언트: SYN-ACK, seq = cookie 값

나중에 클라이언트가 ACK를 보내면 서버는 ack - 1 값을 보고 자신이 만든 유효한 cookie인지 검증한다.

ACK 도착
→ cookie 검증
→ 유효하면 그때 연결 생성

리눅스에서는 다음 설정으로 확인한다.

sysctl net.ipv4.tcp_syncookies

SYN cookie는 SYN queue 고갈에는 도움이 되지만, 이미 완성된 연결 폭주나 애플리케이션 처리 병목까지 해결하지는 못한다.


13. TCP 버퍼링과 슬라이딩 송신 윈도

TCP는 데이터를 바로 네트워크에 내보내지 않고 커널 버퍼에 저장한다.

송신 쪽 흐름은 다음과 같다.

애플리케이션
  ↓ write()
TCP 송신 버퍼
  ↓
TCP 세그먼트
  ↓
NIC
  ↓
네트워크

수신 쪽도 마찬가지다.

네트워크
  ↓
TCP 수신 버퍼
  ↓ read()
애플리케이션

송신 버퍼는 재전송을 위해 필요하다. TCP는 상대방이 ACK를 보내기 전까지 이미 보낸 데이터도 보관해야 한다.

슬라이딩 송신 윈도(sliding send window)는 ACK를 받기 전에도 일정량의 데이터를 연속으로 보낼 수 있게 하는 범위다.

송신 윈도 = ACK 없이 outstanding 상태로 둘 수 있는 바이트 범위

ACK가 오면 윈도는 앞으로 이동한다.

[ 보냈지만 ACK 없음 ][ 보낼 수 있음 ][ 아직 못 보냄 ]
        ↑                         ↑
        윈도 왼쪽                  윈도 오른쪽

실제 송신 가능량은 보통 다음 두 값 중 작은 값이다.

실제 송신 가능량 = min(rwnd, cwnd)

여기서 rwnd는 수신 윈도(receive window), cwnd는 혼잡 윈도(congestion window)다.

rwnd = 수신자가 받을 수 있는 버퍼 여유
cwnd = 네트워크 혼잡을 고려한 송신 제한

송신 버퍼는 저장 공간이고, 송신 윈도는 그중 지금 보낼 수 있는 범위다.


14. BQL, CoDel, TSQ

이 세 가지는 모두 네트워크 큐를 너무 크게 만들지 않기 위한 Linux 네트워크 성능 메커니즘이다.

전체 위치는 대략 다음과 같다.

애플리케이션
  ↓
TCP 송신 버퍼
  ↓  TSQ
qdisc 큐
  ↓  CoDel / FQ-CoDel
NIC 드라이버 큐
  ↓  BQL
NIC 하드웨어 큐
  ↓
네트워크

BQL

BQL(Byte Queue Limits)은 NIC 하드웨어 송신 큐에 너무 많은 바이트가 쌓이지 않도록 제한하는 메커니즘이다.

핵심은 NIC가 굶지 않을 만큼만 채우고, 필요 이상으로 많이 쌓지 않는 것이다.

BQL 없음:
NIC 큐에 많이 쌓임
→ 큐잉 지연 증가

BQL 있음:
NIC 큐를 짧게 유지
→ 지연 감소

CoDel

CoDel(Controlled Delay)은 큐 길이가 아니라 패킷이 큐에서 기다린 시간을 기준으로 드롭 여부를 판단하는 큐잉 정책이다.

기존 drop-tail 방식은 큐가 꽉 찰 때까지 패킷을 쌓다가, 꽉 차면 버린다. CoDel은 다르게 본다.

큐에 몇 개가 쌓였는가?  ❌
패킷이 얼마나 오래 기다렸는가? ✅

패킷이 큐에서 계속 오래 기다리면 일부 패킷을 drop하거나 mark해서 TCP 송신자가 속도를 줄이게 한다.

실무에서는 플로우별 공정성을 함께 제공하는 FQ-CoDel(Fair Queue CoDel)도 자주 사용된다.

TSQ

TSQ(TCP Small Queues)는 특정 TCP 소켓이 qdisc나 device queue에 너무 많은 데이터를 밀어 넣지 못하게 제한하는 메커니즘이다.

TSQ 없음:
한 TCP 연결이 아래 큐를 과점
→ 다른 연결 지연 증가

TSQ 있음:
소켓별로 아래 큐에 밀어 넣는 양 제한
→ 지연과 불공정 완화

BQL이 NIC 하드웨어 큐를 제어한다면, TSQ는 TCP 소켓 단위로 아래 큐를 과점하지 못하게 한다.


15. 단대단 추론 원칙

단대단 추론 원칙(end-to-end argument)은 네트워크 설계 철학이다.

핵심은 다음과 같다.

애플리케이션의 정확성을 위해 꼭 필요한 기능은 네트워크 중간 장비보다 통신의 양 끝단에서 구현해야 한다.

예를 들어 데이터가 정확히 전달되었는지는 중간 라우터가 완전히 보장할 수 없다. 최종적으로 송신 애플리케이션과 수신 애플리케이션이 확인해야 한다.

그래서 TCP의 신뢰성, 순서 보장, 재전송, 혼잡 제어의 핵심은 끝단에서 처리한다.

중간 네트워크:
패킷을 최대한 전달

끝단 TCP:
손실 감지
재전송
순서 재조립
혼잡 제어

CoDel, BQL, TSQ 같은 기능은 끝단 제어를 보조한다. 네트워크 중간이나 커널 내부에서 큐 지연을 줄이고 혼잡 신호를 더 잘 전달하게 해주는 역할이다.


16. 쿠키, 세션, 스토리지

웹에서 쿠키(cookie), 세션(session), 스토리지(storage)는 모두 상태를 기억하기 위한 방법이다.

HTTP는 기본적으로 무상태(stateless) 프로토콜이다. 서버는 요청 하나만 보면 이전 요청과 같은 사용자인지 알 수 없다.

쿠키

쿠키는 브라우저에 저장되고, 조건에 맞으면 서버 요청에 자동으로 포함되는 작은 값이다.

Set-Cookie: session_id=abc123; HttpOnly; Secure

이후 브라우저는 요청마다 쿠키를 보낼 수 있다.

Cookie: session_id=abc123

세션

세션은 서버가 사용자 상태를 기억하는 방식이다. 브라우저에는 보통 세션 ID만 있고, 실제 사용자 정보는 서버에 있다.

브라우저 쿠키:
session_id=abc123

서버 세션 저장소:
abc123 → user_id=42, login=true

스토리지

스토리지는 브라우저 안에 JavaScript가 저장하는 클라이언트용 데이터다. 대표적으로 localStorage와 sessionStorage가 있다.

localStorage.setItem("theme", "dark");

쿠키와 달리 스토리지는 서버로 자동 전송되지 않는다.

정리하면 다음과 같다.

구분저장 위치서버로 자동 전송

Cookie 브라우저
Session 서버 직접 전송 안 됨
localStorage 브라우저 아니오
sessionStorage 브라우저 탭 아니오

전체 정리

네트워크 성능을 이해하려면 단순히 “패킷이 오간다”는 수준을 넘어서, 각 계층에서 어디에 데이터가 쌓이고, 누가 전송 속도를 제한하며, 어떤 신호로 혼잡을 감지하는지를 봐야 한다.

핵심 흐름은 다음과 같다.

애플리케이션 write()
  ↓
TCP 송신 버퍼
  ↓
슬라이딩 윈도, rwnd, cwnd
  ↓
TSQ
  ↓
qdisc, CoDel/FQ-CoDel
  ↓
NIC 드라이버 큐, BQL
  ↓
NIC 하드웨어 큐
  ↓
Ethernet/IP/TCP 패킷 전송
  ↓
라우터, TTL, ICMP
  ↓
수신 TCP 버퍼
  ↓
애플리케이션 read()

성능 문제는 이 중 어디에서든 발생할 수 있다.

CPU를 많이 쓰고 있다면 on-CPU 분석이 필요하다.
I/O나 락을 기다린다면 off-CPU 분석이 필요하다.
연결이 잘 안 된다면 backlog, SYN queue, SYN cookie를 봐야 한다.
지연이 크다면 NIC 버퍼, BQL, CoDel, TSQ, bufferbloat를 봐야 한다.
경로 문제가 의심되면 ICMP, traceroute, TCP/UDP traceroute를 구분해야 한다.
주소 체계를 이해하려면 class보다 CIDR을 기준으로 봐야 한다.

결국 네트워크 성능 분석의 핵심은 데이터가 어디에 머물고 있는가, 누가 속도를 제한하고 있는가, 어떤 계층에서 신호가 손실되고 있는가를 찾는 것이다.

728x90

댓글