QUIC Protocol — 0-RTT connection magic หรือ design ? มีอยู่แค่นี้หรือมีของดีอื่นๆด้วย ?

Bank Eakasit
8 min readFeb 7, 2019

--

สืบเนื่องจากกำลังศึกษา HTTP/3 (ซึ่งยังไม่สมบูรณ์) มีการอ้างอิงถึง QUIC หลายครั้ง แต่ในขณะเดียวกันก็มีบทความเชิงลึกเกี่ยวกับการทำงานของ QUIC ค่อนข้างน้อย. ส่วนใหญ่จะแสดงแค่รูปข้างล่างนี้ ว่าส่งข้อมูลได้ทันทีเลย เป็น 0-RTT connection แล้วก็สรุปไปเลยว่ามันทำให้ internet เร็วขึ้นกี่เปอร์เซ็นโดยที่ไม่ได้อธิบายว่ารูปนี้มันมาได้อย่างไร แล้วมันทำให้ UDP reliable ได้อย่างไรครับ. ผมก็เลยคิดว่าน่าจะมาศึกษา QUIC ให้ลึกซึ้งก่อนว่าด้านล่างมันทำงานยังไงกันแน่ ก่อนที่จะกระโดดไปเกาะ HTTP/3. และไหนๆก็ศึกษาแล้ว ยังไม่มีบทความภาษาไทยเกี่ยวกับเรื่องนี้เลย (บทความภาษาอังกฤษก็ยังพบน้อยมาก หรือไม่ก็มีแต่ outdate บ้าง หรือข้อมูลไม่ลึกถูกใจบ้าง) ก็เลยรวบรวมขึ้นมาเองครับ. หวังว่าผู้อ่านจะได้ประโยชน์ไม่มากก็น้อย

https://blog.chromium.org/2015/04/a-quic-update-on-googles-experimental.html

QUIC มีเนื้อหาค่อนข้างเยอะ แต่หลักการและไอเดียหลายๆอย่างนั้น ไม่ได้เกิดขึ้นใหม่ทั้งหมด [1] มียืมไอเดียบางส่วนจากที่มีอยู่แล้ว เช่น TCP Fast Open, SCTP, SST, TCP Session และมีทั้งปรับแก้เอง เพิ่มเข้าไป เพื่อให้เหมาะสมตามสภาพกาลที่เปลี่ยนไปด้วย. ผมอ้างอิงหัวข้อตาม [2] เนื่องจากแบ่งแยกชัดเจนเข้าใจง่าย เนื้อหาจากอ้างอิงอื่นๆ ​มาอธิบายรวมด้วยครับ

  1. Low-latency connection establishment
  2. Stream Multiplexing
  3. Stream and connection flow control
  4. Flexible congestion control
  5. Connection migration

ทั้งนี้ QUIC มี version ค่อนข้างมาก ผมเองที่ไม่ใช่ผู้เชี่ยวชาญ ไม่สามารถตามทำความเข้าใจ version ใหม่สุดทั้งหมดได้ แต่จะพยายามอ้างอิงตาม version ใหม่นะครับ. ตัวอ้างอิงเก่าๆบางตัวผมหยิบมาเพราะอ่านง่าย แต่ก็จะทบทวนกับ version ใหม่ให้อีกทีแล้วว่าไม่แตกต่างกัน (หรือแตกต่างกันรายละเอียดย่อยเท่านั้น)

1. Low-latency Connection Establishment

หรือแปลง่ายๆ คือ หัวข้อเรื่อง 0-RTT นั่นแหละ. ขั้นตอนการลด RTT ของ QUIC แบ่งออกได้เป็นสองไอเดียครับ [4]

A. การเก็บข้อมูล cache information ไว้ สำหรับ server ที่เคยคุยด้วย

ในเมื่อเราเคยคุยกับ server นั้นๆมาก่อนแล้ว มีเหตุผลอะไรที่เราจะต้องขอข้อมูลที่เรารู้อยู่แล้วใหม่อีกรอบล่ะ มันไม่ make sense. ก็เก็บข้อมูลนั้นไว้ แล้วครั้งต่อไปก็ใช้ข้อมูลนั้นในการเริ่มคุยกับ server เลย. ดังนั้นข้อมูลต่างๆ เช่น server config ที่รับได้, server certificate, client token ต่างๆ. แน่นอนว่า cache นี้ไม่ได้เก็บไว้ตลอดกาล ขึ้นอยู่กับว่า server มองว่าควรเก็บไว้ระยะเวลาเท่าใดจึงเหมาะสม. การเก็บเอาไว้ยิ่งนาน ยิ่งเพิ่มความเสี่ยงด้าน security เช่นกัน.

