Foundationপ্রথম নীতি থেকে
LEVEL 7লেসন ১৯/২২রিসার্চ-লেভেল৫৫ মিনিট

QUIC — TCP+TLS কে UDP-র উপর নতুন করে লেখা কেন

QUIC Protocol

TCP আর TLS আলাদা স্তরে জমে-থাকা ঋণ — handshake cost, transport-HOL, IP-change ভঙ্গুরতা; QUIC সব UDP-র উপর userspace-এ নতুন করে লিখে এক ঝলকে শোধ করল, কিন্তু দামও দিল।

এই লেসন শেষে আপনি পারবেন

  • TCP-in-kernel evolution deadlock-টা ব্যাখ্যা করতে পারবেন — ossification, middlebox behavior, kernel-upgrade cycle — আর কেন userspace protocol-ই একমাত্র ব্যবহারিক escape route
  • QUIC-এর integrated TLS 1.3 handshake, 1-RTT/0-RTT connection establishment trace করে TCP+TLS stack-এর সাথে RTT-হিসাবে তুলনা করতে পারবেন
  • Stream-level multiplexing কীভাবে transport-level head-of-line blocking দূর করে, আর connection ID কীভাবে IP-change (wifi→LTE roam)-survival দেয় — timeline-এ দেখাতে পারবেন
  • HTTP/3 = HTTP-over-QUIC mapping বর্ণনা করতে পারবেন — QPACK, settings frames — আর HPACK থেকে QPACK-এ কেন redesign লাগল
  • Deployment blockers — UDP 443 blocking middleboxes, userspace crypto-র CPU cost, GSO/GRO offload whisper — বাস্তব adoption-data-র সাথে মিলিয়ে বিশ্লেষণ করতে পারবেন

আগে যা বোঝা থাকা দরকার

আগে এটা বুঝি

পিছনের লেসনে আমরা একটা ghost দেখেছি বারবার: head-of-line blocking। HTTP-level-টা h2 মেরেছে; transport-level-টা — TCP-র ordered bytestream — বেঁচে আছে, কারণ TCP-র promise-ই হলো হুবহু order। আরও ঋণ জমে আছে: TCP+TLS handshake-এর দুই-তিন RTT, wifi→LTE switch-এ connection মৃত্যু, আর একটা গভীর সংস্কার-অক্ষমতা।

এখন প্রশ্ন: TCP ঠিক করব কীভাবে?

উত্তরটা চমকপ্রদভাবে নিরাশাবাদী: TCP-কে ঠিক করা যাবে না। Kernel- এ বসা চার দশকের পুরনো code, প্রতিটা OS vendor-এর নিজস্ব release-cycle, আর মাঝপথে অসংখ্য middlebox যারা TCP-র bytes না বুঝেও তাদের উপর rule চালায়। তাই Google ২০১২-এ যে পথ নিল: TCP+TLS-এর কাজগুলো UDP packets-এর ভেতরে userspace-এ নতুন করে লেখা — নাম QUIC (RFC 9000)। এটা শুধু ‘faster TCP’ নয় — এটা transport layer-কে library বানানো, যে upgrade হয় browser/app update-এ, kernel update- এ নয়।

আজকের প্রশ্ন তিনটা: কেন নতুন করে লেখাই একমাত্র পথ? নতুন লেখাটা ঠিক কোন কোন ঋণ শোধ করল? আর তার দাম কী?

মূল ধারণা

কেন TCP-কে ছুঁয়ে লাভ নেই — ossification-এর তিন স্তর

স্তরসমস্যাQUIC-এর পথ
KernelTCP stack OS-এর ভেতরে; fix মানে vendor release cycle — yearsuserspace library — browser update-ই যথেষ্ট
MiddleboxNAT/firewall/TCP-optimizer-রা TCP header-এর fields parse করে; নতুন field/flag দিলে drop বা manglingUDP ‘opaque payload’ — ভেতরের কিছুই তারা parse করে ধরে নিতে পারে না
Protocol lock-inTCP-র congestion-control kernel-fixedpluggable CC — app প্রতি-connection algorithm বদলাতে পারে

