Ruby, Ractor, QUIC

: author

unasuke (Yusuke Nakamura)

: content-source

RubyKaigi Takeout 2021

: date

2021-09-11

: theme

theme

Self introduction

* Name: unasuke (Yusuke Nakamura)
* Work: freelance Web app developer
  * OOParts (Cloud Gaming Service) backend dev
* Itamae gem maintainer, Kaigi on Rails staff
* (('tag:x-small')) GitHub ((<URL:https://github.com/unasuke>))
* (('tag:x-small')) Mastodon ((<URL:https://mstdn.unasuke.com/@unasuke>))
* (('tag:x-small')) Twitter ((<URL:https://twitter.com/yu_suke1994>))

# image
# src = img/icon_face.jpeg
# relative_width = 24
# align = right
# relative_margin_right = -8
# relative_margin_top = 33

Next generation Web

widespreading Web usage n

* Cloud Gaming
* Video meeting
* Streaming media

We want the Web to be faster!

Cloud Gaming requiement

((*“real-time bidirectional communication”*)) n

(1) Send player's input to the game on the cloud machine (1) The game render the input result (1) 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)

Way to real-time bidirectional communication on the Web

HTTP/3

A new hyper text transfer protocol (draft)

# blockquote
This document defines HTTP/3, a mapping of HTTP semantics over the QUIC transport protocol

((<URL:https://datatracker.ietf.org/doc/draft-ietf-quic-http/>))

“QUIC” ? What is this?

QUIC

* standardized at 2021-05-27 by IETF
* More faster than HTTP/2
* Using UDP, not TCP

# image
# src = img/quic.svg
# relative_width = 55
# align = right

(('tag:right')) (('tag:xx-small')) nnnn Logo from ((<URL:quic.tech>))

Tweet by ko1

# image
# src = img/ko1_tweet.png
# relative_width = 57

(('tag:xx-small')) (('tag:center')) ((<URL:twitter.com/_ko1/status/1282963500583628800>))

Tweet by ko1

two people

Sounds interesting!

# image
# src = img/ko1_tweet.png
# relative_width = 55
# align = right

What, Why QUIC

What, Why QUIC - TCP's problem

* Three way handshake
  * additional TLS handshake (at secure communication)
* Head-of-Line Blocking (HoLB)

# blockquote
QUIC is a new latency-reducing, reliable, and secure internet transport protocol

((<URL:https://www.fastly.com/blog/quic-is-now-rfc-9000>))

Is there a benefit?

Why imprement QUIC on Ruby?

(1) For my study and interest (1) For Ractor

* There are still few examples of Ractor
* helps evaluation and improvement of Ractor
  * e.g. ((<URL:https://github.com/mame/optcarrot>))

QUIC - Initial Packet (RFC9001 Appendix A)

# image
# src = img/quic_initial_packet.png
# relative_width = 59

QUIC - reading Initial Packet

# image
# src = img/quic_initial_packet_reading_1.png
# relative_width = 90

QUIC - reading Initial Packet

# image
# src = img/quic_initial_packet_reading_2.png
# relative_width = 90

QUIC - reading Initial Packet

# image
# src = img/quic_initial_packet_reading_3.png
# relative_width = 90

QUIC - reading Initial Packet

# image
# src = img/quic_initial_packet_reading_4.png
# relative_width = 90

QUIC - reading Initial Packet

# image
# src = img/quic_initial_packet_reading_5.png
# relative_width = 90

QUIC - reading Initial Packet

# image
# src = img/quic_initial_packet_reading_6.png
# relative_width = 90

n月刊ラムダノート Vol.2, No.1(2020)

# image
# src = img/nmonthly-vol-2-no-1-2020.png
# relative_width = 26

(('tag:center')) (('tag:xx-small')) (('#1 パケットの設計から見るQUIC(西田佳史)'))n ((<URL:www.lambdanote.com/collections/frontpage/products/nmonthly-vol-2-no-1-2020>))

QUIC - reading Initial Packet by Ruby

# image
# src = img/bindata.png
# relative_width = 80

QUIC - reading Initial Packet by Ruby

# image
# src = img/bindata.png
# relative_width = 80

It causes ((Ractor::IsolationError)) when use in not main Ractor

QUIC - reading Initial Packet by Ruby

# image
# src = img/quic_initial_packet_string.png
# relative_width = 100

I cannot read this, and ruby cannot read it ((*bit by bit*)).

QUIC - reading Initial Packet by Ruby

How to read each “bit” in Ruby?

"A" ← 0x41 (ASCII-8BIT)
"A" ← 0b01000001 (ASCII-8BIT)
"A" → ? → "01000001"

QUIC - reading Initial Packet by Ruby

Use “Array#pack”, “String#unpack1”

# enscript ruby
"A".unpack1("B*") # => "01000001"
["01000001"].pack("B*") # => "A"

Now, we can each “bit” by Ruby!

Handling packet by Ractor

How do we handling UDP packet by Ractor?

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

(('&RightArrow;')) Create ractor per client that has a dynamic table state…🤔

Handling packet by Ractor - UDP echo server by Ractor

* 3 classes
  * Server class
  * Router class
  * Connection class

UDP echo server by Ractor - Server class

# image
# src = img/udp_echo_ractor_server.png
# relative_width = 75

UDP echo server by Ractor - Router class

# image
# src = img/udp_echo_ractor_router.png
# relative_width = 90

UDP echo server by Ractor - Connection class

# image
# src = img/udp_echo_ractor_connection.png
# relative_width = 90

benchmarking by udpbench

((<URL:github.com/unasuke/udpbench>))

Improvised UDP benchmark tool written Go.

Send-receive UDP packet that contain UUIDv4 from goroutines.

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

simple UDP echo server

# image
# src = img/udp_echo_simple.png
# relative_width = 90

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

(('tag:center')) (('tag:large')) x85 faster than Ractor impl 🤷‍♂️❓

Let's decrypt QUIC packet in Ractor

# image
# src = img/openssl_in_ractor.png
# relative_width = 100

Let's decrypt QUIC packet in Ractor

# image
# src = img/openssl_in_ractor.png
# relative_width = 100

Failed by (({OpenSSL::Cipher.new})) 😵

(('tag:xx-small')) Can OpenSSL (({rb_ext_ractor_safe(true)})) …?

Wait, I heard about yesterday…

# blockquote
'Standard libralies are already ractor-safe' by ko1

I heard about that in “Ruby Committers vs the World” ((yesterday)).

OpenSSL is `rb_ext_ractor_safe(true)`

# image
# src = img/openssl_rb_ext_ractor_safe_true.png
# relative_width = 100

Wow…

Conclusion

There are two problems