디버깅 · 성능 측정

VPP 운영 중 실제로 마주치는 문제를 진단·복구하고, 성능을 측정·비교하는 방법을 정리합니다. 패킷 트레이싱·PCAP·이벤트 로거 같은 내부 계측 도구, 증상별 트러블슈팅 매트릭스, 흔한 설정 실수와 안티패턴, HTTP 프로토콜 레벨 트러블슈팅, TRex 기반 외부 벤치마크까지 다룹니다.

연관 문서: 일상 운영·설치·CLI/API·플러그인 개발·Kubernetes 통합 등 정상 상태 운용은 운영 · 플랫폼 · 확장에서 다룹니다. 본 페이지는 문제 상황과 측정 방법에 집중합니다.

성능 측정 및 벤치마크

VPP 구성을 완료한 뒤, 실제 처리량과 지연을 측정하는 체계적인 방법을 소개합니다. 수치 없는 "잘 되는 것 같다"는 운영에서 통하지 않습니다.

TRex를 이용한 트래픽 생성

TRex는 DPDK 기반 고성능 트래픽 생성기로, VPP 벤치마크의 사실상 표준입니다. CSIT(Continuous System Integration Testing)에서도 TRex를 사용합니다.

# TRex STL(Stateless) 프로파일 — NAT44 부하 테스트
from trex_stl_lib.api import *

class STLS1(object):
    def create_stream(self):
        base_pkt = Ether() / IP(
            src="192.168.1.10",
            dst="198.51.100.10"
        ) / UDP(
            sport=1024,
            dport=80
        ) / ("X" * 16)

        # 소스 IP와 포트를 변경하여 다양한 플로우 생성
        vm = STLScVmRaw([
            STLVmFlowVar(name="src_ip",
                         min_value="192.168.1.10",
                         max_value="192.168.1.250",
                         size=4, op="inc"),
            STLVmWrFlowVar(fv_name="src_ip",
                           pkt_offset="IP.src"),
            STLVmFlowVar(name="src_port",
                         min_value=1024,
                         max_value=60000,
                         size=2, op="inc"),
            STLVmWrFlowVar(fv_name="src_port",
                           pkt_offset="UDP.sport"),
            STLVmFixIpv4(offset="IP"),
        ])

        return STLStream(
            packet=STLPktBuilder(pkt=base_pkt, vm=vm),
            mode=STLTXCont(pps=1000000)  # 1Mpps부터 시작
        )

    def get_streams(self, **kwargs):
        return [self.create_stream()]

def register():
    return STLS1()
# TRex 실행 및 결과 확인
$ sudo ./t-rex-64 -i -c 4 --cfg /etc/trex_cfg.yaml

# TRex 콘솔에서:
trex> start -f nat44_test.py -m 5mpps -d 60
trex> stats
# TX: 5.00 Mpps, RX: 4.98 Mpps → 드롭율 0.04%

# VPP 측에서 동시에 확인:
vpp# show runtime
vpp# show interface GigabitEthernet0/8/0
vpp# show nat44 sessions count

VPP 내부 성능 카운터 해석

show runtime 출력의 각 열이 무엇을 뜻하는지 정확히 알아야 병목을 찾을 수 있습니다.

Name                 State    Calls    Vectors  Suspends  Clocks   Vectors/Call
dpdk-input           polling  1234567  9.87e7   0         22.1     79.9
ethernet-input       active   1234567  9.87e7   0         8.3      79.9
ip4-input            active   1234567  9.87e7   0         12.5     79.9
ip4-lookup           active   1234567  9.87e7   0         15.2     79.9
nat44-ed-in2out      active   1200000  9.60e7   0         44.3     80.0
ip4-rewrite          active   1200000  9.60e7   0         9.8      80.0
GigE0/9/0-output     active   1200000  9.60e7   0         5.1      80.0
GigE0/9/0-tx         active   1200000  9.60e7   0         18.7     80.0
의미정상 범위이상 징후
Calls노드가 호출된 횟수
Vectors처리한 총 패킷 수이전 노드보다 현저히 적으면 드롭 발생
Vectors/Call호출당 평균 배치 크기64~256<10이면 배치 효율 저하
Clocks패킷당 평균 CPU 클럭노드 의존특정 노드가 100+ 이면 병목
Suspends자발적 중단 횟수0>0이면 스케줄링 문제
병목 찾기: Clocks가 가장 높은 노드가 처리 비용의 병목입니다. NAT의 경우 nat44-ed-in2out이 보통 가장 높고, IPsec에서는 esp-encrypt/esp-decrypt가 지배적입니다. Vectors/Call이 낮다면 입력 큐가 적절히 배치되지 않아 벡터 효율이 떨어지는 것이므로 RSS 큐와 워커 매핑을 점검하세요.