এই ঘটনাটার নাম protocol ossification — wire-এ যা deploy হয়েছে তার চারপাশে ইনফ্রা জমাট বেঁধে যাওয়া, যাতে evolution frozen। QUIC-র design philosophy এক লাইনে: encrypt everything you can, so nothing can ossify around what you might want to change later।

Wire format — UDP-র পেটে পুরো transport

IP header (proto=17 UDP)
└─ UDP header (src-port, dst-port=443)
   └─ QUIC packet
      ├─ Header form byte     ← packet-type, connection-ID len flags
      ├─ Destination Connection ID (DCID)   ← routing identity!
      ├─ Source Connection ID (SCID)        ← (handshake packets-এ)
      ├─ Protected Payload      ← AEAD-encrypted: frame গুচ্ছ
      │    ├─ STREAM frame {stream-id, offset, data}
      │    ├─ STREAM frame {stream-id-2, offset, data}
      │    ├─ ACK frame {ranges of received packet-numbers}
      │    └─ MAX_DATA / WINDOW_UPDATE-equivalent...
      └─ Authentication Tag (AEAD)

লক্ষ্য করুন: এক packet-এ অনেক frame, ভিন্ন ভিন্ন stream-এর। আর packet-number encrypted — observer sequence-pattern দেখেই পারে না (linkability কমে)। Connection ID হলো QUIC-র সবচেয়ে চতুর idea — একটু পরে।

Integrated crypto — TLS আর transport এক দেহে

TCP-জগতে TLS ছিল আলাদা স্তর — তার নিজের framing, নিজের handshake records, আলাদা buffering। QUIC তা গুটিয়ে নিয়েছে: TLS 1.3 messages সরাসরি QUIC CRYPTO frames-এ চলে, আর handshake-এর phase অনুযায়ী packet-protection keys বদলায়:

TCP+TLS 1.3:                     QUIC (TLS 1.3 built-in):
TCP SYN/SYN-ACK        1 RTT     Initial packet + ClientHello   ┐
TLS ClientHello                  Initial packet + ServerHello,  │ ১ RTT
TLS ServerHello+cert             cert, Finished                 ┘
TLS Finished           1 RTT     1-RTT packets: HTTP data শুরু
HTTP request/response  1 RTT
────────────────────────────     ────────────────────────────
প্রথম byte: ~৩ RTT               প্রথম byte: ~১ RTT

আর 0-RTT resume (TLS-handshake লেসনের PSK + replay warning মনে করুন) QUIC-তেও একই ঝুঁকি-নিয়মে কাজ করে: early data idempotent-only। পার্থক্য এটুকু — QUIC-এ 0-RTT-র transport context-ও (flow-control state, previous RTT estimate) ফেরত আসে, তাই resumed connection প্রথম flight-এই near-full speed।

Stream-level recovery — HOL-এর মূল শিকার

TCP-র মৃত্যুফাঁদ: এক bytestream, এক sequence-space। Byte N হারালে N+1, N+2… deliver হয় না — যত stream থাকুক না কেন (h2-তে সেগুলো সব এই এক stream-এর মাছ)।

QUIC-এ প্রতিটা stream-এর নিজস্ব ordering state — stream-id + offset। Packet loss মানে শুধু ওই ওই frame-এর data retransmit; অন্য stream-এর freshly-arrived data সঙ্গে সঙ্গে app-এ deliver হয়:

TCP (h2 underneath):
  seq: [A1][B1][C1][A2✖lost][B2][C2][B3][C3][A2-retx]...
  app দেখে:  A1 B1 C1 ────── FREEZE (A2 ফেরত না আসা পর্যন্ত কিছুই)

QUIC:
  stream-A: [A1][A2✖lost]......[A2-retx]     ← শুধু A থামে
  stream-B: [B1][B2][B3][B4][B5][B6]         ← প্রতি tick-এ এগোচ্ছে
  stream-C: [C1][C2][C3][C4][C5][C6]         ← প্রতি tick-এ এগোচ্ছে

Loss rate ২%-এ ৬-stream h2-over-TCP page-load গবেষণায় (Google-এর measurement) QUIC প্রায় দ্বিগুণ দ্রুত — এই এক mechanism-ই মূল কারণ।

