Save 37% off PRO during our Black Friday Sale! »

JRuby: Zero to Scale

F1d37642fdaa1662ff46e4c65731e9ab?s=47 headius
November 20, 2019

JRuby: Zero to Scale

JRuby is deployed by hundreds of companies, running Rails and other services at higher speeds and with better scalability than any other runtime. With JRuby you get better utilization of system resources, the performance and tooling of the JVM, and a massive collection of libraries to add to your toolbox.

In this talk, we'll cover:

* Getting started on JRuby
* Comparison to CRuby
* Building, migrating, and deploying apps
* Tuning, profiling, and monitoring
* Scaling considerations

F1d37642fdaa1662ff46e4c65731e9ab?s=128

headius

November 20, 2019
Tweet

Transcript

  1. JRuby: Zero to Scale Thomas E. Enebo (@tom_enebo) Charles O.

    Nutter (@headius)
  2. • JRuby co-leads • Red Hat Charles Thomas Ruby Java

    Beer
  3. What is JRuby? Ruby Implementation (2.5.7 compatible) …which happens to

    run on the Java Virtual Machine (JVM)
  4. JRuby 9.2.9.0 • Lots of memory and startup time improvements

    • Better support for Java module system • .jruby.java_opts file to manage JVM options • Improved startup time for most commands • Dozens of issues fixed
  5. Getting JRuby in 3 Steps

  6. Step 1: You Need a JVM • Java (version 8

    or 11 recommended) • Is it installed? java -version • If !installed • package install: dnf/apt install java • explicit install: http://adoptopenjdk.net
  7. Step 2: Install JRuby

  8. Step 2: Install JRuby on Windows www.jruby.org

  9. Step 3: Profit!

  10. Why JRuby? What are the differences? - JRuby - C

    Ruby
  11. Native Threads vs Global Interpreter Lock

  12. require 'benchmark' ary = (1..1000000).to_a loop { puts Benchmark.measure {

    10.times { ary.each {|i|} } } } Unthreaded require 'benchmark' ary = (1..1000000).to_a loop { puts Benchmark.measure { (1..10).map { Thread.new { ary.each {|i|} } }.map(&:join) } } Multi-threaded
  13. Ruby 2.5.7 unthreaded JRuby unthreaded Ruby 2.5.7 threaded JRuby threaded

  14. Time (in seconds) 0 0.09 0.18 0.27 0.36 Unthreaded Threaded

    0.15 0.23 0.35 0.34 CRuby JRuby (lower is better)
  15. Virtual Machine vs Going It Alone

  16. Ruby Teams Hiro Marcin Nahi Subbu Douglas Christian Karol Tom

    Charlie Hiro charli Nahi zzak nurse hsbt matz ko1 nobu OS (libc, ...) JRuby MRI
  17. Ruby Teams Hiro Marcin Nahi Subbu Douglas Christian Karol Tom

    Charlie Hiro charli Nahi zzak nurse hsbt matz ko1 nobu OS (libc, ...) JRuby MRI JVM POSIX
  18. JVM Ruby Teams Hiro Marcin Nahi Subbu Douglas Christian Karol

    Tom Charlie Hiro charli Nahi zzak nurse hsbt matz ko1 nobu OS (libc, ...) JRuby MRI Better ??? POSIX
  19. !Perspective! ??? Total control can be great!

  20. Shoulders of Giants JVM J. Rose J. Rose J. Rose

    J. Rose J. Rose J. Rose J. Rose J. Rose J. Rose Hiro Marcin Nahi Subbu Douglas Christian Dmitry Tom Charlie JRuby
  21. All the stuff! JVM J. Rose J. Rose J. Rose

    J. Rose J. Rose J. Rose J. Rose J. Rose J. Rose Garbage Collection Native JIT Profiled Optimizations Native Threading Tooling Cross Platform
  22. Alternate JVMs • Hotspot: standard OpenJDK Java VM • OpenJ9:

    open source version of IBM's J9 JVM • New GC and JIT tuning options • Startup time and JIT code-caching features • GraalVM: replaces Hotspot JIT with Graal JIT • New JIT optimizations, ahead-of-time native compilation
  23. JVM is everywhere++! • Unix++, Windows • Exotic platforms: zLinux,

    OpenVMS, AS/400 • Mobile: Android’s Dalvik, Embedded JVMs
  24. Java bytecode == portability

  25. actionmailer-javamail, active_documentum, activerecord-jdbc-adapter, activerecord-jdbcdbf-adapter, activerecord-jdbcderby-adapter, activerecord-jdbch2-adapter, activerecord-jdbchsqldb-adapter, activerecord-jdbcmssql-adapter, activerecord-jdbcmysql-adapter, activerecord-jdbcpostgresql-adapter,

    activerecord-jdbcsqlite3- adapter, activerecord-netezza-adapter, activerecord-vertica-adapter, akephalos, akephalos-nerian, akephalos2, akka-actor-jars, akka-remote-jars, akubra_llstore_migrate, Antwrap, async-http-client-jars, atomic, atoulme-Antwrap, autotest-java, bbrowning-deltacloud-client, bbrowning-deltacloud-core, bcrypt- ruby, bee_java, berkeley-db-java-jars, bert, bio-maf, blockenspiel, boc, bond, bosdk, bouncy-castle-java, boxed-geminabox, brute-fuzzy, bryanl-gherkin, bson, buby, buildr, buildr-resolver, buildrizpack, butternut, capistrano-java, capybara-java_script_lint, carrierwave-neo4j, carrierwave_imagevoodoo, cassandra-jars, chrest, cloby, commons-io-jars, concurrently, contextual, coupler, cucumber-java, cucumber-jvm, cuke4duke, cuuid, dm-ldap-adapter, dm-lucene-adapter, do-jdbc_sqlserver, do_derby, do_h2, do_hsqldb, do_jdbc, do_mysql, do_openedge, do_oracle, do_postgres, do_sqlite3, do_sqlserver, doubleshot, dripdrop, dubious, duby, engineyard-visualvm, epall-limelight, errbit_zmq_handler, eurydice, euston, euston-daemons, euston-eventstore, euston-projections, euston-rabbitmq, euston- websites, eventmachine, excemel, faye-websocket, ffi, fig, file-find, fishwife, foreman, forkit, forkjoin, gamelan, gemshit, geoip-jars, get_back, gherkin, glassfish, gravitext-util, gravitext-xmlprod, grizzly, guava-jars, hadoop-find, hashdot-test-daemon, hiredis, hitimes, hope, hostor, hot_bunnies, hourglass, hpricot, http_parser.rb, inline_javascript, iudex, iudex-async-httpclient, iudex-barc, iudex-brutefuzzy-protobuf, iudex-brutefuzzy-service, iudex-char-detector, iudex-core, iudex-da, iudex-filter, iudex-html, iudex-http, iudex-http-test, iudex-httpclient-3, iudex-jetty-httpclient, iudex-rome, iudex-simhash, iudex-worker, ivy-jars, iyyov, jactive_support, java-autotest, java-inline, java2ruby-xmldsig, java_bin, java_inline, java_override, java_properties, java_streamify, java_testing_guff, javabean_xml, javaclass, javaeye4r, javagems, javajake, javaobj, javaobjs, javaobs, javaparse, javasand, javascript-securehash-rails, javascript-state-machine-rails, javascript_auto_include, javascript_eraser, javascript_features, javascript_i18n, javascript_localize, javascript_safe_logger, javascript_util_asset_pack, javascripto, javascripto-rails, jdbc-derby, jdbc-hsqldb, jdbc-jtds, jdbc-openedge, jdbc-openedge-internal, jdbc-postgres, jdbc-sqlite3, jedis-jars, jena-jruby, jessica, jettr, jetty, jetty- jsp, jgeoip, jms4r, jpdfer, jrack_handlers, jrtm, jruby-activemq, jruby-akka_jars, jruby-elasticsearch_jars, jruby-httpclient, jruby-launcher, jruby-management, jruby- metrics, jruby-pageant, jruby-vijava, jruby_gc_stats, jruby_sandbox, jruby_threach, jrubyconf-button, jsmetric4java, json, json-jruby, jsound, kb-activerecord-jdbc- adapter, kirk, kyotocabinet-java, ladle, latex-decode, launchy, libnotify, limelight, linecache, logback, logback-jars, looksee, lumix, mack-javascript, markdownj, maven_irb_plugin, metrics-core-jars, metrics-java, mguymon-buildr, mikka, mini_aether, mirah, mirah_model, miso-java, mixology, mm_mq, mongrel, msgpack-idl- java, msgpack-jruby, multimeter, naether, nanoc-javascript-concatenator, neo4j, neo4j-admin, neo4j-advanced, neo4j-community, neo4j-core, neo4j-enterprise, neo4j-spatial, neo4j-will_paginate, neo4j-wrapper, netty-jars, ning-compress-jars, nio4r, nokogiri, nokogiri-fitzsimmons, nokogiri-maven, nosqoop4u, ontomde- demo-java5, ontomde-java, ontomde-java-frontend, ontomde-uml2-java, ontomde-uml2-kbjava, open_nlp, pacer, pacer-dex, pacer-neo4j, pacer-orient, pelops-jars, persvr, pg_array_parser, protobuf-jars, pry, puma, qtjruby-core, qwirk_active_mq_adapter, qwirk_jms_adapter, rabbitmqadmin-cli, ragweed, rails_javascript_helpers, rakejava, rave, rcov, realityforge-jekyll, realityforge-jekylltask, redcar-bundles, redcar-clojure, redcar-filter-through-command, redcar- groovy, redcar-icons, redcar-javamateview, redcar-javascript, redcar-mirah, redcar-svnkit, redcar-xulrunner-win, RedCloth, refinerycms-javascripts, reigns, revo- nokogiri, rika, rjack-async-httpclient, rjack-commons-codec, rjack-commons-dbcp, rjack-commons-dbutils, rjack-commons-pool, rjack-httpclient-3, rjack- httpclient-4, rjack-icu, rjack-jackson, rjack-jdom, rjack-jets3t, rjack-jetty, rjack-jetty-jsp, rjack-jms, rjack-jms-spec, rjack-logback, rjack-lucene, rjack-maven, rjack- mina, rjack-nekohtml, rjack-protobuf, rjack-qpid-client, rjack-rome, rjack-slf4j, rjack-solr, rjack-tarpit, rjack-xerces, rmagick4j, rmodbus, rtm-javatmapi, rtm- majortom, rtm-ontopia, rtm-tinytim, rtm-tmql, rubeus, rubinius-core-api, ruby-blockcache, ruby-debug-base, ruby-maven, ruby2java, rubydoop, rubyjedi- nokogiri_java, scala-inline, scala-library-jars, scriptty, slf4j, slf4j-jars, slyphon-zookeeper, slyphon-zookeeper_jar, smackr, smartimage, SNMP4JR, solr_sail, spiegela- jruby-httpclient, sproutcore, spymemcached, sqldroid, steamcannon-deltacloud-client, steamcannon-deltacloud-core, stilts-stomp-client, supermarket, svm_toolkit, swt, theduke, thick, to-javascript, torquebox-base, torquebox-cache, torquebox-configure, torquebox-container-foundation, torquebox-core, torquebox- messaging, torquebox-messaging-container, torquebox-naming, torquebox-naming-container, torquebox-security, torquebox-server, torquebox-vfs, torquebox- web, twitter4j4r, UDJrb, unageanu-javaclass, unimidi, universe-javascript, url_escape, weakling, webbit-jars, wildnet-jackson, wildnet-netty, wildnet-server, wildsonet-hazelcast, wildsonet-netty, wildsonet-server, wildsonet-streamer, wrest, wrong, xdojava, xqruby, zookeeper No build tools!
  26. Ruby C Extensions vs Java Native Extensions

  27. Why Extensions? • Performance • Access Existing Library (e.g. openssl)

  28. C Extensions • API is massive • API is specific

    to C Ruby’s implementation • It is the implementation • At odds with concurrent Ruby execution • Huge support cost
  29. Java Native Extensions • API is massive • API is

    specific to JRuby’s implementation • It is the implementation* • Allows Concurrent Ruby Execution • Support cost minimal • Common Gems Supported * We have plans for a formal API
  30. oj: Optimized json • Fast json parsing and dumping with

    many options • Common transitive dependency with its own API • Needed for many popular apps/libraries https://github.com/ohler55/oj
  31. oj for JRuby! • 9200 lines of Java (vs 20k

    lines of C) • Almost ready: 448 runs, 765 assertions, 43 failures, 12 errors • 35 F/E from minor features, date/time diffs
  32. Load Performance 0M 0.3M 0.6M 0.9M 1.2M small medium large

    0.13 0.29 1.1 0.05 0.11 0.36 0.06 0.11 0.72 MRI (oj) JRuby (json) JRuby (oj) Millions of loads per second (higher is better) https://techblog.thescore.com/2014/05/23/benchmarking-json-generation-in-ruby/
  33. Dump Performance 0 0.75 1.5 2.25 3 small medium large

    0.44 0.86 2.3 0.22 0.44 1.1 0.33 0.73 2.1 MRI (oj) JRuby (json) JRuby (oj) Million of dumps per second (higher is better) https://techblog.thescore.com/2014/05/23/benchmarking-json-generation-in-ruby/
  34. Scripting Java

  35. Scripting Java • Access Java Classes using a Ruby Syntax

    • Java Libraries • Give alternatives to existing Ruby Libraries • Give access to APIs which do not exist in Ruby
  36. JRuby IRB

  37. Fun Stuff event(:player_egg_throw) do |e| e.hatching = true e.num_hatches =

    120 e.player.mesg "hatched" end Purugin https://github.com/enebo/Purugin
  38. JRuby Performance

  39. Startup Time • Runtime optimizations give us excellent performance •

    ...eventually! • Startup time, warmup time are impacted • We continue working to reduce this impact • We compare some common commands
  40. JRuby Architecture Ruby (.rb) JIT Java Instructions (java bytecode) Ruby

    Instructions (IR) parse interpret interpreter interpret C1 compile native code better native code java bytecode interpreter execute C2 compile Java Virtual Machine JRuby Internals deoptimize Performance improves the longer your app runs
  41. JRuby Flag: --dev • export JRUBY_OPTS="--dev" • Disables JRuby's JIT

    • Reduces JVM JIT • Don't use when benchmarking! • 30-40% reduction • More improvements coming total execution time (lower is better) 0s 1.15s 2.3s 3.45s 4.6s gem list (~350 gems) 3.0s 4.6s JRuby JRuby --dev
  42. 0 1 2 3 4 gem list 3.05 0.939 CRuby

    JRuby --dev
  43. 0 1.75 3.5 5.25 7 rails console 6.7 4.96 CRuby

    JRuby --dev
  44. OpenJDK Class Data Sharing • Pre-validate and cache class data

    • Save frequently-accessed data over time • Combined with --dev gives best current JRuby startup
  45. Java 11 total execution time (lower is better) 0 1.75

    3.5 5.25 7 gem list (~350 gems) JRuby --dev --dev + CDS
  46. App Performance • Sinatra and Roda • https://github.com/CaDs/ruby_benchmarks • Comparing

    JRuby, CRuby, and TruffleRuby • RedMine bug tracker and wiki • https://www.redmine.org/ • Real-world Rails application on JRuby, CRuby
  47. Peak Performance • After initial startup, warmup, data caching •

    JRuby generally gives better peak performance • Be aware of warmup time
  48. Sinatra and Roda requests/second (higher is better) 0 12500 25000

    37500 50000 Sinatra Roda 5,214 4,257 44,703 42,468 14,489 12,284 CRuby JRuby TruffleRuby
  49. Redmine Issue View, rendered and json (higher is better) 0

    req/s 35 req/s 70 req/s 105 req/s 140 req/s issues/13 issues/13.json 137 req/s 50 req/s 91 req/s 41 req/s CRuby 2.6.2 JRuby 9.2.9
  50. Warmup Time • Large applications take longer to warm up

    • Working on new JIT metrics, profiling to reduce this curve
  51. Sinatra performance over time, requests/second 0rps 12500rps 25000rps 37500rps 50000rps

    5s 10s 15s 20s 25s CRuby JRuby
  52. Roda performance over time, requests/second 0rps 12500rps 25000rps 37500rps 50000rps

    5s 10s 15s 20s 25s CRuby JRuby
  53. Redmine issues/13.json warmup, one-minute cycles 0 35 70 105 140

    1st 2nd 3rd 4th 5th 6th CRuby 2.6.2 JRuby 9.2.9
  54. Redmine memory usage (lower is better) 0MB 375MB 750MB 1125MB

    1500MB Memory usage for 8 workers vs 8 threads 800MB 1,430MB 1,100MB CRuby JRuby (default) JRuby (300MB heap)
  55. Migrating An App

  56. Migration Process • Existing application Activities: • Configuration Changes (e.g.

    config/database.yml) • C extensions replacement • Thread-safety audit
  57. Use-Case: Discourse • “A platform for community discussion” • Very

    large, well-known Rails application • >500 gems • 250,000 lines of Ruby • JRuby is not currently supported • But it is almost working!
  58. Step 1: jruby-lint

  59. jruby-lint gem See how ready your Ruby code is to

    run on JRuby $ gem install jruby-lint $ cd my-app $ jrlint
  60. [] ~/projects/discourse $ jrlint JRuby-Lint version 0.9.0 ./Gemfile:: [gems, info]

    For more on gem compatibility see http://wiki.jruby.org/C-Extension-Alternatives ./Gemfile:80: [gems, warning] Found gem 'oj' which is reported to have some issues: Try `gson`, `json` or `json_pure` instead.| gem 'oj' ./Gemfile:81: [gems, warning] Found gem 'pg' which is reported to have some issues: Use activerecord-jdbcpostgresql-adapter instead or pg_jruby (drop-in replacement).| gem 'pg' ./Gemfile:187: [gems, warning] Found gem 'mysql2' which is reported to have some issues: Use activerecord-jdbcmysql-adapter.| gem 'mysql2' ./Gemfile:188: [gems, warning] Found gem 'redcarpet' which is reported to have some issues: Same as with **RDiscount** use alternatives such as kramdown, Maruku or markdown_j| gem 'redcarpet' ./Gemfile:189: [gems, warning] Found gem 'sqlite3' which is reported to have some issues: Use activerecord-jdbcsqlite3-adapter.| gem 'sqlite3', '~> 1.3.13' ./app/mailers/user_notifications.rb:152: [nonatomic, warning] Non-local operator assignment (@popular_topics) is not guaranteed to be atomic. @popular_topics = topics_for_digest[0, SiteSetting.digest_topics] ./app/mailers/user_notifications.rb:630: [nonatomic, warning] Non-local operator assignment (@site_name) is not guaranteed to be atomic. @site_name = SiteSetting.email_prefix.presence || SiteSetting.title # used by I18n ./app/models/report.rb:21: [nonatomic, warning] Non-local operator assignment (@start_date) is not guaranteed to be atomic. @start_date ||= Report.default_days.days.ago.utc.beginning_of_day ./app/models/report.rb:22: [nonatomic, warning] Non-local operator assignment (@end_date) is not guaranteed to be atomic. @end_date ||= Time.now.utc.end_of_day ./app/models/admin_dashboard_next_data.rb:17: [nonatomic, warning] Non-local operator assignment (@json) is not guaranteed to be atomic. @json ||= get_json ./app/models/topic_posters_summary.rb:31: [nonatomic, warning] Non-local operator assignment (@descriptions_by_id) is not guaranteed to be atomic. @descriptions_by_id ||= begin ./app/models/topic_posters_summary.rb:33: [nonatomic, warning] Non-local operator assignment (descriptions[id]) is not guaranteed to be atomic. descriptions[id] ||= [] ./app/models/topic_posters_summary.rb:79: [nonatomic, warning] Non-local operator assignment (@avatar_lookup) is not guaranteed to be atomic. @avatar_lookup ||= options[:avatar_lookup] || AvatarLookup.new(user_ids) ./app/models/topic_posters_summary.rb:83: [nonatomic, warning] Non-local operator assignment (@primary_group_lookup) is not guaranteed to be atomic. @primary_group_lookup ||= options[:primary_group_lookup] || PrimaryGroupLookup.new(user_ids) ./app/models/directory_item.rb:8: [nonatomic, warning] Non-local operator assignment (@headings) is not guaranteed to be atomic. @headings ||= [:likes_received, ./app/models/directory_item.rb:18: [nonatomic, warning] Non-local operator assignment (@types) is not guaranteed to be atomic. @types ||= Enum.new(all: 1, ./app/models/group_history.rb:11: [nonatomic, warning] Non-local operator assignment (@actions) is not guaranteed to be atomic. @actions ||= Enum.new( ./app/models/locale_site_setting.rb:10: [nonatomic, warning] Non-local operator assignment (@values) is not guaranteed to be atomic. @values ||= supported_locales.map do |locale| ./app/models/locale_site_setting.rb:25: [nonatomic, warning] Non-local operator assignment (@language_names) is not guaranteed to be atomic. @language_names ||= begin ./app/models/locale_site_setting.rb:41: [nonatomic, warning] Non-local operator assignment (@supported_locales) is not guaranteed to be atomic. @supported_locales ||= begin ./app/models/category.rb:98: [nonatomic, warning] Non-local operator assignment (TOPIC_CREATION_PERMISSIONS) is not guaranteed to be atomic. TOPIC_CREATION_PERMISSIONS ||= [:full] ./app/models/category.rb:99: [nonatomic, warning] Non-local operator assignment (POST_CREATION_PERMISSIONS) is not guaranteed to be atomic. POST_CREATION_PERMISSIONS ||= [:create_post, :full] ./app/models/category.rb:109: [nonatomic, warning] Non-local operator assignment (@topic_id_cache) is not guaranteed to be atomic. @topic_id_cache = DistributedCache.new('category_topic_ids') ./app/models/category.rb:228: [nonatomic, warning] Non-local operator assignment (@@cache) is not guaranteed to be atomic. @@cache ||= LruRedux::ThreadSafeCache.new(1000) ./app/models/category.rb:520: [nonatomic, warning] Non-local operator assignment (@has_children) is not guaranteed to be atomic. @has_children ||= (id && Category.where(parent_category_id: id).exists?) ? :true : :false
  61. Unsupported Extensions ./Gemfile:: [gems, info] For more on gem compatibility

    see http://wiki.jruby.org/C-Extension-Alternatives ./Gemfile:80: [gems, warning] Found gem 'oj' which is reported to have some issues: Try `gson`, `json` or `json_pure` instead.| gem 'oj' ./Gemfile:81: [gems, warning] Found gem 'pg' which is reported to have some issues: Use activerecord-jdbcpostgresql-adapter instead or pg_jruby (drop-in replacement).| gem 'pg' ./Gemfile:187: [gems, warning] Found gem 'mysql2' which is reported to have some issues: Use activerecord-jdbcmysql-adapter.| gem 'mysql2' ./Gemfile:188: [gems, warning] Found gem 'redcarpet' which is reported to have some issues: Same as with **RDiscount** use alternatives such as kramdown, Maruku or markdown_j| gem 'redcarpet' ./Gemfile:189: [gems, warning] Found gem 'sqlite3' which is reported to have some issues: Use activerecord-jdbcsqlite3-adapter.| gem 'sqlite3', '~> 1.3.13'
  62. None
  63. Threading Concerns ./app/models/report.rb:21: [nonatomic, warning] Non-local operator assignment (@start_date) is

    not guaranteed to be atomic. @start_date ||= Report.default_days.days.ago.utc.beginning_of_day ./app/models/report.rb:22: [nonatomic, warning] Non-local operator assignment (@end_date) is not guaranteed to be atomic. @end_date ||= Time.now.utc.end_of_day ./app/models/admin_dashboard_next_data.rb:17: [nonatomic, warning] Non-local operator assignment (@json) is not guaranteed to be atomic. @json ||= get_json ./app/models/topic_posters_summary.rb:31: [nonatomic, warning] Non-local operator assignment (@descriptions_by_id) is not guaranteed to be atomic. @descriptions_by_id ||= begin ./app/models/topic_posters_summary.rb:33: [nonatomic, warning] Non-local operator assignment (descriptions[id]) is not guaranteed to be atomic. descriptions[id] ||= [] ./app/models/topic_posters_summary.rb:79: [nonatomic, warning] Non-local operator assignment (@avatar_lookup) is not guaranteed to be atomic. @avatar_lookup ||= options[:avatar_lookup] || AvatarLookup.new(user_ids) ./app/models/topic_posters_summary.rb:83: [nonatomic, warning] Non-local operator assignment (@primary_group_lookup) is not guaranteed to be atomic. @primary_group_lookup ||= options[:primary_group_lookup] || PrimaryGroupLookup.new(user_ids) @language_names) is not guaranteed to be atomic. @language_names ||= begin
  64. Unsupported Features ./script/measure.rb:48: [objectspace, warning] Use of ObjectSpace is expensive

    and disabled by default. Use -X+O to enable. ObjectSpace.each_object do |o| ./script/check_forking.rb:14: [fork, error] Kernel#fork is not implemented on JRuby. child = fork do ./script/check_forking.rb:17: [fork, error] Kernel#fork is not implemented on JRuby. grand_child = fork do
  65. Step 2: Replace C Extensions

  66. % bundle install Fetching pg 1.1.4 Installing pg 1.1.4 with

    native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension gem 'pg' Gemfile Gemfile gem 'pg', platform: :mri gem 'activerecord-jdbcpostgresql-adapter', platform: :jruby
  67. Missing C Extension 1.Remove it if not needed (development dep

    like byebug) 2.Use a pure-Ruby version if performance is good enough 3.Call into a native library using FFI (Foreign Function Interface) 4.“Script” a Java library 5.Write a JRuby extension
  68. Step 3: Run It • Once your application bundles, it

    should run! • If not talk to us or file an issue puma -t 20:20 -e production
  69. Monitoring and Profiling

  70. JVM Tooling • Visual VM: monitor and profile threads, GC,

    managed heap • Mission Control: visualize Flight Recorder output • Flight Recorder: low-overhead system profiling in OpenJDK • async-profiler: command line profiles, flame graphs of CPU, alloc • All JVM tools work to monitor and profile JRuby apps
  71. VisualVM • Standalone graphical console for monitoring, profiling • Open

    sourced as part of OpenJDK project • https://visualvm.github.io/
  72. None
  73. Visual VM and Visual GC

  74. JDK Flight Recorder • JVM flag: -XX:+FlightRecorder • JRuby flag:

    -J-XX:+FlightRecorder or put in JAVA_OPTS • Add --flight-recorder to JRuby launcher? • No overhead or profiling until you start recording • And usually less than 1% overhead for that
  75. JDK Mission Control • Control center and visualizer for Flight

    Recorder data • Start and manage recordings • Browse recorded data • https://adoptopenjdk.net/jmc.html
  76. None
  77. None
  78. None
  79. None
  80. None
  81. None
  82. async-profiler • JVM extension for lightweight sampled profiles • Install

    jruby-async-profiler gem • jruby -J-agentpath:<jruby home>/lib/libasyncProfiler.so • Simplified command lines coming soon • See https://github.com/jvm-profiling-tools/async-profiler
  83. None
  84. Final Words

  85. Getting Help • JRuby on GitHub: https://github.com/jruby/jruby • Issues, Wiki

    • Chat with JRuby devs, users • jruby on Matrix • #jruby on Freenode IRC • Mailing list: https://lists.ruby-lang.org
  86. During Development • JRUBY_OPTS=--dev • BE WARY of .ruby-version •

    Don’t share gem paths between Ruby implementations • Java and C extensions clobber each other
  87. Java Modules • Java 9+ introduced Java Modules • You'll

    see warnings about JRuby or Ruby accesses • New config file for JVM flags: .jruby.java_opts • Gather JVM options into a single file • Current dir, home dir, JRuby bin/ dir
  88. Java Modules and .jruby.java_opts WARNING: An illegal reflective access operation

    has occurred WARNING: Illegal reflective access by org.bouncycastle.jcajce.provider.drbg.DRBG (file:/Users/headius/.m2/repository/org/ bouncycastle/bcprov-jdk15on/1.61/bcprov-jdk15on-1.61.jar) to constructor sun.security.provider.Sun() WARNING: Please consider reporting this to the maintainers of org.bouncycastle.jcajce.provider.drbg.DRBG WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release --add-opens java.base/java.io=org.jruby.dist --add-opens java.base/java.nio.channels=org.jruby.dist --add-opens java.base/sun.nio.ch=org.jruby.dist --add-opens java.management/sun.management=org.jruby.dist
  89. Try JRuby!

  90. Let us know if you have any questions!

  91. Thank You! • @headius, @tom_enebo • https://www.jruby.org • https://github.com/jruby/jruby •

    Chat with JRuby devs, users • #jruby on Freenode IRC • jruby on Matrix • Mailing list: https://lists.ruby-lang.org