26M29d

Young-Kyoo Kim·2026년 5월 29일

strong_bias가 나오면, 바로 전 노드에 튜닝값을 뿌리기보다 원인이 IRQ/RSS 편중인지, Cilium/터널/flow hash 특성인지, softirq budget 부족인지, NIC ring 부족인지를 분리해서 한 노드에서 검증하는 게 안전합니다.

0. 먼저 판단 기준

strong_bias 자체만으로는 장애 원인이라고 단정하지 마세요. 아래가 같이 있어야 의미가 큽니다.

strong_bias
+ /proc/net/softnet_stat time_squeeze/s 증가
+ ethtool RX no_buffer / missed / queue drop 증가
+ TCP retransmission / timeout 증가
+ MinIO 5xx / quorum warning 시각과 일치

Linux RSS는 flow hash를 기반으로 packet을 receive queue에 분산합니다. 따라서 특정 큰 flow, tunnel encapsulation, LACP hash 편중이 있으면 모든 core가 active여도 특정 core 쏠림이 생길 수 있습니다. RSS/RPS/RFS/XPS는 멀티코어에서 네트워크 처리를 병렬화하기 위한 기능이고, RSS는 일반적으로 IP/L4 header hash와 indirection table로 queue를 고릅니다. (커널 도메인)


1. 가장 먼저: strong_bias가 어느 계층에서 생겼는지 분리

1-1. IRQ bias인지 확인

bond1의 slave NIC 이름을 넣어서 확인합니다.

cat /proc/net/bonding/bond1

# 예: ens3f0, ens3f1 또는 enp65s0f0, enp65s0f1
SLAVES="ens3f0 ens3f1"

for dev in $SLAVES; do
  echo "### $dev"
  ethtool -l $dev
  ethtool -x $dev | head -80
  ethtool -S $dev | egrep -i 'rx.*drop|drop|discard|miss|missed|no.*buf|buffer|alloc|err|crc|fifo|timeout'
done

grep -E 'ens3f0|ens3f1|ice|i40e|ixgbe' /proc/interrupts

해석은 이렇게 합니다.

결과의미
/proc/interrupts도 특정 core에 몰림IRQ/RSS/affinity 문제 가능성 큼
/proc/interrupts는 균등한데 NET_RX만 편중softirq/RPS/Cilium/tunnel/flow hash 쪽 가능성
slave NIC 한쪽만 RX/drop/IRQ가 많음LACP hash 또는 switch port-channel 편중 가능성
특정 RX queue drop/no_buffer 증가NIC ring/driver/RX queue 처리 병목 가능성

1-2. time_squeeze와 같이 증가하는지 확인

strong_bias가 나와도 time_squeeze/s=0, dropped/s=0이면 장애 관련성은 약합니다.

awk '{
  printf "%d %d %d %d\n", NR-1, strtonum("0x"$1), strtonum("0x"$2), strtonum("0x"$3)
}' /proc/net/softnet_stat > /tmp/softnet.1

sleep 10

awk '{
  printf "%d %d %d %d\n", NR-1, strtonum("0x"$1), strtonum("0x"$2), strtonum("0x"$3)
}' /proc/net/softnet_stat > /tmp/softnet.2

join <(sort -n /tmp/softnet.1) <(sort -n /tmp/softnet.2) \
| awk '{
  printf "CPU%-3d processed/s=%12.1f dropped/s=%8.3f squeeze/s=%8.3f\n",
    $1, ($5-$2)/10, ($6-$3)/10, ($7-$4)/10
}' | sort -k4 -nr | head -30

Red Hat 문서 기준으로 /proc/net/softnet_stat의 두 번째 컬럼은 backlog queue full로 인한 drop이고, 세 번째 컬럼은 한 번의 NAPI polling cycle에서 softirq가 모든 packet을 처리하지 못한 횟수입니다. 두 번째 컬럼이 증가하면 backlog queue 쪽, 세 번째 컬럼이 증가하면 softirq 처리 시간/budget 쪽을 봅니다. (Red Hat Documentation)


2. 조치 순서