Connection ID — IP বদলাক, connection বাঁচুক

TCP connection-এর identity = 4-tuple (src-ip, src-port, dst-ip, dst-port)। Wifi থেকে LTE-তে গেলে src-ip বদলায় → tuple মরে → connection reset, সব stream হারায়। QUIC-এর identity হলো Connection ID — একটা opaque random identifier packet-header-এ। IP বদলালে client নতুন address থেকে same DCID path-validation challenge পাঠায়, server নিশ্চিত হয়ে ট্রাফিক সেখানে shift করে — streams, flow-control, TLS state সব অক্ষত। Mobile-first জগতে এটা feature নয়, survival gear।

ভেতরে কী ঘটছে

Frame anatomy আর QPACK — ভেতরের কারিগরি

STREAM frame-এর দেহ (simplified):

┌────────┬───────────┬─────────┬──────────────┐
│ type=08│ stream_id │ offset  │ length+data  │
│ (varint)│ (varint) │ (varint)│              │
└────────┴───────────┴─────────┴──────────────┘
varint = QUIC-র সর্বত্র-ব্যবহৃত variable-length integer (1-4 byte)
offset থাকায় out-of-order arrival-এও reassembly সম্ভব
FIN bit (type-এর bit-এ) = এই stream-এর শেষ frame

ACK frame TCP-র SACK-এর চেয়ে শক্তিশালী — arbitrary ranges list করে, আর ACK delay encoding করে smart pacing সম্ভব করে।

HPACK কেন QPACK হলো

h2-এর HPACK dynamic table strict insertion-order ধরে — encoder আর decoder-এর index-state হুবহু sync থাকতে হয়। কিন্তু QUIC-তে frames out-of-order পৌঁছাতে পারে (এটাই তো মূল সুবিধা!) — strict-order header-compression তাহলে নতুন HOL-এর জন্ম দিত (header-frame আটকে গেলে পরের সব stream-এর headers decode অসম্ভব!)। সমাধান QPACK: encoder আর decoder-এর table-state-এর মধ্যে explicit acknowledgement — decoder জানিয়ে দেয় কোন state পর্যন্ত দেখেছে, encoder সেই নিরাপদ state-ই reference করে। সূক্ষ্ম trade-off: compression ratio সামান্য কমে, কিন্তু HOL জন্মায় না। Design lesson: এক স্তরের সমাধান (multiplexing) অন্য স্তরের assumption ভাঙে (ordered compression), তাই dependent mechanism-ও redesign লাগে।

CPU cost আর offload-এর ফিসফিস

Userspace crypto + copy = kernel-TCP-র চেয়ে বেশি CPU per-byte। Production-এ এটা মেটায় kernel offload: GSO/GRO (Generic Segment/ Receive Offload) — অনেক QUIC packet এক send-call-এ, receive-এ batch; sendmmsg/recvmmsg syscall batching; NIC-level QUIC offload নতুন hardware- এ আসছে। তবু আজও high-throughput server-এ QUIC ≈ 1.5-2× CPU of kTLS- accelerated TCP — deployment decision-এর বড় input।

উদাহরণ

পূর্ণ timeline — wifi থেকে LTE-তে roam, দুই জগৎ পাশাপাশি

═══ TCP+TLS জগৎ (h2) ══════════════════════════════════════
t0   SYN → SYN-ACK → ACK                    (wifi, 1 RTT)
t1   TLS ClientHello → ServerHello+cert     (1 RTT)
t2   Finished → HTTP GET → response         (data শুরু!)
t30  user হাঁটল, wifi হাত থেকে গেল
t31  LTE-তে attach — নতুন source IP
t32  TCP retransmit পুরনো dst-এ যায় — black hole
t33  RST/timeout → connection DEAD
t34  নতুন connection: SYN+TLS আবার          (~২ RTT পুনঃশুল্ক)
     + in-flight requests হারায়, congestion window শূন্য থেকে