디버깅 및 트러블슈팅

패킷 트레이싱

VPP의 패킷 트레이싱은 가장 강력한 디버깅 도구입니다. 패킷이 어떤 노드를 거쳐 어떤 결정을 받았는지 라인별로 확인할 수 있습니다.

패킷 트레이싱 수집 원리와 출력 구조 ① trace add 명령 vppctl trace add dpdk-input 50 (입력 노드 + 채집 개수) ② 트레이스 버퍼 할당 워커별 tracing table vlib_buffer->flags: TRACED ③ 첫 N개 패킷 태깅 dpdk-input 진입 시점에 trace index 할당 ④ show trace trace buffer 덤프 노드별 format_fn 실행 태깅된 패킷이 그래프를 통과하며 각 노드가 자기 몫의 trace record를 남김 dpdk-input rx queue · len ethernet-input MAC · EtherType ip4-input src/dst · ttl ip4-lookup fib index · adj ip4-rewrite next-hop · mtu interface-tx sw_if_index TX → NIC 각 노드는 format_trace 콜백을 등록해 자기 상태를 텍스트로 포맷합니다. 트레이스 수집은 한 번뿐(N개)이므로 성능에 영향이 없습니다. show trace 출력 (예시) Packet 1 00:01:23:456 dpdk-input GigabitEthernet0/8/0 rx queue 0 len 98 IP4 192.168.1.10 -> 10.0.0.1 00:01:23:456 ip4-input src 192.168.1.10 dst 10.0.0.1 ttl 64 proto ICMP len 84 00:01:23:456 ip4-lookup fib 0 dpo-load-balance via 10.0.0.1/32 adj 5 00:01:23:456 ip4-rewrite tx_sw_if_index 2 adj-idx 5 : via 10.0.0.1 ttl 63 -> GigabitEthernet0/9/0
# 트레이싱 활성화 (dpdk-input 노드에서 10개 패킷)
vpp# trace add dpdk-input 10

# 트래픽 발생 후 결과 확인
vpp# show trace

Packet 1

00:00:01:123456: dpdk-input
  GigabitEthernet0/8/0 rx queue 0
  buffer 0x9a340: current data 0, length 98, buffer-pool 0
  trace_handle 0x1000001
  l2-hdr-offset 0 ip4-hdr-offset 14

00:00:01:123458: ethernet-input              ← L2 분류
  IP4: fa:16:3e:aa:bb:cc -> fa:16:3e:dd:ee:ff

00:00:01:123459: ip4-input                   ← IPv4 처리 진입
  TCP: 192.168.1.100 -> 10.0.0.1
    tos 0x00, ttl 64, length 84, checksum 0x1234 dscp CS0 ecn NON_ECN
    fragment id 0x0001, flags DONT_FRAGMENT
  TCP: 45000 -> 80
    seq 0x12345678 ack 0x00000000
    flags [SYN] window 65535

00:00:01:123460: ip4-lookup                  ← FIB 룩업
  fib 0 dpo-idx 7 flow hash: 0x00001234
  TCP: 192.168.1.100 -> 10.0.0.1

00:00:01:123461: ip4-rewrite                 ← MAC 재작성
  tx_sw_if_index 2 dpo-idx 7
  adjacency rewrite: GigabitEthernet0/9/0
    dst aa:bb:cc:dd:ee:01 src fa:16:3e:xx:yy:zz

00:00:01:123462: GigabitEthernet0/9/0-output ← 인터페이스 출력
  GigabitEthernet0/9/0
  IP4: fa:16:3e:xx:yy:zz -> aa:bb:cc:dd:ee:01

00:00:01:123463: GigabitEthernet0/9/0-tx     ← TX 큐 전송
  buffer 0x9a340: current data -14, length 112
