Skip to content

Latest commit

 

History

History
145 lines (106 loc) · 7.34 KB

README.md

File metadata and controls

145 lines (106 loc) · 7.34 KB

UP Logo

(Original Image by Freepik, modified though)

UP!

A high performance Rack server for Opal Ruby and Matz Ruby, Tech Demo

Let Numbers speak first

Response type:               env.to_s                    "hello_world"
                 Requests/Second   Latency       Requests/Second   Latency
Puma:              8884.53 req/s  15.18 ms        50822.38 req/s   2.62 ms
Unicorn:          12302.35 req/s  10.22 ms        16329.68 req/s   7.68 ms
Falcon:           13168.82 req/s   9.49 ms        24041.63 req/s   5.26 ms
Racer:            14536.88 req/s   8.94 ms        15354.14 req/s   8.44 ms
Agoo:             49078.57 req/s   2.54 ms        89022.91 req/s   1.51 ms
Iodine:           59116.53 req/s   2.11 ms <<<   134267.79 req/s   0.93 ms
Up! bun:           3900.44 req/s  32.00 ms        47334.16 req/s   2.64 ms
Up! ruby cluster: 53641.29 req/s   2.35 ms       128237.52 req/s   0.97 ms
Up! uWS cluster:  20143.62 req/s   6.20 ms       152353.97 req/s   0.82 ms <<<

<<< denotes the fastest for the response type

running on/with:
Linux, Kernel 6.5.0-x
ruby 3.3.0, YJit enabled
Opal 2.0-dev as of 9. Feb 2024, with node v20.11.0
Puma 6.4.2, 4 workers, 4 threads
Falcon 0.43.0, 4 workers, 4 threads
Racer 0.1.3, defaults
Unicorn 6.1.0, 4 workers
Agoo 2.15.8, 4 workers, 4 threads
Iodine 0.7.57, 4 workers, 1 thread
Up! bun 0.0.4, 1 worker
Up! uWS cluster 0.0.4, 4 workers
Up! Ruby cluster 0.0.4, 4 workers

running the example_rack_app from this repo, benchmarked with:
bombardier http://localhost:3000/
and taking the Avg

on a Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz

Introduction

This is currently mainly a technical demonstration, demonstrating the speed of the Opal Ruby implementation employing Node and uWebSocketJs as runtime.

Its not yet a generic, all purpose Rack server, but good for further experimentation, research and open for improvement. The included ruby version allows for verification of code correctness and performance. If it works with bundle exec up_ruby it should work equally well with the various Opal versions, at least thats the future goal.

Its a intention of this project, to serve as a tool for enhancing Opal Ruby and porting Rack apps from Matz to Opal Ruby.

Getting started

To start experimenting:

  • clone this repo
  • cd into it, bundle install
  • cd example_rack_app
  • bundle install
  • bundle exec up

You may want to change the gem 'opal-up' line in the Gemfile to use up from rubygems, if you want to run your app outside of the cloned repo.

For a Gemfile available from rubygems: gem 'opal-up'

Available Commands

Available with bundle exec within the example apps or if this gem is included in your Gemfile:

  • up - starts a cluster of workers using Opal with uWebSockets, fastest server
  • up_bun - starts single worker server using Bun, requires Opal bun support from PR#2622
  • up_ruby - starts a cluster of workers using Ruby with uWebSockets in a native extension, does not support the --secure options/TLS
Usage: up [options]

    -h, --help                       Show this message
    -p, --port PORT                  Port number the server will listen to. Default: 3000
    -b, --bind ADDRESS               Address the server will listen to. Default: localhost
    -s, --secure                     Use secure sockets.
When using secure sockets, the -a, -c and -k options must be provided
    -a, --ca-file FILE               File with CA certs
    -c, --cert-file FILE             File with the servers certificate
    -k, --key-file FILE              File with the servers certificate
    -l, --log-file FILE              Log file
    -P, --pid-file FILE              PID file
    -v, --version                    Show version
    -w, --workers NUMBER             For clusters, the number of workers to run. Default: number of processors

Supported Features

Up! implements the Rack Spec as of Rack 3.0 with the following differences:

  • rack.hijack is not implemented, but rack.upgrade instead is, see "Websockets" below
  • Tempfile support is currently incomplete, affecting a few keys in the Rack Env ('tempfile' missing in Opal).
  • Some Rack modules/classes still have issues when run in Opal and may not work as expected

Websockets are supported following the Iodine SPEC-WebSocket-Draft. PubSub is supported following the Iodine SPEC-PubSub-Draft, except for engines.

A example RackApp using WebSockets and PubSub is provided in the 'example_rack_ws_app' directory

Roda

A example app for Roda is provided and appears working with the following patches applied:

Please note the phrase "appear to work" in above sentences. To try:

  • clone Rack 3.0.9 and Roda 3.76
  • apply the patch sets above
  • set paths in the example_roda_app to point to your cloned rack & roda repos
  • and up! the server

Sinatra, others ...

... currently do not work! A example app for Sinatra is provided, for convenience of developing and expanding the capabilities of Opal.

About the Benchmarks

The benchmarks mainly test the overhead introduced by the rack server.

In the 'env.to_s' benchmark, the Rack environment access and response header handling overhead are measured. Simply calling env.to_s accesses all keys and serializes them briefly. If the Rack app accesses the keys of the Rack environment and sets response headers, the overhead/latency as measured can be expected, or that amount of requests per second can be expected at most.

The "hello_world" benchmark measures the overhead for the simplest possible version of a meaningful Rack response and should provide maximum performance. If the Rack app just replies with a string, that overhead/latency can be expected, or that amount of requests per second can be expected at most.

Links

Rack Servers