═══ QUIC জগৎ (h3) ═════════════════════════════════════════
t0'  Initial(ClientHello) → Initial(ServerHello+cert)+1RTT  (1 RTT)
t1'  HTTP GET streams 1,3,5 → responses শুরু
t30' wifi গেল — LTE attach, নতুন IP
t31' client: PATH_CHALLENGE (new-src-ip, same DCID) →
     server: PATH_RESPONSE → migration সম্পন্ন
t32' streams চলছে — কোনো reset নেই, window বজায়, কোনো পুনঃশুল্ক নেই

দুই জগতের পার্থক্য শুধু speedup নয় — failure mode ভিন্ন। TCP- জগতে roam মানে user-visible stall (spinner); QUIC-জগতে এটা একটা নিঃশব্দ path-switch। আর handshake-এর ২ RTT সাশ্রয়টা cold-start- এ: 40ms RTT network-এ ~৮০ms আগে প্রথম pixel — mobile web-এ এটা measurable engagement difference।

ছবিতে

স্তর-চিত্র — পুরনো stack বনাম নতুন stack

   পুরনো (h2):                      নতুন (h3):

┌─────────────────┐             ┌─────────────────┐
│ HTTP/2          │             │ HTTP/3          │  ← semantics একই (RFC 9110)
│  streams        │             │  QPACK, push-হীন │
├─────────────────┤             ├─────────────────┤
│ TLS 1.3         │             │                 │
│  record layer   │             │ QUIC            │  ← streams + crypto + reliability
├─────────────────┤             │  + loss recovery│     এক userspace স্তরে
│ TCP             │             │  + flow control │
│  ordered bytes  │             │  + congestion   │
│  (in kernel)    │             │  (app-updatable)│
├─────────────────┤             ├─────────────────┤
│ IP              │             │ UDP (envelope!) │  ← শুধু demux + checksum
└─────────────────┘             ├─────────────────┤
                                │ IP              │
                                └─────────────────┘

কে কী হারাল/পেল:
• TCP-র ordered-bytes promise  → QUIC per-stream ordering (কঠোরতা কমল)
• TLS-এর স্বাধীন record layer  → QUIC frame-integrated (সরলতা বাড়ল)
• kernel-এর CC ownership       → userspace pluggable (নিয়ন্ত্রণ app-এ)
• 4-tuple identity             → Connection ID (identity ও address আলাদা!)
TCP+TLS+HTTP-র তিন স্তর বনাম QUIC-র এক স্তর — লক্ষ্য করুন কোন responsibility কোথাযে উঠে গেল, আর UDP কেন মাত্র envelope।

নিজে চালিয়ে দেখুন

EXPERIMENT

HTTP/3 probe — curl দিয়ে QUIC ছুঁয়ে দেখা

macOS (brew curl-http3) / Linux; fallback trace দেওয়া আছে· ১৫ মিনিট

ধাপ ১ — আপনার curl-এ h3 support আছে কি না:

curl --version | head -1
# Features-এ 'HTTP3' লেখা থাকলে ready। macOS-এ না থাকলে:
# brew install curl          (keg-only; $(brew --prefix curl)/bin/curl ব্যবহার করুন)
# অথবা apt install curl      (Ubuntu 24.04+ curl-এ HTTP3 flag আসছে)

ধাপ ২ — Cloudflare-এর h3 endpoint-এ negotiate:

$(brew --prefix curl)/bin/curl -sv https://cloudflare-quic.com -o /dev/null 2>&1 |
  grep -i 'http3\|alt-svc\|using HTTP'
# * using HTTP/3, [HTTP/3] 200

alt-svc mechanism খেয়াল করুন: প্রথম request এখনো TCP/h2-ই — server response-header-এ বলে ‘আমি h3-ও দিই (udp 443)’, পরের request থেকে browser switch করে। Discovery এভাবেই bootstrap হয়।

ধাপ ৩ — TTFB measure, h2 বনাম h3 (warm cache bypass করতে query-string):

for proto in --http2 --http3; do
  for i in 1 2 3; do
    $(brew --prefix curl)/bin/curl -s $proto -o /dev/null \
      -w "$proto attempt$i  dns:%{time_namelookup}  conn:%{time_connect}  tls:%{time_appconnect}  TTFB:%{time_starttransfer}\n" \
      "https://cloudflare-quic.com/?r=$RANDOM"
  done