디버깅 시나리오trace add 대상확인 포인트
패킷이 VPP에 도달하지 않음dpdk-input 또는 af-xdp-inputRX 큐 수신 여부
라우팅(Routing) 문제ip4-inputip4-lookup의 dpo-idx
NAT 변환 문제nat44-in2out-output세션 매칭, 주소 변환(Address Translation)
ACL 드롭acl-plugin-in-ip4-fa매치 규칙, deny 여부
IPsec 터널(Tunnel) 문제ipsec-input-ip4SA 매칭, 복호화(Decryption) 에러
인터페이스 미출력interface-outputTX 큐 도달 여부

에러 카운터 분석

vpp# show errors
   Count   Node                  Reason
   15230   dpdk-input            no buffer available
     842   ip4-input             ip4 spoofed local-address packet drops
     156   ip4-lookup            ip4 destination lookup miss
      23   acl-plugin-in-ip4-fa  acl deny
       5   nat44-in2out          no translation
       2   ipsec-input-ip4       SA not found
에러노드원인해결
no bufferdpdk-input버퍼 풀 고갈buffers-per-numa 증가, hugepage 추가
ttl-exceededip4-inputTTL이 0에 도달라우팅 루프 확인
destination lookup missip4-lookupFIB에 경로 없음show ip fib로 경로 확인
adjacency incompleteip4-rewriteARP 미해석show ip neighbor, ARP 상태 확인
acl denyacl-pluginACL 규칙에 의한 차단show acl-plugin acl로 규칙 확인
no translationnat44NAT 세션/주소 풀 소진show nat44 sessions, 주소 풀 확인
SA not foundipsec-inputIPsec SA 매칭 실패show ipsec sa, SPI 확인
interface downinterface-output출력 인터페이스 downshow interface, admin up 확인
worker handoff dropshandoff핸드오프 큐 오버플로워커 부하 분산(Load Balancing), RSS 확인
dpdk driver init faildpdkNIC 바인딩 실패dpdk-devbind --status, VFIO/UIO 확인

PCAP 캡처

# 인입 패킷 PCAP 캡처
vpp# pcap trace rx max 1000 file rx-capture.pcap

# 송출 패킷 캡처
vpp# pcap trace tx max 1000 file tx-capture.pcap

# 드롭 패킷 캡처 (문제 진단에 가장 유용)
vpp# pcap trace drop max 1000 file drop-capture.pcap

# 특정 인터페이스만 캡처
vpp# pcap trace rx max 500 intfc GigabitEthernet0/8/0 file intf-rx.pcap

# 캡처 중지 및 저장
vpp# pcap trace off

