localhostループバックを介してTCP(SOCK_STREAM)を使用した再送/非順次パケット(〜1 MB)の書き込み/読み取り - ACK損失

localhostループバックを介してTCP(SOCK_STREAM)を使用した再送/非順次パケット(〜1 MB)の書き込み/読み取り - ACK損失

ループバックインターフェイスを使用すると、再送信/非順次パケットが表示され、この事実に驚いた(私はそうです)、または他の人が見ているが、私は見たことがないかどうかを判断するために数日間インターネット検索を行ってきました。まだ答えが見つかりませんでした。私が何かを逃した場合は申し訳ありません。誰かがループバック仕様に言及しましたが、見つかりませんでした。ループバックインターフェイスの仕様を知っている人はいますか?

ACK損失による再送の例:

/root
root@cmsstor911 :^| tshark -nr/tmp/t.tcpdump -te | egrep -i 'retrans|out.of.order' -B3 -A2 
Running as user "root" and group "root". This could be dangerous.
 54 1582904297    127.0.0.1 -> 127.0.0.1    TCP 66 7001 > 45529 [ACK] Seq=449 Ack=917399 Win=2752512 Len=0 TSval=3255514024 TSecr=3255514024
 55 1582904297    127.0.0.1 -> 127.0.0.1    TCP 65549 45529 > 7001 [ACK] Seq=982882 Ack=449 Win=49152 Len=65483 TSval=3255514024 TSecr=3255514024
 56 1582904297    127.0.0.1 -> 127.0.0.1    TCP 278 45529 > 7001 [PSH, ACK] Seq=1048365 Ack=449 Win=49152 Len=212 TSval=3255514024 TSecr=3255514024
 57 1582904297    127.0.0.1 -> 127.0.0.1    TCP 278 [TCP Retransmission] 45529 > 7001 [PSH, ACK] Seq=1048365 Ack=449 Win=49152 Len=212 TSval=3255514034 TSecr=3255514024
 58 1582904297    127.0.0.1 -> 127.0.0.1    TCP 78 7001 > 45529 [ACK] Seq=449 Ack=1048577 Win=2686976 Len=0 TSval=3255514034 TSecr=3255514024 SLE=1048365 SRE=1048577
 59 1582904297    127.0.0.1 -> 127.0.0.1    TCP 178 7001 > 45529 [PSH, ACK] Seq=449 Ack=1048577 Win=2686976 Len=112 TSval=3255514224 TSecr=3255514024

tsharkがマイクロ秒を見事に印刷するのは難しいですが、何が起こっているかのように見えるのは、パケット56が(私のアプリケーションでは)しばらくの間最後のパケットであるということです。 Acknowledge以前に2つのパケットが発生したため、1つを送信しなければなりませんでした。について。 9.056ミリ秒が過ぎ、送信者は再送信を決定します。受信者はすぐにSACKを送信します。

私がやっていることは次のとおりです(5.5.4を含むいくつかの最新のLinuxカーネルで試してください)。

sudo tcpdump -s78 -wt.tcpdump -ilo port 7001 & tcpdump_pid=$!; \
taskset -c 1 ./tcp_loopback.py -s -b1048576 & sleep .5; taskset -c 2 ./tcp_loopback.py -c -b1048576 --count=8192; \
sudo kill $tcpdump_pid; \
tshark -r t.tcpdump | egrep -i 'retrans|out.of.order' | tail

tcp_loopback.py スクリプトは home.fnal.gov/~ron/tcp_loopback.py にあります。

サーバー部分(-s)の鍵は次のとおりです。

    sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
    sock.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
    sock.bind( ('127.0.0.1', port) )
    sock.listen( 4 )
    sockconn,address = sock.accept()
    while 1:
        data = sockconn.recv(bs)
        if opargs['-v']=='': print('received: '+str(len(data)))
        if len(data) == 0:
            if opargs['-v']=='': print('0 data, closing')
            break

クライアント部分(-s)の鍵は次のとおりです。

    sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
    sock.connect( ('127.0.0.1',port) )
    for xx in range(cnt): sock.send( '*'*bs )

再送信確率は、書き込み/読み取りが大きいほど(2M、4Mなど)増加するようです。

他のコアのスケジューリングに関連する順序は、間違った問題について読みました(例:Documentation / networking / scaling.rst)。したがって、上記で「作業セット」を使用します。