done

প্যাটার্নটা খুঁজুন: h3-এ time_appconnect প্রায় time_connect-এর সমান — TLS transport-এর ভেতরে গুটিয়েছে, আলাদা round-trip নেই।

ধাপ ৪ — tool না থাকলে: provided trace excerpt (annotated):

$ tshark -r h3-sample.pcapng -Y quic -V 2>/dev/null | grep -E 'Version|DCID|Frame'
Version: 0x00000001 (QUIC v1)
DCID: 8b7a1c3f...            ← connection identity — IP-independent
Frame: CRYPTO frame, offset 0, length 1247   ← TLS ClientHello এর ভেতরে!
Frame: STREAM frame, stream 0, offset 0      ← HTTP request already!
Frame: ACK frame, ranges [[1,4],[6,9]]       ← TCP-SACK-এর চেয়ে expressive

CRYPTO frame-এর ভেতরে ClientHello — এই এক লাইনই integrated-crypto- র সবচেয়ে ছোট প্রমাণ।

এটা কী প্রমাণ করে

আপনার machine থেকেই HTTP/3 negotiation live যাচাই করা যায়, আর h2-vs-h3 TTFB comparison দেখায় handshake-savings টা বাস্তবে কত — সংখ্যা theory-র চেয়ে জোরে কথা বলে।

নিজে বানান

BUILD IT

quic_sim.py — stream-stall বনাম bytestream-freeze, side-by-side timeline

Python · ●●○○○
  1. QUIC model: প্রতি tick-এ তিন stream-এর frame deliver — শুধু lost stream-এর frame থামে
  2. TCP model: এক shared sequence — hole-এর পরে সব segment buffer-এ বন্দি
  3. একই loss-pattern দুটোতেই inject করে timeline পাশাপাশি প্রিন্ট করুন
  4. Progress-bar দিয়ে দেখান: QUIC-এ s2/s3 পূর্ণ, TCP-তে সব freeze

Conceptual simulator — কোনো socket নেই, pure model (~৮০ লাইন):

#!/usr/bin/env python3
"""quic_sim.py — transport-level HOL: QUIC per-stream vs TCP bytestream"""
import random

random.seed(11)


def bar(done, total, w=16):
    filled = round(w * done / total)
    return '#' * filled + '.' * (w - filled)


def quic_run(ticks=12, streams=(1, 2, 3), per_stream=10,
             loss_stream=1, loss_ticks=(4, 5, 8)):
    done = {s: 0 for s in streams}
    order = sorted(streams)
    print('== QUIC: প্রতি tick-এ সব active stream-এর frame; loss শুধু s1-এ ==')
    print(f'{"tick":>4} | {"frame events":<36}| ' + '  '.join(f's{s}' for s in order))
    for t in range(1, ticks + 1):
        events = []
        for s in order:
            if done[s] >= per_stream:
                continue
            if s == loss_stream and t in loss_ticks:
                events.append(f's{s}:frame LOST(retx scheduled)')
                continue
            done[s] += 1
            events.append(f's{s}:delivered #{done[s]}')
        bars = '  '.join(bar(done[s], per_stream) for s in order)
        print(f'{t:>4} | {" · ".join(events):<36}| {bars}')
    return done


def tcp_run(ticks=12, total=36, per_tick=3, drop_seq=12, drop_tick=5):
    sent, expected, delivered, buffered = 0, 0, 0, set()
    print('\n== TCP: এক bytestream — seq12 lost হলে পরের সব বন্দি ==')
    print(f'{"tick":>4} | {"segment events":<36}| delivered')
    for t in range(1, ticks + 1):
        events = []
        for _ in range(per_tick):
            if sent >= total:
                break
            seq = sent
            sent += 1
            if seq == drop_seq and t == drop_tick:
                events.append(f'seq{seq}:LOST (waiting retx)')
                continue
            if seq == expected:
                expected += 1
                delivered += 1
                while expected in buffered:
                    buffered.discard(expected)
                    expected += 1
                    delivered += 1
            else:
                buffered.add(seq)
                events.append(f'seq{seq}:arrived BUT held (hole@{expected})')
        label = f'{delivered}/{total}  frozen!' if buffered else f'{delivered}/{total}'
        print(f'{t:>4} | {" · ".join(events) or "(idle)":<36}| {label}')
    print('>> hole পূর্ণ (retx আসা) পর্যন্ত delivered আর নড়বে না — transport-HOL')