# 파일 위치: /tmp/*.pcap
Wireshark 연계: /tmp/*.pcap 파일을 Wireshark에서 바로 열 수 있습니다. pcap trace drop은 VPP가 드롭한 패킷만 캡처하므로, "왜 패킷이 전달되지 않는가?"에 대한 직접적인 답을 제공합니다.

이벤트 로거와 코어 덤프(Core Dump)

VPP 디버깅 의사결정 트리 패킷이 전달되지 않음 1. show interface → RX 증가? No NIC/DPDK 확인 Yes 2. show errors → 에러 있음? Yes 에러 테이블 참조 No 3. trace add → 경로 추적 4. pcap trace drop → 드롭 패킷 Wireshark 분석 5. show ip fib / show ip neighbor 확인
# 이벤트 로거 활성화
vpp# event-logger resize 1000000
vpp# event-logger restart
vpp# event-logger save /tmp/elog.dat

# GDB로 VPP 디버깅 (디버그 빌드 필요)
$ gdb /usr/bin/vpp_main core.12345
(gdb) bt                          # 백트레이스
(gdb) thread apply all bt         # 모든 스레드 백트레이스
(gdb) frame 3                     # 특정 프레임으로 이동
(gdb) p *b                        # vlib_buffer_t 내용 출력

# startup.conf에서 코어 덤프 활성화
# unix { full-coredump }
# coredump 크기 제한 해제: ulimit -c unlimited
코어 덤프(Dump) 분석: VPP 코어 덤프 크기가 수 GB에 달할 수 있습니다(hugepage 매핑 포함). coredump_filter를 조정하여 hugepage를 제외하면 코어 크기를 줄일 수 있습니다: echo 0x33 > /proc/$(pidof vpp)/coredump_filter

자주 발생하는 문제와 해결

문제증상진단 방법해결
버퍼 고갈RX 드롭 급증show errors no-bufferbuffers-per-numa 증가
DPDK 초기화 실패VPP 시작 실패/var/log/vpp/vpp.logVFIO/UIO 바인딩, IOMMU 확인
Hugepage 부족VPP 시작 실패 또는 OOMcat /proc/meminfohugepage 추가 할당
워커 정지특정 큐 처리 중단show runtime Suspends배리어 장기 홀드 확인
ARP 미해석adjacency incompleteshow ip neighbor연결성 확인, proxy-arp
NAT 세션 소진no translation 에러show nat44 sessions세션 한도/타이머(Timer) 조정
RSS 불균형일부 워커만 과부하show runtime per-workerRSS 해시 키 변경, handoff
MTU 불일치패킷 드롭/단편화(Fragmentation)show hardware인터페이스 MTU 통일
CLI 소켓 거부vppctl 연결 실패소켓 권한 확인api-segment { gid vpp }
플러그인 충돌VPP 크래시코어 덤프 분석문제 플러그인 비활성, 버전 확인

트러블슈팅 가이드

VPP 실전 구성에서 자주 만나는 문제와 체계적인 진단 방법을 정리합니다.

패킷이 전달되지 않는 경우

# 1단계: 인터페이스 상태 확인
vpp# show interface
# 모든 인터페이스가 'up'인지 확인
# 'admin-down'이면: set interface state  up

# 2단계: 수신 패킷 확인
vpp# clear interface counters
# 트래픽 생성 후:
vpp# show interface
# rx-pkts가 증가하는지 확인
# 증가하지 않으면: DPDK 바인딩, Hugepage, NIC 드라이버 문제

# 3단계: 패킷 추적
vpp# clear trace
vpp# trace add dpdk-input 20
# 트래픽 생성 후:
vpp# show trace
# 패킷이 어느 노드에서 드롭되는지 확인
# 'error' 또는 'drop' 노드에서 끝나면 해당 에러 메시지 확인

# 4단계: 에러 카운터 확인
vpp# show errors
# 가장 높은 에러 카운터부터 추적

# 5단계: FIB(라우팅 테이블) 확인
vpp# show ip fib                  # 전체 라우팅 테이블
vpp# show ip fib 198.51.100.0/24  # 특정 서브넷 경로

자주 발생하는 문제와 해결법

증상진단 명령원인해결
VPP 시작 실패journalctl -u vppHugepage 부족, DPDK 바인딩 실패echo 1024 > /proc/sys/vm/nr_hugepages, dpdk-devbind.py -b vfio-pci
DPDK 인터페이스 미표시show interfaceNIC가 DPDK에 바인딩되지 않음dpdk-devbind.py --status로 확인, modprobe vfio-pci
ARP 미응답show ip neighbors인터페이스에 IP 미할당, uRPF 드롭set interface ip address 재확인. uRPF/ip4-local 트랩의 자세한 진단은 데이터 경로 — L3 라우팅VRF 기초 참조
NAT 세션 미생성show nat44 sessionsin/out 방향 설정 오류set interface nat44 in/out 방향 교차 확인
memif 연결 안됨show memif소켓 경로/권한, master/slave 역할양쪽 소켓 파일 경로 동일 확인, 권한 chmod 770
IPsec 단방향만 동작show ipsec sa detailSPI/키 불일치, 라우팅 미설정양쪽 설정 교차 검증, show ip fib
처리량 기대 이하show runtime워커 불균형, 배치 효율 저하RSS 큐 수와 워커 수 일치, isolcpus 확인

패킷 캡처 (pcap)

패킷 내용을 직접 확인해야 할 때는 VPP의 내장 pcap 기능을 사용합니다. tcpdump와 달리 커널을 거치지 않으므로 DPDK 인터페이스의 패킷도 캡처할 수 있습니다.

# 특정 인터페이스의 수신 패킷 캡처
vpp# pcap trace rx tx max 1000 intfc GigabitEthernet0/8/0 \
     file /tmp/vpp-capture.pcap

# 트래픽 발생 후 캡처 중지
vpp# pcap trace off

# 호스트에서 Wireshark로 분석
$ wireshark /tmp/vpp-capture.pcap

# 또는 tcpdump로 빠르게 확인
$ tcpdump -r /tmp/vpp-capture.pcap -nn | head -20

# 그래프 노드 단위 캡처 (더 세밀한 분석)
vpp# pcap trace rx tx max 500 \
     classify-table-index 0 \
     file /tmp/vpp-classified.pcap
주의: pcap 캡처는 성능에 영향을 줍니다. 운영 환경에서는 max를 작게 설정하고, 분석이 끝나면 즉시 pcap trace off로 중지하세요. 대량 캡처가 필요하면 trace addshow trace로 노드 경로만 먼저 확인하는 것이 효율적입니다.

흔한 실수와 안티패턴

VPP 운영 시 자주 발생하는 실수와 권장 해결 방법을 정리합니다. 특히 초기 구축 시 환경 설정 오류가 대부분의 장애 원인입니다.

Hugepage 설정 누락/부족

증상원인해결 방법
VPP 시작 실패: rte_eal_init errorHugepage 미할당커널 부트 파라미터에 hugepages=2048 추가
VPP 시작 후 버퍼 부족 경고Hugepage 부족워커 수 × 4GB 이상 확보 (NUMA 당)
DPDK 인터페이스 생성 실패1G hugepage만 할당, 2M 미할당hugeadm --pool-pages-min 2MB:2048
NUMA 편향 성능 저하NIC NUMA와 hugepage NUMA 불일치NIC NUMA 노드에 hugepage 분배: echo 1024 > /sys/devices/system/node/node0/hugepages/.../nr_hugepages
# Hugepage 상태 확인
$ cat /proc/meminfo | grep -i huge
HugePages_Total:    2048
HugePages_Free:     1536
HugePages_Rsvd:        0
Hugepagesize:       2048 kB

# 부팅 시 영구 설정 (GRUB)
GRUB_CMDLINE_LINUX="default_hugepagesz=2M hugepagesz=2M hugepages=2048 \
    hugepagesz=1G hugepages=4 iommu=pt intel_iommu=on"

# 런타임 할당 (재부팅 없이)
$ echo 2048 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
$ sudo mkdir -p /dev/hugepages
$ sudo mount -t hugetlbfs none /dev/hugepages

DPDK 인터페이스 바인딩 오류

드라이버IOMMU 필요장점주의사항
vfio-pci (권장)예 (intel_iommu=on)DMA 격리, 보안, SR-IOV 지원IOMMU 미활성 시 바인딩 실패
uio_pci_generic아니요IOMMU 없는 환경에서 동작보안 격리 없음, root 필요
igb_uio (DPDK)아니요레거시 NIC 호환별도 모듈 빌드 필요, 유지보수 중단 추세
# 잘못된 예: IOMMU 없이 vfio-pci 바인딩 시도
$ sudo dpdk-devbind.py --bind=vfio-pci 0000:00:08.0
# Error: Cannot bind to driver vfio-pci: No IOMMU group

# 올바른 해결 방법 1: IOMMU 활성화
# GRUB에 intel_iommu=on iommu=pt 추가 후 재부팅

# 올바른 해결 방법 2: IOMMU 없는 환경에서 vfio 사용
$ sudo modprobe vfio enable_unsafe_noiommu_mode=1
$ echo 1 | sudo tee /sys/module/vfio/parameters/enable_unsafe_noiommu_mode
$ sudo dpdk-devbind.py --bind=vfio-pci 0000:00:08.0

# NIC 현재 상태 확인
$ dpdk-devbind.py --status
Network devices using DPDK-compatible driver
============================================
0000:00:08.0 'Virtio network device' drv=vfio-pci

Network devices using kernel driver
====================================
0000:00:03.0 'Virtio network device' drv=virtio-pci
커널 드라이버 복귀 실패: DPDK에 바인딩된 NIC를 커널로 돌리려면 dpdk-devbind.py --bind=virtio-pci 0000:00:08.0을 사용합니다. 관리 인터페이스(SSH 접속용)를 실수로 DPDK에 바인딩하면 원격 접속이 끊어지므로 반드시 OOB(Out-of-Band) 관리 인터페이스를 별도 확보하세요.

startup.conf 워커 스레드 / CPU 핀닝 실수

실수 패턴증상올바른 설정
main-corecorelist-workers 중복메인/워커 경합, 불안정겹치지 않는 CPU 코어 할당
하이퍼스레딩 형제 코어에 워커 배치캐시 경합으로 성능 50% 저하물리 코어만 사용: lscpu -e로 확인
NUMA 노드 교차 배치원격 메모리 접근 지연NIC와 같은 NUMA 노드의 코어 사용
워커 수 > RSS 큐 수일부 워커 유휴num-rx-queues와 워커 수 일치
isolcpus 미적용OS 프로세스가 VPP 코어에 스케줄됨커널 부트 파라미터: isolcpus=1-3
# CPU 토폴로지 확인
$ lscpu -e
CPU NODE SOCKET CORE L1d L2 L3 ONLINE
  0    0      0    0   0  0  0      yes  ← main-core (관리용)
  1    0      0    1   1  1  0      yes  ← worker 0
  2    0      0    2   2  2  0      yes  ← worker 1
  3    0      0    3   3  3  0      yes  ← worker 2
  4    0      0    0   0  0  0      yes  ← HT sibling of core 0 (사용 금지)

# NIC NUMA 노드 확인
$ cat /sys/bus/pci/devices/0000:00:08.0/numa_node
0

# 올바른 startup.conf
cpu {
    main-core 0                        /* 관리 전용 */
    corelist-workers 1-3               /* NIC와 같은 NUMA, HT 제외 */
    skip-cores 0                       /* 기본값 유지 */
}