B. การรวม TCP Layer handshake เข้ากับ TLS handshake

มาตรฐานความปลอดภัย internet เราดีขึ้นกว่าแต่ก่อนมาก เราคาดหวังว่าทุก data บน internet นั้นควรจะมี encryption เสมอ. นั่นหมายความว่า จากเดิมที่ TCP + TLS นั้นทำงานแยก layer กัน ทำให้ต้องมีการทำ TCP handshake แล้วค่อยต่อด้วย TLS handshake อีกที่ซึ่งใช้เวลาถึง 3-RTT นั้นเป็นการเสียเวลามาก. ในเมื่อเราอยากให้ encryption เป็นมาตรฐานอยู่แล้ว ก็รวมมันเป็น handshake เดียวกันซะ. เราก็จะลด TLS handshake ได้เหลือแค่ handshake ของ transport ละ.

เมื่อสองไอเดียรวมกัน

แต่ handshake ของ transport มันก็เป็น 0-RTT ได้แล้ว จากไอเดียข้อแรกที่เราได้มา ดังนั้นเมื่อรวมกันแล้ว ก็เลยออกมาได้ว่า TCP + TLS handshake บน QUIC เนี่ยสามารถลดได้เหลือ 0-RTT เลย

หมายความว่า แทนที่ client จะต้อง handshake TLS ด้วย ก็สามารถนำ public value ของ server จาก cache เดิมในการสร้าง Diffie-Hellman shared key (initial key) แล้วเข้ารหัส ส่งข้อมูลได้ใน request แรกเลย. ขณะเดียวกันก็มีการแลก session key ใหม่เพื่อให้ได้ forward secrecy ด้วย — รายละเอียดเพิ่มเติมอ่านได้จาก [4][5])

QUIC Handshake break down [3]

น่าจะพอเห็นภาพว่า ถึงแม้จะเป็น UDP แต่ก็มีการควบคุมให้สุดท้ายมันออกมาคล้ายๆ TCP handshake อยู่ดี. เพียงแต่ว่า เราไม่สามารถหยิบ TCP มาแก้อย่างที่เราอยากแก้ได้ เพราะมีปัญหากับ Operating system, Network device, และอื่นๆอีกมหาศาลบานตะไท. เราก็เลยหยิบ UDP ที่เป็น bare เปล่าๆมาแล้วเอา protocol QUIC ใหม่ไปครอบมันอีกทีนั่นเอง. ดังนั้นเป็น reliable แน่นอนครับ.

หรือเป็น flow diagram ก็ดูง่ายดีครับ

Client handshake flow [4]

ซึ่งถ้าดูจาก flow นี้แล้วจะเห็นว่า จริงๆแล้ว มันก็มีบางกรณีที่เป็นการเชื่อมต่อครั้งแรก แล้วเสียเวลามากกว่า 1-RTT ด้วย แต่โดยภาพรวมแล้ว QUIC มันจะไม่แย่กว่า TCP ครับ เพราะกรณีที่เลวร้ายที่สุด ก็คือต้องแลกเปลี่ยนข้อมูลกันไปเรื่อยๆ เสมือนที่เกิดขึ้นใน TCP นั่นเอง. หากสนใจ flow นี้อย่างลึก แนะนำ [4] ครับ.

นอกจากนี้ เนื่องจาก QUIC นั้น built over UDP และไม่ได้ต้องผ่านการ handshake ในการส่งข้อมูลก้อนแรก ทำให้มีสิ่งที่ต้องพิจารณาเพิ่ม คือ Source address spoofing และ Replay attack ซึ่งปกติแล้วใน TCP มี sequence number แนบไปกับทุก packet ทำให้แก้ปัญหาสองข้อนี้ได้. ส่วนใน QUIC นั้นมองว่าสองข้อนี้ แก้ได้ด้วยสิ่งอื่น

A. Source address spoofing