2-1. irqbalance부터 확인

가장 먼저 볼 것은 irqbalance입니다.

systemctl status irqbalance

꺼져 있으면 우선 켜는 쪽을 검토하세요.

sudo systemctl enable --now irqbalance

Red Hat 문서도 irqbalance가 CPU load를 보고 interrupt를 core 간 이동시키며, 꺼져 있으면 CPU0 등에 interrupt가 몰려 network/storage performance 저하, packet loss, 지연이 생길 수 있다고 설명합니다. (Red Hat Documentation)

다만 이미 운영팀에서 수동 IRQ affinity를 세팅해 둔 경우에는 irqbalance를 켜면 설정이 바뀔 수 있으니, 먼저 현재 affinity를 백업하세요.

mkdir -p /root/irq-backup

for irq in $(grep -E 'ens3f0|ens3f1|ice|i40e|ixgbe' /proc/interrupts | awk -F: '{print $1}' | tr -d ' '); do
  echo -n "$irq " >> /root/irq-backup/smp_affinity_list.before
  cat /proc/irq/$irq/smp_affinity_list >> /root/irq-backup/smp_affinity_list.before
done

2-2. RSS queue 수와 indirection table 확인

96 core 모두 active라고 해도 RSS indirection table이 불균등하면 특정 queue/core가 많이 받을 수 있습니다.

for dev in $SLAVES; do
  echo "### $dev channels"
  ethtool -l $dev

  echo "### $dev RSS indirection"
  ethtool -x $dev | head -120
done

확인 포인트:

Combined / RX queue 수가 충분한가?
RSS indirection table이 특정 queue에 과도하게 몰려 있지 않은가?
두 slave NIC의 RSS 설정이 서로 다른가?

문제가 있어 보이면, 테스트 노드 1대에서만 RSS indirection table을 균등화해 봅니다.

# 예: combined queue가 96이면
sudo ethtool -X ens3f0 equal 96
sudo ethtool -X ens3f1 equal 96

# 적용 후 확인
ethtool -x ens3f0 | head -120
ethtool -x ens3f1 | head -120

RSS indirection table은 ethtool로 조회/수정 가능하며, queue별 상대 가중치를 조정할 수 있습니다. (커널 도메인)

주의할 점은 ethtool -X 지원 범위가 NIC/driver/펌웨어에 따라 다르고, NetworkManager나 부팅 후 스크립트에 의해 원복될 수 있다는 점입니다. 적용은 반드시 한 노드에서만 비교하세요.


2-3. Cilium이 tunnel mode인지 확인

Cilium이 VXLAN/Geneve encapsulation mode라면, node-to-node 트래픽이 UDP tunnel flow로 보이면서 RSS hash entropy가 줄어들 수 있습니다. Cilium 문서상 encapsulation mode에서는 노드 간 트래픽이 VXLAN 또는 Geneve UDP tunnel로 캡슐화됩니다. (Cilium Docs)

확인:

kubectl -n kube-system exec ds/cilium -- cilium config view \
  | egrep -i 'routing-mode|tunnel|vxlan|geneve|encapsulation'

또는 Cilium ConfigMap:

kubectl -n kube-system get cm cilium-config -o yaml \
  | egrep -i 'routing-mode|tunnel|vxlan|geneve|encapsulation'

해석:

Cilium 모드strong_bias 가능성
native routing / direct routingRSS가 pod flow를 더 잘 분산할 가능성
VXLAN/Geneve tunnelouter node-to-node UDP flow 중심으로 hash되어 특정 queue 편중 가능
암호화/IPsec/WireGuard 사용flow 분산/CPU 위치가 더 복잡해질 수 있음

만약 tunnel mode이고 특정 노드 간 MinIO internode traffic이 크다면, strong_bias는 “NIC 설정 오류”라기보다 tunnel + elephant flow 특성일 수 있습니다. 이 경우 단순 IRQ affinity보다 Cilium routing mode, native routing 가능성, tunnel RSS 지원 여부, MinIO internode flow 수를 같이 봐야 합니다.


2-4. softnet time_squeeze/s가 같이 증가하면 netdev_budget 조정