# 커널 부트 파라미터 (VPP 코어 격리)
GRUB_CMDLINE_LINUX="isolcpus=1-3 nohz_full=1-3 rcu_nocbs=1-3"

벡터 크기와 배치 처리 오해

VPP의 벡터 처리 모델에서 벡터 크기(VLIB_FRAME_SIZE)는 한 번에 처리되는 패킷 묶음의 크기입니다. 벡터가 클수록 I-cache 효율이 높아지지만, 지연는 증가합니다.

오해실제
벡터 크기가 클수록 항상 좋다처리량은 증가하지만 지연도 증가. 실시간 트래픽(VoIP 등)에서는 VLIB_FRAME_SIZE를 줄이는 것이 유리
벡터 크기를 임의로 조절할 수 있습니다입력 노드의 수신 버스트 크기(DPDK rx-burst)가 실질적 벡터 크기 결정. show runtime의 Vectors/Call로 확인
모든 노드가 동일한 벡터 크기를 처리분기 노드(classify, ACL)에서 벡터가 분할될 수 있음. show runtime에서 노드별 Vectors/Call 차이 확인
패킷이 없으면 CPU를 쉰다기본 DPDK 폴링은 항상 100% CPU 사용. poll-sleep-poll 또는 interrupt mode로 완화 가능 (아래 성능 최적화 참조)
벡터 크기 모니터링: show runtimeVectors/Call 값이 1에 가까우면 패킷이 산발적으로 도착하는 것이므로 벡터 처리의 이점이 줄어듭니다. 이 경우 배치 크기를 늘리거나(num-rx-desc 2048), 트래픽 패턴을 분석하여 폴링 주기를 조정하세요.

