テレビのアニメはどこから来る? / 第25話

第25話:イトは、最初のduplicate ACKで再送しなかった|TCPは欠けをどう知る?

TCPは消えたdataを直接見ているわけではない。イトは一度のduplicate ACKで早合点せず、同じACKが三度続く意味とRTOを使い分け、欠けたsequenceを再送する。ACK、fast retransmit、timerの因果を物語でつかむ第25話。

TCP sequenceとcumulative ACKduplicate ACKfast retransmitRTO10分更新

第24話のsubtitle gateは開いた。

remote stageでは、話し手が次の台詞へ進んでいる。

けれどsource TCP ledgerの裏側では、三つの同じACK pulseがまだ明滅していた。

その横で、retransmission timerのringがゆっくり細くなる。

イトは、三つのpulseの中央へmissing札を置こうとした。

「このACKが、二番目をなくしたと教えてくれたんだよね」

ピコは札に触れなかった。

代わりにreceiverから返ったpulseを、一つずつsource側へ並べた。

ピコ

ACKに『二番目をなくした』とは書かれていないよ

イト

じゃあ、TCPは見えないgapをどうやって知ったの?

ユイ

ACKが実際に知らせていることから戻ってみましょう

stageの次のsubtitle lineが必要になるまで、あと九秒。

このlabでは、そのlineを同じ大きさのfive segment traysへ分けて観察する。

五枚であることと、同じ大きさにしたことは、仕組みを見やすくするための実験設定だ。

segment番号ではなく、byteの位置

送信台には、長いbyte railが一本あった。

railの各位置に、小さなsequence markが付いている。

TCPでsequence numberが付く基本単位は、「荷物の一番、二番」ではない。

connection内を流れる一つ一つのoctet、つまり8 bitのbyteの位置だ。

segmentのsequence numberは、そのsegmentが運ぶfirst data octetの位置を示す。

IETFの現行TCP標準RFC 9293は、connection上で送る各data octetがsequence numberを持ち、ACK numberにはreceiverが次に期待するsequence numberを入れると定めている。

ACKはcumulativeだ。

ある位置まで進んだACKは、その位置より前のoctetsを受け取ったことをまとめて知らせる。

イトは「二番」と書こうとした札を裏返した。

そこへ「次は、この位置から」と書き直す。

イト

ACKは、消えたsegmentの名前じゃなくて、次に待っているbyte位置を返すんだ

マコト

senderは、自分が送ったsequence範囲と、そのnext expectedを比べられる

ピコ

でも同じACKが一度返っただけでは、lossと決められない

stage gateは、残り七秒。

一度のduplicate ACKで、早合点した

ピコは最初に、lossではなくreorderingのtrialを開いた。

first trayがreceiverへ届く。

ACKのnext expected markが、second trayのstartへ進んだ。

ところがnetwork内でsecond trayが少し遅れ、third trayが先に着く。

receiverのrailには、second trayのgapがある。

後ろのthird trayは届いている。

receiverは、先ほどと同じnext expectedをもう一度返した。

duplicate ACKだ。

イトは、すぐretransmit leverへ手を伸ばした。

その瞬間、遅れていたoriginal second trayがreceiverへ着く。

gapが埋まり、ACKはthird trayの後ろまで一気に進んだ。

lossはなかった。

もし一度のduplicate ACKだけでsecond trayを送り直していたら、同じdataを余分にnetworkへ出すところだった。

イト

同じACKはgapの手がかり。でも一回なら、ただ順番が入れ替わった可能性もある

ユイ

retransmissionにもnetworkを使うcostがあります

ピコ

duplicate ACKはlossの原因証明ではない。次のtrialでは、signalの重なりを見よう

IETFのTCP Congestion Control RFC 5681も、duplicate ACKはdropped segmentだけでなく、network reorderingや複製でも起こり得ると説明している。

同じACKが一つ返った、だから即loss確定、ではない。

three duplicate ACKsが返った

今度は、second trayが本当にroute途中で失われた。

first trayは届いている。

receiverのnext expectedは、second trayのstartだ。

その後、third trayが届く。

same next expectedを返すduplicate ACKが一つ。

fourth trayが届く。

同じduplicate ACKが二つ。

fifth trayが届く。

同じduplicate ACKが三つ。

receiver側には、gapの後ろへthree later traysが並んだ。

source側では、ACK numberが三度続けて前へ進まない。

timer ringは、まだ尽きていない。

stage gateは、残り四秒。

どのsignalで再送する?

操作台に、三枚のrecovery cardが開いた。

  1. first duplicate ACKだけで、すぐapparent missing segmentを再送する
  2. duplicate ACKsはすべて無視し、retransmission timerが尽きるまで待つ
  3. 同じACK numberを返すthree duplicate ACKsをloss indicationとしてclassic fast retransmitを使い、RTOはfeedbackが足りない場合のfallbackとして残す