QUIC แก้ปัญหานี้ด้วยการส่ง Source-address token ไปแทน ซึ่งในมุมของ client คือก้อน string มั่วๆที่จำเป็นต้องส่งให้ server ทุกครั้ง. ส่วนในมุม server มันคือ authenticated-encryption block (e.g. AES-GCM) ที่ประกอบด้วย client IP address และ timestamp ไว้. ซึ่งอาจจะมีหมดอายุ หรือ client เปลี่ยน IP address หรือว่า client จะไม่มีก็ตาม, server จะ reject connection ทิ้ง แล้วส่ง token นี้ให้ client ส่งมาใหม่แทน. ทั้งนี้หลายๆส่วน server สามารถตัดสินใจเองได้ เช่น ถ้าเปลี่ยน IP address แล้วจะต้อง REJ เสมอไหม หรือสามารถผ่อนปรนได้ (ในกรณี client ใช้ mobile) รวมทั้งการกำหนดระยะเวลาของ token เองด้วย (ยิ่งสั้น ยิ่งปลอดภัย)

B. Replay attack

Replay attack นั้นแก้ไขได้ง่ายด้วย TLS nonce อยู่แล้ว เพียงแต่ว่าในกรณีของ 0-RTT นั้น server ไม่มีโอกาสได้ส่ง nonce ไปเช็ค client เลย. การเช็คฝั่ง server อย่างเดียวว่า client ไม่ส่ง nonce ซ้ำนั้น จำเป็นต้องทำเป็น stateful ซึ่งใช้ resource สูงมาก โดยเฉพาะกรณีที่ server มีการทำ load/duplicate ไว้. QUIC จึง note ไว้ว่าไม่มีการป้องกัน replay attack ก่อนที่จะได้ first server reply. ใน chrome จึงอนุญาตให้เฉพาะ request GET (ที่ไม่เปลี่ยนแปลงข้อมูล ไม่ถูกกระทบจาก replay attack) ในการส่ง 0-RTT request เท่านั้น.

อันนี้ก็เป็นเฉลยสำหรับที่มาของ 0-RTT handshake นั่นเอง ไม่ใช่ magic อะไรเลยครับ และเป็น design ที่จริงๆแล้ว simple เข้าใจง่ายด้วยซ้ำ. ผู้อ่านอย่าเพิ่งคิดว่า QUIC หมดแค่นี้นะครับ ใน document QUIC จริงๆเนี่ย ส่วน connection เป็นส่วนที่ผมดูแล้วสั้นมาก (หลายสิบหน้าอยู่) เทียบกับส่วนอื่นๆ และ feature อื่นๆแล้ว ยาวกว่านี้เยอะเลยครับ XD

2. Stream Multiplexing

ปกติ connection เป็นท่อๆเดียว. การส่งข้อมูลต่างๆผ่านท่อ จำเป็นต้องเรียงลำดับ (Sequence number) ให้ถูกต้อง ก่อนจะส่งไปชั้น application ต่อได้. อันนี้ทำการแก้ใหม่ คือให้มีท่อย่อยหลายๆท่ออยู่ใน connection อีกที. ท่อย่อยๆนี้เรียกว่า stream. ในความเป็นจริงนั้นไม่ได้มีการแบ่งท่อจริงๆ แต่ logically ให้มี stream id กำกับในแต่ละ packet เพื่อใช้ระบุว่าไหนอยู่ท่อไหนอีกที.

ข้อดีคือ มันแก้ปัญหา head-of-line blocking บนชั้น transport ครับ เพื่อความง่ายขออธิบายไปพร้อมกับรูปเลยนะครับ [6]

อันนี้คือ กรณีทั่วไปของ HTTP/2 หรือ SPDY ครับ จะเห็นว่าเส้นปลายซ้ายขวามีการแบ่ง multiplexed บนชั้น application เรียบร้อยแล้ว ส่วน connection บนชั้น transport นั้นมีเพียง TCP เส้นเดียว. สีของ packet ทำให้เห็นลำดับได้ชัดเจน จะเห็นว่าลำดับส่งก่อน ต้องถึงก่อน ห้ามแซง ห้ามสลับ ห้ามหาย.