memif 연결 시 소켓 권한 문제

# 흔한 오류: Permission denied
vpp# create interface memif id 0 socket-id 1 slave
# create memif: connect error (Permission denied)

# 원인 진단
$ ls -la /run/vpp/
srwxrwx--- 1 root root 0 memif-chain.sock     ← 그룹 접근 필요

# 해결: 공통 그룹 사용
$ sudo groupadd vpp-memif
$ sudo usermod -aG vpp-memif vpp-user1
$ sudo usermod -aG vpp-memif vpp-user2

# startup.conf에서 그룹 지정
unix {
    gid vpp-memif
}

# 소켓 디렉터리 권한 확인 (실행 권한 필수)
$ sudo chmod 2770 /run/vpp/
$ sudo chgrp vpp-memif /run/vpp/

# 연결 상태 확인
vpp# show memif
interface memif1/0
  socket-id 1 id 0 mode ethernet
  status: connected                     ← 정상
  ring 0: region 0 num-s 2048 ...
  link up

L7 트러블슈팅 — HTTP 파싱 오류부터 워커 편중까지

L4 트러블슈팅이 패킷 드롭·재전송·MTU 같은 전송 계층 문제에 집중한다면, L7 트러블슈팅은 한 단계 더 위에서 시작합니다. 이 절은 운영에서 자주 마주치는 6가지 L7 증상을 골라, 증상 → 가설 → 진단 명령 → 해결 패턴 순으로 정리합니다.

관련 페이지:

증상별 진단 매트릭스