현재 dropped=0이라고 하셨으므로, 우선순위는 net.core.netdev_max_backlog가 아닙니다.
time_squeeze/s가 장애 시각에 증가한다면 아래를 봅니다.

sysctl net.core.netdev_budget
sysctl net.core.netdev_budget_usecs

기본이 예를 들어:

net.core.netdev_budget = 300
net.core.netdev_budget_usecs = 2000

이면, 테스트 노드 1대에서만 2배로 올려봅니다.

sudo sysctl -w net.core.netdev_budget=600
sudo sysctl -w net.core.netdev_budget_usecs=4000

Red Hat도 softirq가 한 NAPI polling cycle에서 packet을 다 가져오지 못하면 net.core.netdev_budgetnet.core.netdev_budget_usecs를 조정해 한 cycle에서 처리할 packet 수와 시간을 늘리는 절차를 제시합니다. (Red Hat Documentation)

적용 후 확인:

# 10초 단위로 before/after 비교
/tmp/netrx-softnet-bias.py

nstat -az | egrep 'TcpRetransSegs|TCPSynRetrans|TcpTimeouts|TCPFastRetrans|TCPSlowStartRetrans|TCPLostRetransmit'

for dev in $SLAVES; do
  ethtool -S $dev | egrep -i 'rx.*drop|drop|discard|miss|missed|no.*buf|buffer|alloc'
done

기대하는 효과:

time_squeeze/s 감소
TCP retransmission 감소
MinIO timeout/5xx 감소
CPU softirq가 과도하게 올라가지 않음

주의할 점:

budget을 너무 키우면 softirq가 CPU를 오래 점유
→ MinIO user thread scheduling 지연 가능
→ kubelet/container runtime 반응 지연 가능

그래서 600/4000 정도로 시작하고, 효과와 부작용을 본 뒤에만 더 올리는 게 좋습니다.


2-5. NIC RX ring은 “driver drop/no_buffer가 있을 때만”

아래 counter가 증가하면 RX ring을 봅니다.

for dev in $SLAVES; do
  echo "### $dev"
  ethtool -g $dev
  ethtool -S $dev | egrep -i 'rx_queue_.*drop|rx.*drop|rx_no.*buffer|rx_missed|rx_discards|alloc'
done

rx_queue_*_drops, rx_no_buffer, rx_missed, discard가 증가하고, 현재 RX ring이 최대값보다 낮으면 테스트 노드에서 올려볼 수 있습니다.

# 예시. 실제 maximum은 ethtool -g 결과 확인
sudo ethtool -G ens3f0 rx 4096
sudo ethtool -G ens3f1 rx 4096

Red Hat 문서도 high-speed network에서 ring buffer가 작으면 packet drop/performance degradation이 날 수 있고, drop/discard가 높으면 ring buffer 증설이 도움이 될 수 있다고 설명합니다. 단, driver에 따라 ring buffer 변경 시 네트워크가 짧게 끊길 수 있습니다. (Red Hat Documentation)

softnet dropped=0이고 NIC driver drop도 없으면 RX ring 증설은 우선순위가 낮습니다.


2-6. RPS는 “RSS로 충분하지 않을 때”만 조심스럽게

96 core가 모두 active이고 hardware RSS queue도 충분하다면 RPS는 1순위가 아닙니다. Red Hat 문서도 multiple queue NIC에서는 RSS가 기본적으로 receive queue를 CPU에 매핑하므로 RSS와 RPS를 동시에 설정해도 일반적으로 이득이 크지 않고, RPS는 hardware queue 수가 CPU보다 적을 때 도움이 될 수 있다고 설명합니다. (Red Hat Documentation)

다만 다음 조건이면 RPS를 테스트할 만합니다.

Cilium tunnel mode라 outer flow hash 때문에 특정 RX queue에 몰림
또는 RX queue 수가 실제 core 수보다 훨씬 적음
또는 IRQ는 특정 queue에 몰리는데 softirq를 같은 NUMA 내 여러 core로 흩뿌리고 싶음

RPS 상태 확인:

