Text
Page: 1
Ruby, Ractor, QUIC
unasuke (Yusuke Nakamura)
RubyKaigi Takeout 2021
2021-09-11
Page: 2
Self introduction
Name: unasuke (Yusuke Nakamura)
Work: freelance Web app developer
OOParts (Cloud Gaming Service) backend dev
Itamae gem maintainer, Kaigi on Rails staff
GitHub https://github.com/unasuke
Mastodon https://mstdn.unasuke.com/@unasuke
Twitter https://twitter.com/yu_suke1994
Page: 3
Next generation Web
widespreading Web usage
Cloud Gaming
Video meeting
Streaming media
We want the Web to be faster!
Page: 4
Cloud Gaming requiement
"real-time bidirectional communication"
1. Send player's input to the game on the cloud machine
2. The game render the input result
3. Send result to the player's screen (web browser)
Repeat the above process as soon as possible for comfortable game play.
(Same as remote working collaboration)
Page: 5
Way to real-time bidirectional communication on the Web
Now
WebRTC
WebSocket
Future?
WebTransport
a new server-client protocol over the HTTP/3
use UDP
status: draft → https://datatracker.ietf.org/group/webtrans/documents/
Page: 6
HTTP/3
A new hyper text transfer protocol (draft)
This document defines HTTP/3, a mapping of HTTP semantics over the
QUIC transport protocol
https://datatracker.ietf.org/doc/draft-ietf-quic-http/
"QUIC" ? What is this?
Page: 7
QUIC
standardized at 2021-05-27 by IETF
More faster than HTTP/2
Using UDP, not TCP
Page: 8
Tweet by ko1
https://twitter.com/_ko1/status/1282963500583628800
Page: 9
Tweet by ko1
two people
@_ko1 (Koichi Sasada)
Ruby core commiter
Ractor author
@kazuho (Kazuho Oku)
author of h2o
QUIC RFC contributor
Sounds interesting!
Page: 10
What, Why QUIC
HTTP uses TCP/IP
TCP is reliable, but slow
Oriented data transfer
Retransmission of lost packets
Congestion control
UDP is unreliable, but fast
realtime transfer e.g. audio
Page: 11
What, Why QUIC - TCP's problem
Three way handshake
additional TLS handshake (at secure communication)
Head-of-Line Blocking (HoLB)
QUIC is a new latency-reducing, reliable, and secure internet transport
protocol
https://www.fastly.com/blog/quic-is-now-rfc-9000
Page: 12
Is there a benefit?
Why imprement QUIC on Ruby?
1. For my study and interest
2. For Ractor
There are still few examples of Ractor
helps evaluation and improvement of Ractor
e.g. https://github.com/mame/optcarrot
Page: 13
QUIC - Initial Packet (RFC9001 Appendix A)
Page: 14
QUIC - reading Initial Packet
Page: 15
QUIC - reading Initial Packet
Page: 16
QUIC - reading Initial Packet
Page: 17
QUIC - reading Initial Packet
Page: 18
QUIC - reading Initial Packet
Page: 19
QUIC - reading Initial Packet
Page: 20
n月刊ラムダノート Vol.2, No.1(2020)
#1 パケットの設計から見るQUIC(西田佳史)
https://www.lambdanote.com/collections/frontpage/products/nmonthly-vol-2-no-1-2020
Page: 21
QUIC - reading Initial Packet by Ruby
Page: 22
QUIC - reading Initial Packet by Ruby
It causes Ractor::IsolationError when use in not main Ractor
Page: 23
QUIC - reading Initial Packet by Ruby
I cannot read this, and ruby cannot read it bit by bit.
Page: 24
QUIC - reading Initial Packet by Ruby
How to read each "bit" in Ruby?
"A" ← 0x41 (ASCII-8BIT)
"A" ← 0b01000001 (ASCII-8BIT)
"A" → ? → "01000001"
Page: 25
QUIC - reading Initial Packet by Ruby
Use "Array#pack", "String#unpack1"
"A".unpack1("B*") # => "01000001"
["01000001"].pack("B*") # => "A"
Now, we can each "bit" by Ruby!
Page: 26
Handling packet by Ractor
How do we handling UDP packet by Ractor?
Page: 27
Handling packet by Ractor - think about QPACK
QPACK (Header Compression for HTTP/3)
Static Table
"content-encoding gzip" (values that appear many times)
Dynamic Table
per client-server
e.g. user-agent
→ Create ractor per client that has a dynamic table state...
Page: 28
Handling packet by Ractor - UDP echo server by Ractor
3 classes
Server class
Router class
Connection class
Page: 29
UDP echo server by Ractor - Server class
Page: 30
UDP echo server by Ractor - Router class
Page: 31
UDP echo server by Ractor - Connection class
Page: 32
benchmarking by udpbench
https://github.com/unasuke/udpbench
Improvised UDP benchmark tool written Go.
Send-receive UDP packet that contain UUIDv4 from goroutines.
Page: 33
Result of benchmark UDP echo server by Ractor
$ ./udpbench --count 100 --parallelism 100
Total request count : 10000
Total request time : 10m48.446641s
Time per packets : 64.844664ms
Failed count : 0
Page: 34
simple UDP echo server
Page: 35
Result of benchmark simple UDP echo server
$ ./udpbench --count 100 --parallelism 100
Total request count : 10000
Total request time : 7.5696799s
Time per packets : 756.967µs
Failed count : 0
x85 faster than Ractor impl
Page: 36
Let's decrypt QUIC packet in Ractor
Page: 37
Let's decrypt QUIC packet in Ractor
Failed by OpenSSL::Cipher.new
Can OpenSSL rb_ext_ractor_safe(true) ...?
Page: 38
Wait, I heard about yesterday...
'Standard libralies are already ractor-safe' by ko1
I heard about that in "Ruby Committers vs the World" yesterday.
Page: 39
OpenSSL is `rb_ext_ractor_safe(true)`
Wow...
Page: 40
Conclusion
There are two problems
Libraies that cannot use in not main Ractor
useful gem → imprement myself (e.g. bindata)
core lib → DEEP DIVE to fix this (e.g. openssl)
Need many many code to imprement QUIC
Mozilla's Neqo : 50,000 LoC (Rust) https://github.com/mozilla/neqo
aioquic : 17,000 LoC (Python) https://github.com/aiortc/aioquic
Ruby : ?