if __name__ == '__main__':
    q = quic_run()
    print(f'\nQUIC ফল: s1={q[1]}/10 (stalled), '
          f's2={q[2]}/10 ✓, s3={q[3]}/10 ✓ — ক্ষতি শুধু যে-এর দোষ')
    tcp_run()

প্রত্যাশিত output-এর মর্ম (shape):

== QUIC ==
tick 4 | s1:frame LOST · s2:delivered · s3:delivered | ####........####........####........
tick 5 | s1:frame LOST · s2:delivered · s3:delivered | ####........#####.......######......
...
>> QUIC ফল: s1=7/10 (stalled), s2=10/10 ✓, s3=10/10 ✓

== TCP ==
tick 4 | seq12:LOST · seq13:held · seq14:held | 12/36  frozen!
tick 5 | seq15:held · seq16:held · seq17:held | 12/36  frozen!
>> hole পূর্ণ পর্যন্ত delivered আর নড়বে না

নিজে বাড়ান: (১) h2-over-TCP model — ৬ logical stream এক bytestream-এ map করে দেখান এক loss সবকে ছোঁয়; (২) retransmission timeout-এর পরে flush event যোগ করুন — TCP তখন jump করে 35/36-এ; (৩) loss-rate parameter নিয়ে throughput-curve plot করুন — QUIC-র advantage loss-এর সাথে কীভাবে বাড়ে।

বাস্তব সিস্টেমে

Adoption আর blockers — বাস্তব জগতের হিসাব

Scale-এ আছে। Google-এর নিজস্ব traffic-এর বড় অংশ, Meta-র apps (Instagram/Facebook backend + client), Cloudflare network-এর উল্লেখযোগ্য অংশ h3। Chrome-এ h3 enablement ৭৫%-এর উপরের users। Apple-এর platforms-ও NSURLSession-এ h3 default-attempt করে। অর্থাৎ — আপনি আজ পড়ছেন এই লাইনটা QUIC-এর উপর দিয়ে এসে থাকতে পারে, না-ও থাকতে পারে, আপনি জানবেনও না (semantics একই!)।

Blocker ১ — middleboxes UDP 443 block/drop। Enterprise firewalls আর কিছু carrier NAT UDP-তে aggressive timeout রাখে। Fallback mandatory তাই: alt-svc advertise করলেও client h3 fail করle সঙ্গে সঙ্গে h2-তে ফেরে — happy-eyeballs-style race। Production metric: h3-fallback-rate monitor করা হয় corporate-network share বোঝার সূচক হিসেবে।

Blocker ২ — CPU। আগের section-এর হিসাব: userspace crypto + copy ≈ 1.5-2× cost। Edge-provider-রা দাম দিতে রাজি (latency-win তাদের business), কিন্তু একটা ছোট self-hosted service-এ h2-ই pragmatic choice হতে পারে। GSO + newer kernels + NIC offload এই gap দ্রুত বন্ধ করছে।

Blocker ৩ — debugging culture। tcpdump-এ QUIC payload এখন undecipherable (encrypted!) — logging আর analysis করতে হয় qlog format (endpoint-রা নিজেরা emit করে), নতুন toolchain। Network-engineer workflow-এর এই বদলটাই অনেক org-এর slowest অংশ।

WebTransport/WebRTC সংযোগ। QUIC-র stream-abstraction-ই WebTransport API-র ভিত্তি — browser-এ bidirectional stream/datagram, game আর collab- app-দের নতুন খেলনা। QUIC transport-layer innovation-এর engine হয়ে উঠছে, শুধু web-page-delivery-র চেয়ে বড় প্রজেক্ট।

যে ভুলগুলো সবাই করে

“QUIC UDP-র উপর তাই TCP-র চেয়ে দ্রুত — UDP নিজেই দ্রুত।”