for dev in $SLAVES; do
  echo "### $dev"
  for q in /sys/class/net/$dev/queues/rx-*; do
    echo -n "$q rps_cpus="
    cat $q/rps_cpus
  done
done

기본값이 0이면 RPS disabled입니다.

RPS를 켤 때는 전체 96 core를 무작정 넣기보다, 해당 NIC가 붙은 NUMA node의 CPU만 쓰는 것이 보통 더 안전합니다.

cat /sys/class/net/ens3f0/device/numa_node
lscpu -e=CPU,NODE,CORE,SOCKET,ONLINE | column -t

예를 들어 NIC가 NUMA node 0이고 node 0 CPU가 0-47이라면, 해당 범위의 CPU mask를 계산해서 rx queue에 넣습니다. 다만 RPS는 inter-processor interrupt 비용을 추가하므로, 반드시 한 노드에서만 비교해야 합니다. Red Hat 문서도 RPS가 hardware RSS와 달리 software level에서 동작하고 inter-processor interrupt를 도입한다고 설명합니다. (Red Hat Documentation)


2-7. LACP / bond hash 편중 확인

bond1이 LACP layer3+4라고 해도 단일 flow는 한 slave로만 갑니다. 따라서 MinIO internode 대형 flow 몇 개가 있으면 slave NIC 한쪽 또는 특정 RSS queue에 몰릴 수 있습니다.

확인:

cat /proc/net/bonding/bond1

sar -n DEV,EDEV 1

for dev in $SLAVES; do
  echo "### $dev"
  ip -s -s link show dev $dev
  ethtool -S $dev | egrep -i 'rx_packets|tx_packets|rx_bytes|tx_bytes|drop|miss|buffer'
done

bond1의 slave 간 RX bytes/packets가 크게 다르면:

스위치 port-channel hash 정책
bond xmit_hash_policy
MinIO node-to-node flow 수
Cilium tunnel outer flow 구조
특정 노드 간 elephant flow

를 같이 봐야 합니다.

Linux 쪽 bond 송신 hash만 바꿔도 수신 방향은 스위치 hash 정책의 영향을 받습니다. 따라서 RX 편중이면 서버 설정만으로 완전히 해결되지 않을 수 있습니다.


2-8. Intel NIC라면 BIOS/메모리/전원 설정도 확인

Intel E800 계열 ice driver 문서에는 receive stress 상황에서 PCIe/DMA transaction latency가 커지면 packet buffering 시간에 영향을 줘 drop이 생길 수 있으며, workload에 영향이 있다면 물리 메모리 구성과 BIOS/UEFI Performance profile을 확인하라는 내용이 있습니다. (커널 문서)

현재 500GB 노드에서 global OOM/xfs_inode 이슈도 같이 있었으니, 아래를 같이 보세요.

dmesg -T | egrep -i 'GFP_ATOMIC|page allocation failure|skb|oom-kill|ice|i40e|ixgbe|reset|hang|timeout'

grep -E 'MemAvailable|Slab|SReclaimable|SUnreclaim|KReclaimable' /proc/meminfo

cat /proc/pressure/memory

특히 timeout 시점에 GFP_ATOMIC allocation failure, skb allocation, rx_no_buffer, time_squeeze가 같이 나오면, 단순 network tuning보다 500GB 노드의 memory headroom 문제가 더 우선입니다.


3. 제가 권하는 실제 적용 순서

1단계: 한 노드에서 10초 delta 재확인

장애가 있었던 500GB 노드 중 1대를 고릅니다.

/tmp/netrx-softnet-bias.py

for dev in $SLAVES; do
  echo "### $dev"
  ethtool -S $dev | egrep -i 'rx.*drop|drop|discard|miss|missed|no.*buf|buffer|alloc|err|crc|fifo|timeout'
done

nstat -az | egrep 'TcpRetransSegs|TCPSynRetrans|TcpTimeouts|TCPFastRetrans|TCPSlowStartRetrans|TCPLostRetransmit'

2단계: irqbalance / affinity 확인

systemctl status irqbalance