สมมติว่าถ้าสีแดงหาย (packet loss) ข้อมูล packet ด้านหลังทั้งหมดจะต้องรอจนกว่าฝั่งซ้ายจะรู้ว่า loss (อาจจะ timeout / nack / etc) แล้วทำการ retransmission packet สีแดงกลับมา ซึ่งเสียเวลาอย่างเห็นได้ชัด. multiplexing ของ HTTP/2 บนชั้น application ไม่สามารถทำอะไรกรณีนี้ได้เลย เปล่าประโยชน์ๆๆๆ. ยังไม่รวมกรณีที่ loss แล้วยังต้องถูกปรับ congestion window ให้ส่งได้น้อยลงอีกต่างหาก.

ใน QUIC จึงมีการทำ multiplexed บนชั้น transport ด้วย. เส้นใครเส้นมัน. หากสีแดง loss ก็ยังคงสามารถส่งสีเขียวและสีฟ้าขึ้นชั้น application ไปทำงานอย่างอื่นต่อได้ ช่วยแก้ปัญหา head-of-line blocking ชัดเจนครับ

3. Stream and connection flow control

แน่นอนว่ามันจำเป็นที่จะต้องมี flow control ในการควบคุมปริมาณ data ไม่ให้มันล้น buffer. ในกรณี QUIC ออกแบบมาคล้ายๆกับ HTTP/2 เลย คือ

  • Stream flow control — ควบคุมปริมาณ data บน stream ใดๆ
  • Connection flow control — ควบคุมปริมาณ data ของทุก streams รวมกัน

การควบคุม flow control นั้นใช้ระบบ credit-based flow-control scheme (ซึ่งก็คล้ายๆกับ HTTP/2) คือให้ receiver ประกาศว่าตัวเองรับได้เท่าไรในแต่ละ stream หรือ connection ให้กับ sender. ส่วน sender นั้นก็ต้องปฎิบัติตาม credit ให้ถูกต้อง ห้ามส่งเกิน. มี frame สำหรับให้ sender บอก receiver ได้ว่า credit ตัวเองหมดแล้ว และก็มี frame สำหรับให้ receiver เพิ่ม credit ให้ sender ได้เช่นกัน. ไม่มีลด credit นะครับ เพิ่มแล้วเพิ่มเลย.

4. Flexible congestion control

เรื่องนี้ผมมีความรู้ค่อนข้างอ่อนอาจจะเข้าใจผิดได้ แต่พยายามอ่านมาเขียนให้เข้าใจง่ายๆครับ. เป็นเนื้อหาที่ผมมองว่าเยอะที่สุดใน document QUIC เลย

ถึงแม้จะ based on UDP แต่คงปฎิเสธไม่ได้ว่า congestion control คือสิ่งที่จำเป็นในการควบคุม reliability ของ connection. เพียงแต่ว่า TCP congestion control นั้นก็เกิดมาหลายสิบปีแล้ว ตั้งแต่ยุค internet ยุคแรกเลย ทำให้ไอเดียและค่าคงที่หลายค่านั้น ค่อนข้างล้าสมัยไปแล้ว. QUIC จึงเลือกที่จะนำ congestion control ของ TCP มาปรับปรุงให้เข้ากับยุคสมัยปัจจุบันครับ โดยแก้คุณสมบัติของ packet ต่างๆด้วย. [7] เนื่องจากไอเดียหลายๆอย่างมีความคล้ายคลึงกับ TCP ทาง QUIC เลยยกข้อที่แตกต่างจาก TCP มาดังนี้

A. Sequence number

ใน TCP เนี่ย seq no มีลักษณะเพิ่มขึ้นเรื่อยๆก็จริง แต่ในกรณีที่เกิด retransmission เนี่ย จะทำให้เกิดความกำกวมขึ้นมา เพราะกลายเป็นว่ามี 2 packets ที่มี data เหมือนกัน และ seq no เหมือนกันด้วย. ส่วนใน QUIC จึงออกแบบไว้ว่า เพิ่มขึ้นอย่างเดียวเท่านั้น ต่อให้ packet loss ก็จะส่ง packet ใหม่ด้วย seq no ใหม่ครับ.

B. No Reneging

ใน QUIC ก็มีการเก็บและส่งข้อมูลคล้ายๆ TCP SACK นั่นแหละ แต่จะไม่อนุญาตให้ ack packet ถูก reneging ได้ เพื่อให้ง่ายต่อการ implement และพัฒนา performance (อันนี้ผมเข้าใจว่า ส่วนนี้ต่อไปจะไม่ใช้คำว่า SHOULD แต่จะใช้คำว่า MUST เพื่อลดความซับซ้อนลง)

