And here it is ๐ My template for Ruby's notorious web router Roda - running on the JVM (JRuby)! ๐
Start the server with $ rackup
, then benchmark (see below) as unscientifically as possible (but easy as pie), using HTTPie:
๐คซ or for production sth like: $ jruby --server -S bundle exec rackup -o 0 -E production
$ time http :9292/jsondata >/dev/null
sucks 25mb from your server ๐งโโ๏ธ
Add rodauth to have a proper user account management ๐คฏ
I cannot really say why JRuby intriqued me, since I fell in love with Ruby.
But, JRuby never felt especially beginner friendly. ๐ฌ
Something didn't work. Very tough to google. JDBC what?
Java docs?! Java ecosystem?! They do what? How on earth? Cheesus ... ๐คข
- curious Rubyists, struggling to find a use case of getting something up with JRuby
- those who want get hold of JRuby, without the suspicious feeling that Rails takes care of everything behind the curtains (it's why we love you, Rails, you know that! ๐)
- People curious of Roda
- PORO lovers
- Rack fanboys
- Sinatra / Fastify / FastAPI / Gin
- Java people / JVM users โ๏ธ
- those on a journey, they don't know, they are on: Ruby โก JRuby โก Clojure โฎ๏ธ
Your Java version should be pinned to 11.x
as this is what the CI is running on. MacOS checks for JRuby run on Java v8.
if one of you gets this going on another OS, please submit a PR with some handy notes โ๏ธ
$ docker build . -t joda
$ docker run --rm -it -p9292:9292 joda
For aarch64 (e.g. Mac M1):
$ docker run -ti --env LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2 --rm -p9292:9292
For x86_64:
$ docker run -ti --env LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 --rm -p9292:9292
๐
$ docker run -ti --env LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2 --rm -p9292:9292 rackup -o 0 -E production
please, see the docs of your asdf-vm java plugin (docs of the default java plugin ๐). It's about JRuby having Java in it's PATH.
Then fire the following commands:
$ asdf install java microsoft-17.35.1
$ asdf reshim
$ asdf install ruby jruby-9.4.1.0
$ bundle install -j4
$ jruby -S rackup
$ jruby --profile.graph -S rackup
This is how you could use it for production:
$ jruby -J-Xmx512m --server -S rackup -E production
- minimum and maximum Java heap size to 512 MB
- optimization for server ON
- runs Rack in production mode
or:
$ jruby -J-Xms2g -J-Xmx2g --server -J-Djruby.thread.pool.enabled=true -S rackup -E production
FIRST OF ALL the JVM had some requests before the benchs to warm up a little
BUT let's be honest the server wasn't fresh and had already other stuff to do
AND had just 2 cores (but 8 gigs of RAM ๐
)
AND for sure I missed an opportunity for tweaking something
BECAUSE the JVM still is completely new to me at this point
SO this is worthless, but some just need to see some numbers
well, enough whining...
Benchmarking with ab:
$ ab -n 1000 -c 10 -k -H "Accept-Encoding: gzip, deflate" "https://joda.test.test/hello/world"
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking joda.test.test (be patient)
[...shortened...]
Server Software:
Server Hostname: joda.test.test
Server Port: 443
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-CHACHA20-POLY1305,4096,256
Server Temp Key: ECDH X25519 253 bits
TLS Server Name: joda.test.test
Document Path: /hello/world
Document Length: 38 bytes
Concurrency Level: 10
Time taken for tests: 11.268 seconds
Complete requests: 1000
Failed requests: 0
Keep-Alive requests: 0
Total transferred: 166000 bytes
HTML transferred: 38000 bytes
Requests per second: 88.74 [#/sec] (mean)
Time per request: 112.685 [ms] (mean)
Time per request: 11.268 [ms] (mean, across all concurrent requests)
Transfer rate: 14.39 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 49 78 14.4 77 137
Processing: 12 33 22.0 22 113
Waiting: 11 23 12.1 17 77
Total: 64 111 26.2 105 244
Percentage of the requests served within a certain time (ms)
50% 105
66% 117
75% 126
80% 131
90% 151
95% 164
98% 176
99% 186
100% 244 (longest request)
Benchmarking with wrk:
$ wrk -t10 -c10 -d30s "https://joda.test.test/hello/world"
Running 30s test @ https://joda.test.test/hello/world
10 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 23.21ms 15.14ms 81.68ms 84.52%
Req/Sec 46.87 15.47 80.00 62.34%
14065 requests in 30.10s, 2.07MB read
Requests/sec: 467.21
Transfer/sec: 70.28KB
Model Name | MacBook Pro |
Model Identifier | MacBookPro18,1 |
Chip | Apple M1 Pro |
Total Number of Cores | 10 (8 performance and 2 efficiency) |
Memory | 16 GB |
Entering this fancy new rabbit hole, here's what didn't work, or may well be served with butter in the future
when load testing /jsondata/items
route:
-
H2 database is run with
single_threaded: true
and seems to be able to handle higher loads nicely ๐ https://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html#label-General+connection+options -
H2 database may crash though, especially without
single_threaded
option, and throw horrifying errors, I propose you use Postgres/MySQL/AnyOtherProperDB for mimicking "real-life" server simulation
there's so much beauty in Roda, so it would be nice to showcase more of it.
I suggest you stumble through the following websites:
- Roda's Website
- Federico's and Avdi's Book: Mastering Roda
- Jeremy Evans' Code Lair (sequel, rodauth, and many more)
-
large file json taken from:
https://github.com/json-iterator/test-data/blob/master/large-file.json -
Inspiration sparked the amazing Ruby for all Podcast ๐ You guys rock!
Tags/Keywords: Ruby, JRuby, Java, Roda, Sequel, JDBC, Puma, REST, API, JSON