증상1차 의심진단 명령해결
특정 클라이언트만 400 폭증HTTP 파서 엄격성 / 헤더 한도show stat /http/parse_errors헤더 한도 상향 또는 클라이언트 수정
p99 지연만 튐워커 편중 / 캐시 미스show stat /http/in_flight per-workerRSS 재구성 또는 캐시 튜닝
5xx 단속 발생업스트림 실패 / 회로 차단show http gateway upstream업스트림 헬스체크 강화
HTTP/2 스트림 멈춤흐름 제어 윈도 고갈show http2 stream <id>SETTINGS_INITIAL_WINDOW_SIZE 상향
TLS 핸드셰이크 실패율 상승인증서 만료 / SNI 미일치show stat /tls/handshakes_total인증서 갱신 / SNI 설정
캐시 적중률 급락Vary 헤더 변화 / 키 폭증show http gateway cacheVary 정규화 / 키 설계 재검토

L7 pcap — vppctl trace + 외부 분석

VPP는 자체 패킷 트레이스(trace add)와 pcap 캡처(pcap trace)를 모두 제공합니다. L7 문제 해결에는 두 도구를 조합해야 합니다.

# 1) HTTP 게이트웨이 인터페이스에서 캡처
vppctl pcap trace rx tx max 5000 \
    intfc TenGigabitEthernet0/0/0 \
    file /tmp/http-debug.pcap \
    filter classify table 0 match l3 ip4 dst 192.0.2.10 \
                            l4 tcp dst-port 443

# 2) 캡처 시작 후 재현
curl -k -v https://192.0.2.10/api/v1/version

# 3) 캡처 종료
vppctl pcap trace off

# 4) Wireshark에서 분석
wireshark /tmp/http-debug.pcap
# - TLS pre-master secret 있으면 복호화 후 HTTP 메시지 확인
# - HTTP/2는 Wireshark가 자동 해석 (SETTINGS·HEADERS·DATA 프레임)

# 5) 그래프 노드 트레이스 (헤더 파싱 단계까지 추적)
vppctl trace add dpdk-input 100
vppctl show trace | grep -A 20 'http-static'

show 명령 카드

# 세션 레이어 상태
vppctl show session verbose 2          # 모든 활성 세션
vppctl show session thread 0 verbose   # 워커 0만

# HTTP/2 스트림 상세
vppctl show http2 conn
vppctl show http2 stream <conn-id> <stream-id>
# - state: open / half-closed / closed
# - recv_window / send_window
# - bytes_sent / bytes_recv

# TLS 세션
vppctl show tls
vppctl show tls openssl ctx 0
# - cipher / version / sni / alpn
# - resumption: full / psk / 0-rtt

# 게이트웨이 라우팅·캐시
vppctl show http gateway routes
vppctl show http gateway upstream
vppctl show http gateway cache top 20

# 워커 편중 진단
for i in 0 1 2 3; do
  echo "Worker $i:"
  vppctl show session thread $i | grep -c 'state ESTABLISHED'
done

자주 마주치는 증상 — 해결 레시피 4가지

레시피 1: 특정 vhost만 5xx

  1. rate(http_requests_total{status=~"5..", vhost="api.example.com"}[5m]) 추세 확인
  2. 같은 시간대 http_upstream_failures_total{upstream="api-backend-1"} 동반 상승 여부
  3. 업스트림 헬스체크 결과(show http gateway upstream)에서 응답 시간 분포 확인
  4. 해결: 업스트림 health check interval 단축, 회로 차단 임계 강화, 트래픽 일부를 백업 업스트림으로 이동

레시피 2: HTTP/2 스트림이 멈춤

  1. show http2 stream에서 send_window=0 확인
  2. 같은 연결의 다른 스트림도 같은 상태면 연결 윈도 고갈, 한 스트림만이면 스트림 윈도 고갈
  3. 대형 응답 BDP 계산: BDP = bandwidth × RTT. 100Mbps × 100ms = 1.25MB
  4. 해결: SETTINGS_INITIAL_WINDOW_SIZE를 BDP × 2 이상으로 설정. VPP CLI 또는 startup.conf의 http2 절

레시피 3: 워커 편중으로 한 워커만 100%

  1. vppctl show runtime에서 워커별 vector rate 비교 — 한 워커만 0.9 이상이면 편중
  2. show session thread N에서 활성 세션 수 비교
  3. 가설 1: NIC RSS 키가 비대칭 → show hardware-interfaces에서 RSS 큐 분포 확인
  4. 가설 2: 한 클라이언트가 단일 연결로 거대한 HTTP/2 스트림 폭주 → SETTINGS_MAX_CONCURRENT_STREAMS 하향
  5. 해결: RSS 대칭 해시(Toeplitz 키 0x6d5a) 적용, 또는 HAProxy 같은 L7 LB로 사전 분산