for irq in $(grep -E 'ens3f0|ens3f1|ice|i40e|ixgbe' /proc/interrupts | awk -F: '{print $1}' | tr -d ' '); do
  echo -n "IRQ=$irq affinity="
  cat /proc/irq/$irq/smp_affinity_list
done

비정상적으로 특정 core만 affinity에 들어가 있으면 우선 이걸 풀어야 합니다.

3단계: RSS table 균등화 테스트

for dev in $SLAVES; do
  ethtool -l $dev
  ethtool -x $dev | head -120
done

문제가 있으면:

sudo ethtool -X ens3f0 equal 96
sudo ethtool -X ens3f1 equal 96

적용 후 다시:

/tmp/netrx-softnet-bias.py

4단계: time_squeeze/s가 있으면 budget 2배 테스트

sysctl net.core.netdev_budget net.core.netdev_budget_usecs

sudo sysctl -w net.core.netdev_budget=600
sudo sysctl -w net.core.netdev_budget_usecs=4000

효과 없거나 CPU softirq가 과도해지면 즉시 롤백합니다.

sudo sysctl -w net.core.netdev_budget=300
sudo sysctl -w net.core.netdev_budget_usecs=2000

실제 원래값은 적용 전 sysctl 출력값을 저장해 두세요.

5단계: NIC driver drop이 있으면 RX ring 증설

for dev in $SLAVES; do
  ethtool -g $dev
done

최대값이 4096이고 현재가 1024 이하라면 테스트:

sudo ethtool -G ens3f0 rx 4096
sudo ethtool -G ens3f1 rx 4096

6단계: Cilium tunnel이면 native/direct routing 가능성 검토

kubectl -n kube-system exec ds/cilium -- cilium config view \
  | egrep -i 'routing-mode|tunnel|vxlan|geneve'

VXLAN/Geneve tunnel이면 strong_bias가 flow hash 특성일 수 있으므로, 장기적으로는 Cilium native routing, BGP 기반 podCIDR 라우팅, DSR/NodePort path, MTU, tunnel RSS 지원 여부를 같이 봐야 합니다.


4. 상황별 처방 요약

관찰 결과우선 조치
IRQ도 특정 core에 몰림irqbalance, IRQ affinity, RSS queue/indirection 확인
IRQ는 균등한데 NET_RX만 편중RPS/Cilium/tunnel/flow hash 확인
time_squeeze/s 증가netdev_budget, netdev_budget_usecs 2배 테스트
softnet dropped/s 증가netdev_max_backlog 증가 검토
NIC rx_no_buffer, rx_missed, rx_queue_drop 증가RX ring 증설, softirq budget, CPU/BIOS performance profile 확인
slave NIC 한쪽만 과부하LACP/switch hash, elephant flow, Cilium tunnel 확인
TCP retransmission 증가 없음application timeout과 직접 관련성 낮음
500GB 노드에서만 심함network tuning보다 memory headroom/xfs_inode/global OOM 우선

최종 판단

strong_bias면 저는 다음 순서로 하겠습니다.

  1. 장애 노드 1대에서만 재현 시각에 10초 delta 수집
  2. IRQ bias인지 NET_RX softirq bias인지 분리
  3. irqbalance와 RSS indirection table 확인
  4. RSS table이 이상하면 ethtool -X <dev> equal <queue_count> 테스트
  5. time_squeeze/s가 증가하면 netdev_budget=600, netdev_budget_usecs=4000 정도로 1차 테스트
  6. NIC driver drop/no_buffer가 증가하면 RX ring 증설
  7. Cilium tunnel mode이면 tunnel/flow hash 편중 가능성까지 확인
  8. 500GB 노드에서만 심하면 네트워크 단독 원인이 아니라 메모리 pressure와 함께 판단

즉, strongbias의 첫 조치는 **`netdev*` 값을 무조건 올리는 것이 아니라, IRQ/RSS 분산 확인 → RSS table/irqbalance 정리 → time_squeeze가 있을 때만 budget 조정 → driver drop이 있을 때만 ring 증설** 순서가 안전합니다.

0개의 댓글