tcpdumpはセグメントが2回送信されたことを確認したので、再送信が本当であると信じています。また、転送中に再送信情報を取得するためにNETLINK_SOCK_DIAGソケットを使用するカスタムアプリケーションもあります。これを使用すると、ローカルホスト/ループバックの再送信が表示されます。送信のほとんど(おそらくすべて)は、この順序が間違った現象によって引き起こされるようです。したがって、次の質問が実際にある可能性があります。ループバックを使用するときにパケット順序を保証するために私ができるトリック(作業セットを除く)はありますか?相互作用?

ループバックを使用すると、送信プロセスが間違ったコンテンツを送信するのか、それとも受信プロセスが間違ったコンテンツを受信するのかを知ることはできません。私の究極の目標は、100Gi、高輻輳(多対一)環境で低レイテンシのノード間転送の基準を設定することです。再送情報を得るために「デバッグソケット」を使用するアプリケーションを開発しましたが、ローカルホストで再送されるのを見て驚きました。

何が起こっているのかを理解するのに役立つ人はいますか?ハンドル(sysctlなど)がある場合は、データレートを最大化しながら再送を削除できますか?

ありがとう、ロン

PS:これを実行したときにも、最終的にこの問題が発生しました。

while true;do
 sudo tcpdump -s78 -w/tmp/t.tcpdump -ilo port 7001 & tcpdump_pid=$!
 ncat -4l localhost 7001 > /dev/null & ncat_pid=$!
 sleep .5
 dd if=/dev/zero bs=1048576 count=2048 | ncat localhost 7001
 sudo kill $tcpdump_pid
 tshark -r /tmp/t.tcpdump | egrep -i 'retrans|out.of.order' && break
done

出力例:

/home/ron/notes
ron@ronlap77 :^) sudo tcpdump -s78 -wt.tcpdump -ilo port 7001 & tcpdump_pid=$!; \
> taskset -c 1 ./tcp_loopback.py -s -b1048576 & sleep .5; taskset -c 2 ./tcp_loopback.py -c -b1048576 --count=8192; \
> sudo kill $tcpdump_pid; \
> tshark -r t.tcpdump | egrep -i 'retrans|out.of.order' | tail
[1] 29066
[2] 29067
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 78 bytes
191379 packets captured
383230 packets received by filter
0 packets dropped by kernel
[2]+  Done                    taskset -c 1 ./tcp_loopback.py -s -b1048576
189947   1.092534    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4203412074 Ack=1 Win=65536 Len=65483 TSval=2693245609 TSecr=2693245609
189948   1.092535    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4203477557 Ack=1 Win=65536 Len=65483 TSval=2693245609 TSecr=2693245609
189949   1.092536    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4203543040 Ack=1 Win=65536 Len=65483 TSval=2693245609 TSecr=2693245609
189950   1.092536    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4203608523 Ack=1 Win=65536 Len=65483 TSval=2693245609 TSecr=2693245609
189951   1.092537    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4203674006 Ack=1 Win=65536 Len=65483 TSval=2693245609 TSecr=2693245609
189962   1.092594    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Spurious Retransmission] 46988 → 7001 [ACK] Seq=4203674006 Ack=1 Win=65536 Len=65483 TSval=2693245609 TSecr=2693245609
190115   1.093456    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4211997131 Ack=1 Win=65536 Len=65483 TSval=2693245610 TSecr=2693245610
190116   1.093457    127.0.0.1 → 127.0.0.1    TCP 65549 [TCP Out-Of-Order] 46988 → 7001 [ACK] Seq=4212062614 Ack=1 Win=65536 Len=65483 TSval=2693245610 TSecr=2693245610
190117   1.093457    127.0.0.1 → 127.0.0.1    TCP 1762 [TCP Out-Of-Order] 46988 → 7001 [PSH, ACK] Seq=4212128097 Ack=1 Win=65536 Len=1696 TSval=2693245610 TSecr=2693245610
190138   1.093547    127.0.0.1 → 127.0.0.1    TCP 1762 [TCP Out-Of-Order] 46988 → 7001 [PSH, ACK] Seq=4212128097 Ack=1 Win=65536 Len=1696 TSval=2693245610 TSecr=2693245610
[1]+  Done                    sudo tcpdump -s78 -wt.tcpdump -ilo port 7001
--2020-02-25_11:27:17--

関連情報