이더넷 케이블을 통해 두 대의 컴퓨터가 연결되어 있고 Ubuntu 22.04가 설치되어 있습니다. 컴퓨터 B)에 있는 서버로 UDP 패킷을 보내는 컴퓨터 A)에 클라이언트가 있고 다양한 시나리오에서 이러한 패킷의 대기 시간과 지터를 측정하고 있습니다. 소켓 라이브러리를 사용하여 C로 클라이언트 및 서버 소스 코드를 작성했습니다.
대기 시간을 측정하는 패킷 외에 두 시스템 사이에 추가 고대역폭 트래픽이 있는 경우 추가 트래픽 없이 패킷을 보낼 때보다 지터와 대기 시간이 더 작습니다.
- 추가 트래픽 없는 왕복 시간: 0.556ms
- 추가 트래픽의 왕복 시간: 0.105ms
- 추가 트래픽이 없는 지터: 0.042ms
- 추가 트래픽에 대한 지터: 0.014ms
패킷 수가 적으면 대기 시간과 지터가 줄어든다고 생각했기 때문에 이는 흥미로웠지만 결과는 그렇지 않은 것으로 나타났습니다. 이유가 무엇인지 말해 줄 수 있는 사람이 있나요? 나는 이것이 더 많은 패킷이 도착할 때 버퍼를 더 자주 비워야 하는 버퍼 최적화와 관련이 있다고 생각하지만 확실하지 않습니다. 이 경우 대기 시간을 최소화하도록 버퍼를 어떻게 구성할 수 있습니까?
편집#1: 제안한 대로 NIC 구성(ethtool -c)의 매개변수를 수정해 보았습니다.
rx-usecs 3의 초기 값을 rx-usecs 1 us로만 변경할 수 있습니다. Adaptive-rx 및 rx-usecs-low를 수정할 수 없습니다. 내 네트워크 카드가 이를 지원하지 않는 것 같습니다.
rx-usecs 값을 1로 줄이면 문제가 해결되지 않습니다. 두 시나리오 간의 대기 시간 차이는 증가하지 않으면 동일하게 유지됩니다.
5와 10으로 늘리는 것도 도움이 되지 않는 것 같습니다.
답변1
네트워크 지연 시간과 지터를 줄이려면 트래픽에 관계없이 항상 CPU 부하를 늘리고, 어떤 경우에는 트래픽이 많은 상황에서 처리량을 줄이기도 한다고 합니다.
A/Ultimate Hammer: 바쁘게 투표하세요!(중요한 경고는 CPU가 적을수록 다른 영역에서 더 많은 희생이 따른다는 것입니다.)
아이디어는 일부 차단을 실행하고 잊어서 recvmsg
다른 작업을 위해 CPU를 확보하는 대신 결국 CPU 캐시를 플러시하고 몇 가지 컨텍스트 전환과 Softirq 처리 후에 결국 작업으로 돌아간다는 것입니다.... 루프 네트워크 카드에서 무언가가 나오길 기다리느라 바쁩니다.
버퍼에서 데이터를 사용할 수 있게 되면 추가 지연 없이 처리됩니다.
man recvmsg
이에 관련된 부분을 참고하고 읽어보시기 바랍니다MSG_기다리지 마세요배너. 또한 소켓을 열어도 비슷한 효과를 얻을 수 있습니다.O_비차단또한 폴링은 코어를 통해 구현될 수도 있지만 개인적으로 이 아이디어가 마음에 들지 않습니다. 왜냐하면... 코어가 2개 밖에 없기 때문입니다... ;-)
즉, 작업을 하나의 CPU에 고정하고 싶을 것입니다. 이렇게 하면 작업 마이그레이션 오버헤드가 방지되고 캐시를 핫하게 유지하는 데 도움이 됩니다.
이 접근 방식의 이점은 즉각적입니다! 처리량에 영향을 주지 않고 대기 시간과 지터를 최소화하지만... 공짜 점심 같은 것은 없기 때문에... 가능한 가장 높은 CPU 로드입니다.
B/낮은 수준의 네트워크 카드 조정(인터럽트 병합, 링 버퍼, 전송 큐...from ethtool
)
- 버퍼:일반적으로 어떤 하위 시스템(네트워크/사운드/…) 버퍼든 대기 시간/지터의 적입니다. 따라서 이를 최소한으로 줄여야 합니다.
엄격한 최소값은 무엇입니까?
부하가 높을 때 패킷 손실 및/또는 오버플로가 시작됩니다(보고된 대로 ifconfig
).
- 인터럽트 병합:
인터럽트 통합은 패킷이 호스트 메모리에 있기 때문에 패킷 도착 시간의 지연을 증가시키지만 호스트는 일정 시간이 지날 때까지 패킷을 인식하지 못합니다. 그러나 더 적은 수의 인터럽트가 생성되고 호스트가 인터럽트당 여러 패킷을 처리하므로 시스템은 더 적은 CPU 주기를 사용합니다.
따라서 CPU 시간과 처리량을 희생하면서 병합을 가능한 한 가장 낮은 정도로 줄이는 것이 흥미롭다는 것을 알 수 있습니다.
- 물론, 다음과 같은 경우에는 필요하지 않습니다.바쁜 폴링.
- 물론 관련 IRQ가 사용 가능한 모든 코어에 균등하게 분산되어 있는지 먼저 확인하지 않으면 다중 대기열 네트워크 카드에 거의 영향을 미치지 않습니다.
- 물론 시스템이 실행되고 있지 않으면 아무 효과가 없습니다.인터럽트 스레드IRQ 처리의 실제 작업은 실시간 스케줄링 정책을 따르는 전용 커널 스레드에 의해 수행되지 않기 때문입니다.
답변2
네트워크 드라이버와 스택은 이더넷 프레임을 수신하거나 전송 프레임을 완료할 때 카드가 인터럽트를 발생시키는 모드에서 본질적으로 커널이 필요한 것이 있는지 묻기 때문에 가능한 한 빨리 카드를 조사하는 모드로 자동 전환할 수 있습니다. 처리됩니다.
새로운 패킷이 도착할 때마다 직관적으로 인터럽트를 받는 것이 대기 시간을 줄이는 것처럼 들리지만, 인터럽트를 처리하려면 약간의 준비가 필요하므로 시간이 걸린다는 아이디어입니다. 고속 통신이 진행되는 경우 패킷이 처리되고 모든 커널 관리가 완료된 후 처리를 기다리는 새 패킷이 거의 확실하게 존재합니다. 따라서 중단으로 인해 작업 흐름이 중단되고 실제로 사용할 수 있는 시간이 줄어듭니다.다루다(단순히 패킷의 존재에 반응하는 대신)
ethtool -C
ethtool의 매뉴얼 페이지를 확인하여 어떤 옵션이 이해되는지 확인하여 동작을 제어할 수 있습니다 . sudo ethtool -c ${YOUR_ETHERNET_INTERFACE_NAME}
다음을 사용하여 현재 옵션을 확인 해야 합니다 .
Coalesce parameters for ${YOUR_ETHERNET_INTERFACE_NAME}:
Adaptive RX: on TX: off
stats-block-usecs: 50
sample-interval: 20
pkt-rate-low: 0
pkt-rate-high: 0
rx-usecs: 0
rx-frames: 1
rx-usecs-irq: n/a
rx-frames-irq: n/a
tx-usecs: 0
tx-frames: 1
tx-usecs-irq: n/a
tx-frames-irq: n/a
rx-usecs-low: n/a
rx-frame-low: n/a
tx-usecs-low: n/a
tx-frame-low: n/a
rx-usecs-high: n/a
rx-frame-high: n/a
tx-usecs-high: n/a
tx-frame-high: n/a
CQE mode RX: n/a TX: n/a
이를 합리적인 값(마이크로초 단위)으로 설정하거나 rx-usecs-low
설정 rx-usecs
하고 비활성화할 수 있습니다 adaptive-rx
. (고속 네트워킹을 연중무휴 24시간 사용할 수 없는 상황에서는 거의 단점이 없는 Adaptive RX를 사용하는 것이 좋은 생각일 것입니다.)