C. More ACK ranges

มีการ support ACK ranges ที่มากขึ้น ซึ่งจะช่วยแก้ปัญหาในกรณี high loss environment (เช่น มือถือ), เพิ่มความเร็วการ recovery, ลด spurious retransmission (ส่งซ้ำเพราะคิดว่า loss แต่จริงๆไม่ได้ loss) และช่วยให้ทำงานต่อๆไปได้ โดยไม่ต้องรอ timeout. เพิ่มจาก 3 SACK เป็น 256 NACK ranges แทน.

และก็มีการปรับปรุงไอเดียของ TCP เดิมหลายตัว ดังนี้

A. Generating Acknowledgements

QUIC มองว่าควรมีการ delay ack เพื่อป้องกัน spurious retransmission (ที่เกิดบ่อยในกรณี out of order packet). และเพื่อป้องกันปัญหาที่อาจเกิดขึ้นจาก delay ก็มีการบังคับให้ packet บางประเภทนั้นระบุห้าม delay ได้ และก็มีการตั้ง max_ack_delay เอาไว้ด้วย โดย default ที่ 25 ms (เหมาะสมตามสภาพ internet ปัจจุบัน)

B. Loss Detection

เป็นเนื้อหาเกี่ยวกับการเก็บข้อมูลว่าอะไร loss ไม่ loss ครับ โดยใช้ข้อมูลทั้งจาก ack และ timeout ในการ detect loss เหมือนที่พบใน TCP แต่มีรายละเอียดเพิ่มเติมในส่วนการ implementation คำนวณ RTT. [7] detection แบ่งได้เป็น

  • Acknowledgement-based Detection สำหรับกรณีทั่วไป ตรวจจับ loss โดยมีเงื่อนไขว่า packet นั้นไม่ถูก ack กลับมาและถูก ack ของ packet อื่นแซงไปเกินค่า threshold หรือเกินเวลามากไปแล้ว. ทั้งนี้ก็มี time และ packet threshold ไว้สำหรับรองรับ reordering. และ
  • Timeout Loss Detection สำหรับกรณีที่ไม่สามารถใช้ ack-based ได้ เช่น กรณี CRYPTO frames, Retry and Version negotiation packet เป็นต้น อีกกรณีคือ probe packet สำหรับกรณี probe timeout แล้วให้ยิงไปเพื่อบังคับให้อีกฝั่งส่ง ack กลับมา.

โดยรวมแล้วเน้นการ track ข้อมูล packet ให้ครบถ้วนมากขึ้นครับครับ. ซึ่งจะช่วยเพิ่มความแม่นยำการคำนวณ​ estimate RTT, เพิ่มความถูกต้องในการตัดสินใจว่าเป็น loss, delay แล้วควร retransmission หรือไม่อย่างไร เป็นต้น

C. Congestion Control

เริ่มมาบรรทัดแรก QUIC ก็เปิดเลย ว่าอ้างอิงส่วนใหญ่จาก TCP NewReno [RFC6582] แต่เลือกที่จะวัด congestion window จาก bytes มากกว่าจำนวน packets. บังคับว่าห้ามส่งปริมาณข้อมูลที่จะทำให้ bytes_in_flight มากกว่า congestion window และสุดท้ายก็บอกว่าต้นทาง ปลายทางอาจจะมี congestion algorithm ที่แตกต่างกันก็ได้ ไม่เป็นประเด็น. โดยรวมแล้วคล้ายๆ TCP มากครับ.

  • Explicit Congestion Notification (ECN) [RFC8311] — ถ้าปลายทาง support ECN ก็สามารถส่ง packet ที่มี Congestion Experienced codepoint ได้เลย
  • Slow Start — QUIC เริ่ม connection ที่ phase นี้และจะออกเมื่อ loss หรือได้รับ ECN-CE เพิ่ม. ส่วน congestion window เพิ่มตามจำนวน ack ที่ได้รับเลย (โตเป็น exponential rate คล้ายๆใน TCP)
  • Congestion Avoidance — ใช้ท่าเดียวกับ TCP NewReno (ประมาณว่าถ้าอยากรู้ลึกให้ไปอ่านอันนั้นต่อมั้ง) เป็นท่า additive increase multiplicative decrease (AIMD). เพิ่มทีละ 1 packet size ต่อ ack และลด congestion window ครึ่งหนึ่งเมื่อเกิด loss และตั้งค่า slow start threshold เป็นค่านี้แทน.

