배경
1G 환경에서 istio가 패킷 포워딩을 처리하는 과정에서 packet drop이 많이 발생하여, 이를 해결하는 과정을 기록하였습니다.
1. 튜닝 전 테스트
보통 서비스를 위한 네트워크의 패킷 유실율은 10^(-6) = 0.000001% 이하여야 합니다.
- 물리 인터페이스에서 약 0.6% 드랍 발생
- istio의 calico rx/tx에서 6%, 3.5% 드랍 발생.

- ethtool 통계 확인
- fx_fifo_errors: NIC의 FIFO 큐에서 Ring buffer로 옮기기 전에 큐가 가득 차서 발생한 에러
- rx_missed_errors: FIFO 큐 또는 Ring buffer가 넘쳐서 패킷이 드랍된 횟수
# ethtool -S eno1
rx_missed_errors: 19882559
...
rx_fifo_errors: 19882559
# /Document/networking/statistics
What: /sys/class/<iface>/statistics/rx_missed_errors
...
Description:
Indicates the number of received packets that have been missed
due to lack of capacity in the receive side. See the network
driver for the exact meaning of this value.
- SoftIRQ
# awk '{for (i=1; i<=NF; i++) printf strtonum("0x" $i) (i==NF?"\n":" ")}' /proc/net/softnet_stat | column -t
# 수신 프레임 time_squeeze cpu_number
512787 0 3 0 0 0 0 0 0 0 0 0 0
495932 0 3 0 0 0 0 0 0 0 0 0 1
476620 0 3 0 0 0 0 0 0 0 0 0 2
522209 0 3 0 0 0 0 0 0 0 0 0 3
- NIC utilization 확인
- NIC의 대역폭은 여유가 있는데 패킷 드랍이 발생한 상황입니다.
# sar -n DEV 1
10:47:13 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
10:47:15 PM lo 505.50 505.50 71.79 71.79 0.00 0.00 0.00 0.00
10:47:15 PM eno1 215271.50 240560.50 73207.84 82766.38 0.00 0.00 1.50 67.80
- 결론
- CPU가 NIC buffer에서 패킷을 polling하는 속도가 패킷 유입 속도를 따라가지 못해서 드랍이 발생했습니다.
2. OS 튜닝
TCP 커널 버퍼 수정
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65536 16777216
net.core.netdev_max_backlog=5000
net.core.netdev_budget=1000
net.core.netdev_budget_usecs=10000
ring buffer 수정
- ethtool -G eno1 rx 4096 tx 4064 명령어로 변경 가능하지만, 재부팅 시 초기화 됩니다.
# ethtool -g eno1
Ring parameters for eno1:
Pre-set maximums:
RX: 4096
RX Mini: n/a
RX Jumbo: n/a
TX: 4096
Current hardware settings:
RX: 4096
RX Mini: n/a
RX Jumbo: n/a
TX: 4096
CPU frequency 변경
- cpupower frequency-set --governor performance로 수정할 수 있으며 재부팅 시 초기화됩니다.
# cpupower frequency-info
analyzing CPU 0:
...
current CPU frequency: 2.80 GHz (asserted by call to hardware)
* Packet fragment 발생 여부
- Calico에서 VxLAN이나 IPIP를 사용하는 경우 outer header가 추가로 붙어서 물리 인터페이스의 MTU를 초과할 수 있습니다.
- 그러나 Calico interface의 default MTU는 IPIP인 경우 1480, VxLANㅇ니 경우 1450으로 맞춰서 설정됩니다.
- 따라서 단편화에 대한 해당 사항은 없습니다.
CPU - NIC 매핑(NUMA aware)
- irqbalance 데몬이 켜져 있는 상태라 패킷이 NIC로 인입되면 모든 코어로 균일하게 irq를 보냅니다.
(2 소켓 CPU 서버에 NIC가 단중화라 패킷이 균일하게 처리되면 QPI를 거치게 되므로 성능 저하가 발생)
# mpstat -P ALL 1
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 5.84 0.00 1.09 0.00 0.00 1.54 0.00 0.00 0.00 91.53
Average: 0 5.40 0.00 0.95 0.06 0.00 1.97 0.00 0.00 0.00 91.62
Average: 1 5.95 0.00 0.98 0.00 0.00 0.77 0.00 0.00 0.00 92.30
Average: 2 5.40 0.00 0.68 0.00 0.00 0.53 0.00 0.00 0.00 93.39
Average: 3 5.46 0.00 0.74 0.00 0.00 0.44 0.00 0.00 0.00 93.36
Average: 4 7.00 0.00 1.18 0.00 0.00 1.12 0.00 0.00 0.00 90.69
Average: 5 5.69 0.00 0.77 0.00 0.00 1.74 0.00 0.00 0.00 91.80
Average: 6 6.70 0.00 1.56 0.00 0.00 1.59 0.00 0.00 0.00 90.14
Average: 7 6.57 0.00 1.66 0.00 0.00 1.60 0.00 0.00 0.00 90.17
Average: 8 6.10 0.00 1.36 0.00 0.00 1.30 0.00 0.00 0.00 91.23
Average: 9 1.53 0.00 0.24 0.00 0.00 28.17 0.00 0.00 0.00 70.06
Average: 10 7.66 0.00 1.74 0.00 0.00 1.57 0.00 0.00 0.00 89.03
Average: 11 6.31 0.00 1.48 0.00 0.00 2.22 0.00 0.00 0.00 89.98
Average: 12 7.15 0.00 1.51 0.00 0.00 1.21 0.00 0.00 0.00 90.13
- NIC RSS 설정 확인
# ethtool -x eno1
RX flow hash indirection table for eno1 with 8 RX ring(s):
0: 0 0 0 0 0 0 0 0
8: 0 0 0 0 0 0 0 0
16: 1 1 1 1 1 1 1 1
24: 1 1 1 1 1 1 1 1
32: 2 2 2 2 2 2 2 2
40: 2 2 2 2 2 2 2 2
48: 3 3 3 3 3 3 3 3
56: 3 3 3 3 3 3 3 3
64: 4 4 4 4 4 4 4 4
72: 4 4 4 4 4 4 4 4
80: 5 5 5 5 5 5 5 5
88: 5 5 5 5 5 5 5 5
96: 6 6 6 6 6 6 6 6
104: 6 6 6 6 6 6 6 6
112: 7 7 7 7 7 7 7 7
120: 7 7 7 7 7 7 7 7
- irqbalance 데몬을 stop하고 인터럽트 요청이 동일한 NUMA의 CPU를 바라보도록 설정합니다.
- NUMA 확인
# ethtool -i eno1
...
bus-info: 0000:63:00.0
# lspci -vvv | grep Eth -A 7
63:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
...
NUMA node: 0
# lscpu
NUMA:
NUMA node(s): 2
NUMA node0 CPU(s): 0-31,64-95
NUMA node1 CPU(s): 32-63,96-127
- 인터럽트가 어떤 코어에 쏠리는지 확인
- 32코어 CPU의 NUMA에 맞게 인터럽트 요청이 되고 있음.
# cat /proc/interrupts | grep eno1
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 CPU16 CPU17 CPU18 CPU19 CPU20 CPU21 CPU22 CPU23 CPU24 CPU25 CPU26 CPU27 CPU28 CPU29 CPU30 CPU31 CPU32 CPU33 CPU34 CPU35 CPU36 CPU37 CPU38 CPU39 CPU40 CPU41 CPU42 CPU43 CPU44 CPU45 CPU46 CPU47 CPU48 CPU49 CPU50 CPU51 CPU52 CPU53 CPU54 CPU55 CPU56 CPU57 CPU58 CPU59 CPU60 CPU61 CPU62 CPU63 CPU64 CPU65 CPU66 CPU67 CPU68 CPU69 CPU70 CPU71 CPU72 CPU73 CPU74 CPU75 CPU76 CPU77 CPU78 CPU79 CPU80 CPU81 CPU82 CPU83 CPU84 CPU85 CPU86 CPU87 CPU88 CPU89 CPU90 CPU91 CPU92 CPU93 CPU94 CPU95 CPU96 CPU97 CPU98 CPU99 CPU100 CPU101 CPU102 CPU103 CPU104 CPU105 CPU106 CPU107 CPU108 CPU109 CPU110 CPU111 CPU112 CPU113 CPU114 CPU115 CPU116 CPU117 CPU118 CPU119 CPU120 CPU121 CPU122 CPU123 CPU124 CPU125 CPU126 CPU127
225: 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904512-edge eno1
226: 83502188 0 0 0 0 0 12 0 0 0 0 229624 0 0 106538 0 0 0 0 0 0 310412 0 0 115826 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8725845 0 0 0 0 0 0 0 0 0 0 356583 0 0 92022 0 0 0 0 0 0 41963 0 0 120484 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904513-edge eno1-TxRx-0
227: 0 0 4329 0 22058 79974858 0 5876 0 29406 0 40150 8842 0 39321 0 0 0 9747 0 0 63250 11937 0 65301 0 0 0 12216 0 12576 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 144 0 6323 0 17652 0 0 13164 0 24681 14655 36264 6812 0 41162 0 0 0 1105 0 711 53743 1669879 0 72514 0 0 0 853 0 7183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904514-edge eno1-TxRx-1
228: 8595276 0 3390 0 1293157 0 0 8021 7 1689644 0 853834 9803 0 3141289 0 0 0 339 0 0 1527820 10156 0 3137750 0 0 0 2679 0 9783 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 45519649 0 8355 0 2862458 0 0 8751 11 270635 1967 1008413 7152 0 3922754 0 0 0 0 0 2634 7118787 12291 0 1856440 0 0 0 138 0 3169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904515-edge eno1-TxRx-2
229: 0 0 19991 0 1195216 812 0 24327 0 6518631 0 1217322 78370 0 6420069 0 0 0 0 0 0 10194227 337759 0 3374695 0 0 0 32163 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5497294 0 7467 0 477793 0 0 12223 0 2445081 0 41761718 1434752 0 1591891 0 0 0 180617 0 0 4848387 140226 0 2481320 0 0 0 0 0 5732 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904516-edge eno1-TxRx-3
230: 0 0 258640 0 138578 815337 0 1302684 0 418622 8 272004 134173 0 610410 0 0 0 21494 0 0 552005 55938 0 756485 0 0 0 645 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77610 0 12155 0 112490 0 0 45203 0 204021 0 574545 45856 0 449836 0 22684381 0 0 0 39956935 819907 98211 0 626075 0 0 0 1661 0 3159 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904517-edge eno1-TxRx-4
231: 0 0 7193 0 1112928 9224 0 92397 0 461768 0 11123588 52942 0 3207074 0 0 0 1605 0 0 3697806 1502278 0 4287738 0 0 0 3464 0 772 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1003157 0 67971 0 373156 0 0 3289 0 1470978 1381 1873520 118474 0 2581217 0 0 0 155 0 5594 8860813 325490 0 27589217 0 0 0 0 0 1508 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904518-edge eno1-TxRx-5
232: 0 0 1351 0 543455 391 0 21013 0 269761 0 684262 8257 0 1534331 0 0 0 2518911 0 0 1876412 13776 0 1627170 0 1377 0 9261 0 7298 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12120260 0 3143 56453633 35954 0 0 6164 0 1808253 0 701702 62365 0 1899029 0 0 0 189 0 5465 2319681 917657 0 1046856 0 0 0 3743 0 3741 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904519-edge eno1-TxRx-6
233: 0 0 2949 0 1587065 89 0 5255 0 1796928 0 1962632 8953 7 6893264 0 0 0 1603 0 0 5698540 151787 0 22071018 0 0 0 1347 0 5294 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16594 0 9495 0 500265 0 0 272862 0 638106 16171 10892973 12784 0 4198715 0 0 0 0 0 821 6926534 193808 0 2916659 8371497 0 0 528 0 42622 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI 51904520-edge eno1-TxRx-7
테스트 결과
- RX: 221,000,000 p/s (3.03%)
- Drop: 6,690,000 p/s
- TX: 216,000,000 p/s (1.6%)
- Drop: 3,400,000 p/s
3. Istio 설정
확인해보니 설정이 이상하게 되어있어서 3-way handshake가 과도하게 발생하였습니다. 그리고 IRQ affinity를 설정과 일치하도록 istio를 NUMA aware하게 배포하고 concurrency를 조정합니다.
DestinationRule 설정
- loadBalancer.simple: (로그밸런싱 알고리즘)
- UNSPECIFIED: No LB (default
- RANDOM: random healthy host. 헬스체크 정책이 없다면 RR보다 성능 좋음.
- PASSTHROUGH: Envoy는 by-pass하고 외부 LB 부하 분산 하겠다 인듯.
- ROUND_ROBIN: Basic and unsafe.
- LEAST_REQUEST: 패킷 처리가 지연되는 Pod에 패킷을 덜 보냄. 모든 케이스에서 RR보다 성능 좋음.
spec:
host:
trafficPolicy:
loadBalancer:
simple: LEAST_REQUEST
connectionPool:
http:
http1MaxPendingRequests: 256000
http2MaxRequests: 0
maxRequestsPerConnection: 0
idleTimeout: 300s
tcp:
connectTimeout: 10s
maxConnectionDuration: 600s
maxConnections: 0
tls:
mode: SIMPLE
insecureSkipVerify: true
- 적용 확인
kubectl exec <pod-name> -c istio-proxy -n <namespace> -- curl -s localhost:15000/config_dump | grep -A 50 "<host_url>"
Concurrency 설정
- envoy가 몇개의 worker thread를 사용할지 concurrency로 설정합니다.
- envoy의 각 스레드는 connection data를 TLS(Thread Local Storage)라는 메모리 공간에 저장합니다.
- worker thread이 큰 상황에서 connection이 많아지면 TLS에서 사용하는 메모리가 과하게 많아집니다.
- 벤치마크 성능에서는 concurrecy를 낮게 설정합니다. 따라서 concurrency를 NIC queue개수와 맞추어 8로 설정했습니다.

- NIC 물리 queue 개수 확인
# ethtool -l eno1
Channel parameters for eno1:
Pre-set maximums:
RX: n/a
TX: n/a
Other: 1
Combined: 8
Current hardware settings:
RX: n/a
TX: n/a
Other: 1
Combined: 8
- istio concurrency 설정 확인
# kubectl exec -n <namespace> <istio-pod> -c istio-proxy -- curl localhost:15000/server_info
"concurrency": 128
NUMA aware 설정
- 우선 kubelet에 topology manager 설정이 추가되어야 합니다.
- OS와 kubelet, IRQ 처리 등을 위한 코어를 reserve합니다.
- Istio가 PCI에서 NIC과 인정하도록 배포합니다.
- 실제 사용할 topology manager policy는 best-effort/restircted + prefer-closet-numa-nodes를 고려합니다.
# vim /etc/kubernetes/kubelet.env
...
--cpu-manager-policy=static \
--topology-manager-policy=single-numa-node \ # 단순 테스트용
--reserved-cpus=0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,72
# systemctl stop kubelet
# rm /var/lib/kubelet/cpu_manager_state
# systemctl start kubelet
- kubelet 설정 이후 istio의 QoS Class가 Quaranteed로 배포되면 .
- 적용 확인
- istio의 pid로 CPU 마스킹을 확인합니다.
# cat /proc/<pid>/status
...
Cpus_allowed: 00000000,000003c0,00000000,000003c0
Cpus_allowed_list: 13-16,77-80
테스트 결과
- RX: 53,900,000 p/s (1.17%)
- Drop: 925,000 p/s
- TX: 71,900,000 p/s (0.3%)
- Drop: 227,000 p/s
4. Calico eBPF 설정
felixConfiguration에 eBPF를 적용하면 iptables 대신 eBPF에서 패킷을 후킹하여 calico interface로 bypass합니다.

- 적용 방법
1. calico-node pod의 upgrade-iam과 calico-node 컨테이너에 kube-apiserver에 대한 환경변수를 추가합니다.
- name: KUBERNETES_SERVICE_HOST
value: "<Master IP>"
- name: KUBERNETES_SERVICE_PORT
value: "6443"
2. kube-proxy disable
kubectl patch ds -n kube-system kube-proxy -p '{"spec":{"template":{"spec":{"nodeSelector":{"non-existent": "true"}}}}}'
3. felix bpf enable 후 노드 재부팅
kubectl patch felixconfiguration default --type merge --patch '{"spec": {"bpfEnabled": true}}'
4. 적용 확인
# kubectl exec -it -n kube-system calico-node-xxxxx -- calico-node -bpf routes dump
테스트 결과
- RX: 91,500,000 p/s
- Drop: 0 p/s
- TX: 313,000,000 p/s
- Drop: 0 p/s
'System Engineering > Network' 카테고리의 다른 글
| InfiniBand에 대한 이해 (1) - 구조와 헤더 (0) | 2025.06.28 |
|---|---|
| Cloud를 위한 VXLAN part.1 - LAN 통신 (0) | 2023.10.10 |
| ipTIME과 Mikrotik RouterOS로 VPN 구축하기 (0) | 2021.03.13 |