一番目は、先ほどのreordering trialでunnecessary retransmissionになりかけた。

二番目でも、timerが尽きれば回復できる。

けれど、このlabのsubtitle deadlineには間に合わない。

三番目なら、later three traysがreceiverへ届いたsignalを使える。

ただしlossの正確な原因まで証明したわけではない。

イトは三番目のcardを選んだ。

同じnext expectedが三度続いたことを確認する。

source ledgerで、まだACKされていないearliest sequence spanを一つだけ光らせた。

そのtrayを、自分でfast retransmit slotへ入れる。

同時にsend windowのvalveを狭めた。

loss indicationを見て、missing dataだけを送り直し、残りを同じ勢いで押し込まないためだ。

イト

ACKが『これをなくした』と言ったんじゃない。next expectedが進まず、後ろのdataは三つ届いた。その重なりからapparent missing spanを選ぶ

マコト

timerを捨てずに、先に得られたfeedbackで回復を始めたんだね

ピコ

fast retransmitのactionを選んだのはイトだよ

RFC 5681のclassic fast retransmitは、ACKを前進させる新しいACKを挟まずにthree duplicate ACKsを受けたとき、segment lossのindicationとして、retransmission timerのexpiryを待たずにapparent missing segmentを再送する。

同じ規格は、このloss indicationに合わせたcongestion control / fast recoveryも定めている。

再送だけして、networkへの送り方を何も変えない仕組みではない。

ACKがgapを越えた

retransmitted second trayが、two routersを越えた。

receiverのcentral gapへ収まる。

後ろではthird、fourth、fifth traysがすでに待っている。

byte railが一続きになると、receiverはgapの先までまとめて認めるcumulative ACKを返した。

source側のACK markが、fifth trayの後ろへ跳ぶ。

そろったbyte streamがapplication gateへ渡り、次のsubtitle lineが欠けなく灯った。

stage gateは、一秒を残して開いた。

receiver railのsecond gapと後ろのthree traysから同じnext-expected ACK pulseが三つ戻り、timerが尽きる前にイトがsingle missing trayをfast retransmit slotへ入れるラボ
ACKはmissing tray名を通知しない。同じnext expectedを返すthree duplicate ACKsをloss indicationにし、イトはRTO前にapparent missing spanを一つだけ再送した。

成功したのは、later dataがthree duplicate ACKsを生んだこのtrialだ。

later dataがなければ、timerが残る

ピコは、別のshort streamを出した。

最後のtrayだけが失われる。

その後に送るdataはない。

receiverへabove-gap segmentが来ないため、three duplicate ACKsもsourceへ返らない。

fast retransmitを始めるsignalが足りない。

それでもTCPのrecoveryは終わらない。

IETFのretransmission timer標準RFC 6298では、RTOがexpireしたとき、receiverからまだACKされていないearliest segmentをretransmitする。

RTOは固定の砂時計ではない。

senderはround-trip timeの測定と変動から値を管理し、timeout後はRTOをback offする。

だから、次の二つを分ける。

three duplicate ACKsが返ったloss indicationでは、classic fast retransmit。

十分なfeedbackが返らないlossでは、RTOがfallback。

実際のTCP実装やoptionsは、さらに多くのloss recovery情報を使うことがある。

この回で見たのは、RFC 5681のclassic fast retransmitとRFC 6298のRTOという基本の二経路だ。

関連ガイド「TCPとは」では、reliable in-order stream、sequence / ACK、retransmissionを一覧で確認できる。

再送できたあとにも残るもの

subtitleは間に合った。

でも、second trayは二度networkへ出た。

receiverはlater traysをgapの後ろで保持した。

senderはsequence state、ACK state、timer、congestion windowを持ち続けた。

retransmissionが起きた原因が、route congestion、reordering、wireless lossのどれだったかは、cumulative ACKだけでは確定していない。

イトは、再送成功lampの横へcost cardを置いた。

reliableにそろえるためのstateとfeedback。

それを持つから回復できる。

持つから、待ちと制御も増える。

次回:このledgerを外したら?

イトは、次の実験台へ移った。

そこには、connection ledgerがない。

cumulative ACKのreturn pathもない。

retransmission timer ringもない。

一つのdatagram cradleだけが、openなまま置かれている。

イトはlate voice pieceをその上へ置き、手を止めた。

次回、ピコルート第26話。

UDPは何を持たず、applicationへ何を残す?

この物語を、解説で深める

第25話で生まれた疑問を、解説記事で少し深く見ていきます。物語で感じた不思議さを残したまま、言葉と仕組みを順番に整理しましょう。

TCPとは|届いたか確認しながらデータを届ける仕組みを読む