UDP কোনোভাবেই TCP-র চেয়ে দ্রুত নয় — সে তো কিছুই করে না (no reliability, no congestion control, no ordering)! QUIC দ্রুত হয় কারণ সে নিজে TCP-র সব কাজ + TLS-integration + smarter loss-recovery userspace-এ করে, আর handshake-composition-এর খরচ কমায়। আর সেই কাজ করতে গিয়ে CPU-তে উল্টো দামও দেয়। Speedup টা protocol-design-এর, envelope-এর নয়। ‘UDP faster than TCP’ — networking interview-এর classic trap।

“QUIC মানে reliability বাদ — তাই gaming/VoIP-র জন্য পারফেক্ট।”

QUIC-এ reliability default-on — retransmission, ACK, ordering সব TCP-র মতোই, শুধু per-stream। Real-time media-র জন্য QUIC রেখেছে unreliable datagram extension (DATAGRAM frame — RFC 9221) — সেটা opt-in, আলাদা। অর্থাৎ QUIC হলো both-mode transport: stream-mode reliable, datagram-mode not। Gaming-দের পুরনো প্রিয় raw-UDP এখনো আলাদা; QUIC-র দান সেখানে selective-reliability — critical state stream-এ reliable, position-update datagram-এ unreliable, এক connection-এ দুটোই।

“HTTP/3 মানে HTTP-র নতুন semantics — নতুন methods/status codes।”

না — এটাই পুরো series-এর সবচেয়ে সুন্দর separation। RFC 9110-এর semantics (methods, status, headers, caching) তিন version-এই হুবহু এক; বদলায়েছে শুধু binding: কোন wire-format-এ কীভাবে encode হয়। h3-তে pseudo-header, QPACK, control-stream — transport-mechanics; GET/404/ETag — untouched। তাই application-code-এ h1→h2→h3 migration প্রায় invisible — server/client infra-decision, API-design decision নয়।

“Connection ID থাকায় QUIC connection কখনো মরেই না — roam unlimited?”

Migration শুধু তখনই কাজ করে যখন নতুন path সত্যিই viable — server PATH_CHALLENGE দিয়ে যাচাই করে আপনি সত্যিই নতুন address-এর মালিক (address-spoofing attack বন্ধ করতে), আর NAT rebinding নতুন CID-ও চাইতে পারে। কিছু networks-এ outbound-UDP এত restrictive যে migration attempt-ই ব্যর্থ — fallback তখন নতুন connection (CID নতুন, state resumption ticket দিয়ে 0-RTT)। Migration graceful-path-change-এর জন্য; immortality-র প্রতিশ্রুতি নয়।

বুঝেছেন কি না দেখুন

1

Middlebox-ossification problem-টা যদি না থাকত, TCP-কে সরাসরি extend করা কি QUIC-এর চেয়ে ভালো path হতো? কোন সমস্যাগুলো তবুও থেকে যেত?

যুক্তি

Middlebox না থাকলে TCP extension (নতুন option/flag) ব্যবহারিক হতো — Google-এর TCP Fast Open, MPTCP-র গল্প এটাই বলে (deploy-দুর্ধর্ষতা মূলত middlebox-এ)। তবু থেকে যেত: kernel-distribution lag (OS release-cycle — MPTCP Linux-এ এল বছরখানেক আগে iOS-এর বহু পরে), per-app customization-অসম্ভবতা (সব app এক kernel-stack শেয়ার), আর TCP+TLS-এর দুই-layer composition overhead। QUIC-র মূল বিজয় ossification- bypass এবং transport-as-library — দুটোই।

2

RTT 60ms-এর network-এ প্রথম page-byte পেতে: (ক) TCP+TLS1.2+h1, (খ) TCP+TLS1.3+h2, (গ) QUIC+h3 cold-start, (ঘ) QUIC+h3 0-RTT resume — প্রতিটায় কত RTT (handshake+first-response)? ধরুন DNS cached।

প্রয়োগ