레시피 4: 캐시 적중률 급락

  1. show http gateway cache의 entries / bytes / evictions 추세 확인
  2. evictions 폭증 + 적중률 감소 → 캐시 크기 부족 또는 키 폭증
  3. 키 폭증 가설: 새 배포 후 Vary 헤더에 변동성 큰 헤더(예: User-Agent) 추가됨
  4. 해결: Vary 정규화, 캐시 크기 상향, 또는 stale-while-revalidate 도입으로 백그라운드 갱신
골든 시그널(Signal) 4종: 구글 SRE 책의 latency·traffic·errors·saturation을 VPP L7에 매핑하면 다음과 같습니다 — latency = http_request_duration_seconds p99, traffic = http_requests_total rate, errors = 5xx 비율, saturation = http_in_flight + 워커 vector rate. 이 네 가지만 모니터링해도 운영 사고의 80%는 즉시 감지할 수 있습니다.

Common Pitfalls

디버깅 보조 도구 — PG · nsim · BPF Trace Filter

VPP에는 장애 재현과 조건부 트레이스를 돕는 소규모 도구 세 개가 있습니다. 일상 운영에서 자주 언급되지 않지만 어려운 버그를 잡을 때 결정적인 역할을 합니다. 상시 관측 도구(perfmon/sFlow/IPFIX 등)는 관측성 · 원격 측정에서 다룹니다.

Packet Generator (PG) — 재현 주입

문제를 겪은 패킷 패턴을 외부 장비 없이 VPP 안에서 직접 재현하고 싶을 때 PG가 최적입니다. 헤더 조합을 스크립트로 정의하고, 원하는 비율로 특정 노드에 주입할 수 있어 엣지 케이스 회귀 테스트에도 적합합니다.

vpp# packet-generator new {
  name bug-repro
  limit 100
  node ip4-input
  size 64-1500
  data { IP4: 10.0.0.1 -> 10.0.0.2
         UDP: 1234 -> 5678
         incrementing 100 }
}
vpp# trace add pg-input 100
vpp# packet-generator enable-stream bug-repro
vpp# show trace

장점은 외부 트래픽 생성기(TRex 등) 없이도 패킷 레벨 정확도로 동일 시나리오를 재현할 수 있다는 점입니다. 단점은 pps가 제한적이라 성능 재현 테스트에는 부적합합니다.

nsim — 네트워크 지연 시뮬레이션

nsim은 인터페이스 송신 경로에 지연·대역폭 한계·손실을 주입해 WAN 환경을 재현합니다. 리눅스 netem의 VPP 버전으로, TCP 혼잡 제어가 특정 조건에서 어떻게 동작하는지 검증할 때 결정적입니다.

vpp# nsim output-feature enable-disable <if>
vpp# set nsim delay 100.0 ms bandwidth 10.0 mbit packets-per-drop 1000
vpp# show nsim

실전 시나리오 예:

BPF Trace Filter — 조건부 트레이스

일반 trace add는 지정 노드에 들어오는 모든 패킷을 캡처합니다. 트래픽이 많으면 금세 버퍼가 가득 차고, 정작 문제 패킷은 놓치기 쉽습니다. BPF Trace Filter는 tcpdump 문법으로 트레이스 대상을 정밀 필터링합니다.

vpp# set trace filter function-name vlib_trace_filter_bpf      expr "host 192.0.2.100 and tcp port 443"
vpp# trace add dpdk-input 1000
# 문제 재현 후
vpp# show trace

BPF 식은 libpcap 문법을 그대로 사용하므로, tcpdump -d로 익숙한 사람은 바로 쓸 수 있습니다. 고PPS 운영 환경에서 특정 플로우만 정밀 관찰할 수 있어 진단 시간이 크게 단축됩니다.

도구 선택 요약

상황권장
특정 패킷 시나리오 재현Packet Generator + show trace
WAN 조건 아래서 버그 검증nsim + iperf3
폭주 중인 트래픽에서 한 플로우만 보기BPF Trace Filter
노드 성능 hot spot 찾기perfmon topdown
워커 간 시간 분포 보기이벤트 로그 + G2