ส่วน congestion พอแค่นี้ดีกว่า เพราะมันก็คล้าย TCP มาก มันมีรายละเอียดต่างกันเล็กน้อย พวกค่า default/constant ต่างๆ ซึ่งตรงเล็กน้อยนี่แหละที่จะช่วยพัฒนา performance ได้. ผมเขียนสรุปมาให้เห็นว่าไอเดียมันก็คล้ายๆ TCP นี่เอง ส่วนถ้าอยากรู้ลึกเพื่อนำไปใช้ (ใช้ทำไรหว่า) ก็ลงไปดู document version ล่าสุดเองเลยดีกว่าครับ. [7]

5. Connection Migration

Connection Migration ไม่ใช่ Multipath นะครับ !! เป็นการเพิ่ม feature ในการย้าย connection ข้าม endpoint (เปลี่ยน IP address หรือ port) โดยใช้ข้อมูล connection ID และให้ความสามารถ client ในการขอย้ายครับ. ยกตัวอย่างเช่น NAT rebinding คือมีการเปลี่ยน port หรือ ถ้าใช้มือถืออยู่ อาจจะอยากย้าย connection จาก Cellular มาเป็น Wifi เป็นต้น ก็จะสามารถใช้ connection ใหม่ต่อได้เลยครับ. ทั้งนี้ผมยังไม่เห็น API ที่ใช้เรียกส่วนนี้ว่ามันจะ simple, transparency ขนาดไหน รวมทั้ง load balancer หรือ NAT router ก็ยังไม่ support แต่เข้าใจว่าเป็นการวางพื้นฐานเอาไว้ให้อนาคตเติบโตได้ครับ. [8]

NAT rebinding ที่สามารถจะเกิดขึ้นได้ทั่วไป

เนื้อหาอื่นๆ

1. QUIC Discovery

แน่นอนว่าทุก browser, server ไม่ได้ support QUIC ดังนั้นจะต้องมีการทำการ discovery ก่อนเสมอ ไม่งั้นส่งไปก็โดนเตะทิ้ง ไหนจะถูกบล็อคจาก firewall อีก. เรื่องนี้ไม่ได้มีระบุ best practice ไว้ชัดเจน แต่ก็สามารถ follow ตาม Chrome ได้ดังนี้ [9][10]

  1. สำหรับ client-server connection แรก ไม่เคยคุยกันมาก่อน. ให้สร้าง TCP connection แล้วส่ง HTTP request ปกติจาก client ไป server
  2. หาก server ตอบมี header Alt-Svc: hq=”:50781" มาด้วยแปลว่า server นั้นรองรับ HTTP QUIC. client ก็จะพยายามสร้าง QUIC connection ต่อไปยัง server โดยที่ยังเปิด TCP connection ไว้เหมือนเดิม. (ส่วนกรณี server ไม่ support ก็จบ ไม่ต้องพูดถึง)
  3. หาก QUIC connection นั้นถูก establish สำเร็จ. client จะเริ่มส่ง HTTP request บน QUIC connection นี้
  4. หาก QUIC connection นั้น establish ไม่สำเร็จ ก็จะใช้ connection TCP เดิมต่อไป เหมือนไม่มีอะไรเกิดขึ้น. ดังนั้นการเปิด support QUIC ก็จะไม่ทำให้ performance เสีย
  5. สำหรับ client-server ที่เคยคุยกันแล้ว. client จะมีข้อมูลแล้วว่า server นี้ support QUIC ให้ทำการสร้าง QUIC connection และ TCP connection พร้อมกัน ซึ่งในกรณีทั่วไป QUIC 0-RTT จะชนะ แล้ว browser จะเลือกใช้ QUIC. หากกรณีถูก block ก็จะใช้ TCP connection อีกอันตามปกติแทน

ไอเดียค่อนข้างสวยและเรียบง่ายนะครับ ถ้าไม่รู้ว่า support หรือไม่ support ก็เปิด connection ทั้งสองตัวไปเลย แล้วตัวไหนทำงานได้ ทำได้ดีกว่า ค่อยเลือกตัวนั้น.