(ক) TCP 1 + TLS1.2 2 + req-resp 1 = 4 RTT = 240ms। (খ) TCP 1 + TLS1.3 1 + req-resp 1 = 3 RTT = 180ms। (গ) QUIC integrated 1 + req-resp 1 = 2 RTT = 120ms। (ঘ) 0-RTT early-request + resp = 1 RTT = 60ms (early data accepted হলে; reject হলে গ-এর মতো 2)। প্রতিটা generation-এ ঠিক এক RTT কমানো — protocol-evolution-র rhythm-টা লক্ষ্য করুন।

3

HPACK-এর strict-order assumption কীভাবে QUIC-তে নতুন HOL তৈরি করত? QPACK-এর explicit-ack solution কী দিয়ে দাম দেয়?

যুক্তি

HPACK decoder-এর dynamic-table index মানে হুবহু insertion-order state; QUIC-এ header-frame stream-A আগে পাঠানো হয়েও stream-B-এর পরে পৌঁছাতে পারে — B decode করতে গিয়ে A-dependent index reference দেখলে B-কে A-র delivery-র জন্য wait করতে হয় = cross-stream HOL, ঠিক যে বিষটার জন্য QUIC বানানো! QPACK দেয় acknowledged-state model: encoder শুধু decoder-confirmed state reference করে। দাম: extra round-of-acks latency on table-insertion (compression opportunity সামান্য হারায়) আর complexity। Correctness-critical dependency সবসময় explicit করা উচিত — hidden-ordering assumption distributed system-এ ফাঁদ।

4

আপনার team একটা multiplayer game-server design করছে (position-updates 20Hz, chat, inventory-transactions)। Transport-design propose করুন QUIC-র features ব্যবহার করে — কোন traffic কোন mode/stream-class-এ, আর কেন।

ডিজাইন

Position updates → DATAGRAM frames (RFC 9221): unreliable, latest- wins — পুরনো position-এর retransmit অর্থহীন। Chat → reliable ordered stream (একটা dedicated stream) — message-loss unacceptable, order meaningful। Inventory transactions → আলাদা reliable streams, প্রতিটা transaction এক stream — এক transaction-এর packet-loss অন্যটা block করবে না (per-stream HOL-immunity!), server-side idempotency-key সহ (0-RTT replay defense)। Connection ID → mobile players roam- এ connection বাঁচবে। Bonus: congestion-control pluggability — game- traffic-এ BBR-style বা custom CC, kernel-এর হাত ছাড়াই। এক transport, traffic-class-per-policy — QUIC-র architecture-ই এই use-case-এর জন্মভূমি।

5

QUIC packet-এর header-এ Connection ID কেন আছে, আর TCP-তে এর equivalent কী — সেটা কেন অপর্যাপ্ত?

স্মরণ

QUIC-র DCID/SCID = stable, address-independent connection identity — routing-demux এটা দিয়ে, IP নয়। TCP-র equivalent 4-tuple (src-ip, src-port, dst-ip, dst-port) — যেখানে IP নিজেই component। তাই address বদলালে (roam, DHCP renew, NAT rebind) tuple বদলায় = connection অস্তিত্বহীন। Identity আর locator-এর এই বিচ্ছেদ-ই QUIC-র mobility-magic — একই philosophy যেটা LISP/HIP research-line বছরের পর বছর ধাক্কা খেয়েছে; QUIC প্রথম mass-scale জয়।

এরপর কী

এরপর কী

এতদূর আমাদের সব model ছিল request-response — client চায়, server দেয়। কিন্তু chat, game, collaborative editor-এ দুই দিকেই initiative — server-ও যখন তখন কথা বলতে চায়। HTTP-র request-gate ভেঙে full-duplex channel খোলার প্রোটোকল WebSocket — Upgrade dance, frame-format- এর masking history, আর scale করার সময় sticky-session pain — পরের লেসনে।

আরও পড়ুন

  • RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport — J. Iyengar, M. Thomson (eds.) · Connection ID, streams, frames, loss recovery — QUIC-র core specification
  • RFC 9001 — Using TLS to Secure QUIC — M. Thomson, S. Turner · TLS handshake-এর QUIC-integration — কোন keys কোন packet-type encrypt করে
  • RFC 9114 — HTTP/3 — M. Bishop (ed.) · HTTP semantics-এর QUIC-mapping — QPACK আর control streams