2. Forward Error Correction

เรื่องนี้เข้าใจว่าเคยเป็น feature ทดลองอันหนึ่งใน QUIC แต่เนื่องจากทำให้ performance เสีย จึงเอาออกไปแล้ว (ถ้าอ่านเจอก็ไม่ต้องแปลกใจ) อันนี้ให้อารมณ์คล้ายๆ RAID-4 คือมีการใส่ error correction bit เข้าไปใน packet อื่นๆด้วย ถ้าเกิดมี packet ใด loss ก็สามารถสร้าง packet ที่ loss จาก packet อื่นได้ทันทีเลย แต่เพราะว่าต้องใส่ correction bit ในทุก packet แล้วยังใช้งานไม่ได้ถ้า loss >2 อีก ทำให้ performance เสียมากกว่าดีครับ. [11]

QUIC Performance

ขออ้างผล performance จาก paper ของ Google เองเมื่อปี 2017 เลยนะครับ [12]

โดยวัด handshake latency เริ่มจากเวลาที่ได้รับ QUIC Client Hello (หรือ TCP SYN) จนถึงเวลาที่ handshake สมบูรณ์. สำหรับ 0-RTT QUIC นั้น latency จะเป็น 0ms (ไม่ได้แสดงในกราฟ) โดยนับไปเป็น 88% ของ QUIC connection ที่พบจริง. พอเฉลี่ยกับกรณี 1-RTT QUIC แล้ว (เส้นสีน้ำเงินอ่อน) จะได้ค่าเฉลี่ยออกมา (เส้นสีน้ำเงินเข้ม) ต่ำกว่า TCP ทั่วไปพอสมควรเลย.

Latency มีลดไปตั้งแต่ 5–16% เลยทีเดียว. ทั้งนี้การลด Rebuffer Rate คาดว่าเกิดจากการ improve loss recovery rate ใน QUIC ด้วย.

ในส่วนของ Server CPU Utilization พบว่า QUIC มีการใช้งาน CPU มากกว่า TLS/TCP มากถึง 3 เท่า และเมื่อพยายาม tune performance ต่างๆ (เช่น เปลี่ยน cipher) ก็พบว่ายังมากถึง 2 เท่าอยู่ดี. ทั้งนี้ยังมี room ที่สามารถ improve performance ได้อยู่ก็จริง แต่คาดว่ายังไงก็สูงกว่า TLS/TCP แน่นอน.

ส่วนปริมาณ host ที่ support QUIC ไม่ค่อยสูงมากครับ มาสูงช่วงที่ Akamai เริ่ม support ให้. อันนี้ให้อารมณ์เหมือน HTTP/2 ครับ คือหลายคนไม่ต้องไป config server ใหม่เอง ให้ CDN จัดการ middle ให้แทน.

ให้ CDN เป็น proxy ให้ โดยที่ server ด้านหลังเป็น HTTP/1.1 อยู่ช่วยได้จริงหรือ

เกริ่นด้วยรูปคงเห็นภาพเลย ช่วยได้เพราะเราลดระยะเวลาที่คุย HTTP/1.1 ลงนั่นเอง และถ้า CDN/proxy อยู่ใกล้ server มากเท่าไร ก็ยิ่งช่วยให้ดีขึ้นมาก. จากรูปแสดงให้เห็นแค่ส่วนของ handshake นะครับ ส่วนของ loss, retransmission, multiplexed streams ก็มีผลเหมือนกัน แต่มันวาดรูปออกมาให้เห็นภาพยากกว่าเท่านั้น

Future

ในขณะที่ QUIC version 1 ค่อนข้างเสถียรแล้ว ก็ยังคงมีกลุ่มพัฒนา QUIC อยู่เรื่อย ๆ ครับซึ่งคงเรียกว่า QUIC version 2 ในอนาคตคาดว่าจะมี feature บางตัวเพิ่มขึ้นมา ซึ่งทั้งหมดนี้ยังอยู่ในช่วงศึกษาวิจัย [15] ได้แก่

  1. Multipath — การใช้ multiple path เช่น ใช้งานทั้ง WiFi และ Mobile Network พร้อมกันเพื่อเพิ่ม throughput และความเสถียรภาพ เป็นต้น
  2. Forward Error Correction — ไอเดียเดิมตามที่ได้กล่าวไว้ก่อนหน้า เพียงแต่เอาออกจาก version 1 ก่อนและเอามาวิจัยเพื่อเพิ่มประสิทธิภาพกันอยู่
  3. Unreliable Streams — ในเมื่อ QUIC ก็อยู่บน UDP อยู่แล้ว ถ้าในกรณีที่เราอยากส่ง data บางประเภทที่สามารถ loss ได้ เราก็น่าจะใช้ UDP บน QUIC อีกทีได้นะ เราก็จะสามารถส่งทั้ง reliable และ unreliable ใน connection เดียวกันได้
  4. More application protocols — อันนี้ผมมองว่าคือเป้าหมายของ IETF ระยะยาว เขานำ protocol Google เนี่ยมาปรับให้เป็น standard มาขึ้นเพื่อให้ application อื่น ๆ นอกจาก HTTP สามารถนำ QUIC ไปใช้ต่อยอดได้ด้วย

ปัจจุบันที่กำลังจะใช้งาน QUIC v1 อยู่ เพื่อความเสถียร เขาจึง freeze features ต่าง ๆ ไปแล้ว ผู้ใช้งานจะไม่พบ feature ข้อ 1–3 แน่นอนครับ ผมแนะนำว่าเพื่อความเข้าใจที่ถูกต้องและ updated ผู้อ่านควรอ้างอิงจาก RFC draft ล่าสุด, workspace ของทีม chromium หรือ HTTP/3 Explained ของ Daniel Stenberg [16] ครับ

สรุป

ทั้งหมดนี้ผู้อ่านน่าจะเข้าใจไอเดียภาพรวม (ที่ลงลึกหน่อย) ว่า QUIC คืออะไร ทำงานอย่างไร มีอะไรบ้าง และได้ผลออกมาดีแค่ไหน. ถึงแม้ว่าตัว QUIC เองยังไม่ได้ standardize แต่เราคงได้เห็น standard ออกมาในชื่อของ HTTP/3 เร็วๆนี้ครับ. เราอาจจะไม่ได้เข้าไปแตะหรือคลุกคลีกับมันโดยตรง แต่ผมก็หวังว่าการเข้าใจไอเดียหลายๆอย่าง จะช่วยจุดประกาย ช่วยให้ความรู้ว่าโลกเราไปถึงไหนแล้ว แล้วก็ไม่ถูกหลอกขายของ magic ๆ จากคนอื่นครับ XD

- Feb 7, 2019 -
- Oct 24, 2019 - [Add: Future]

Reference

[1] https://datatracker.ietf.org/meeting/98/materials/slides-98-edu-sessf-quic-tutorial-00.pdf
[2] https://tools.ietf.org/html/draft-ietf-quic-transport-18
[3] https://docs.google.com/presentation/d/15e1bLKYeN56GL1oTJSF9OZiUsI-rcxisLo9dEyDkWQs/edit
[4] https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit
[5] https://tools.ietf.org/html/draft-ietf-quic-tls-13#section-5.1.1
[6] https://docs.google.com/presentation/d/13LSNCCvBijabnn1S4-Bb6wRlm79gN6hnPFHByEXXptk/present
[7] https://www.ietf.org/id/draft-ietf-quic-recovery-18.txt
[8] https://blog.cloudflare.com/the-road-to-quic/
[9] https://docs.google.com/document/d/1i4m7DbrWGgXafHxwl8SwIusY2ELUe8WX258xt2LFxPM/edit
[10] https://tools.ietf.org/html/draft-ietf-quic-http-15#section-2.2
[11] https://medium.com/@codavel/quic-vs-tcp-tls-and-why-quic-is-not-the-next-big-thing-d4ef59143efd
[12] https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/46403.pdf
[13] https://blog.apnic.net/2018/05/15/how-much-of-the-internet-is-using-quic/
[14] https://docs.google.com/document/d/1i4m7DbrWGgXafHxwl8SwIusY2ELUe8WX258xt2LFxPM/edit
[15] https://www.youtube.com/watch?v=idViw4anA6E
[16] https://http3-explained.haxx.se/en/

--

--

Bank Eakasit
Bank Eakasit

Responses (2)