Scaling Rails With Torquebox Presented at JUDCon:2011 Boston

Scaling Rails With Torquebox Presented at JUDCon:2011 Boston
Scaling Rails Applications
     with TorqueBox
         Ben Browning
Ben Browning
•TorqueBox Contributor
•Red Hat Senior Engineer since July 2010
•Ruby yay! JVM yay! Java boo! JRuby yay!
The Team
TorqueBox
•The power of JBoss with the expressiveness of Ruby
•Rails, Sinatra, Rack and non-web applications running
 on top of JBoss AS and JRuby
•Messaging, Asynchronous Tasks, Scheduled Jobs, and
 Services built-in
Rails
“Ruby on Rails® is an open-source web framework
that’s optimized for programmer happiness and
sustainable productivity. It lets you write beautiful code
by favoring convention over configuration.” - http://
rubyonrails.org
Scaling
Ability to increase throughput by adding hardware
Learn By (Beer) Example
Let’s create an application to find the most popular beer
according to Twitter.
Beer Tweets
•Web front-end
•Twitter Streaming API client
•Scheduled job to clean old beer tweets
•Caching so our database doesn’t fall over
Web Front-end
class BeersController < ApplicationController

 def most_popular
  @popular_beers = Beer.most_popular(:limit => 25)
 end

end
Twitter Streaming API Client
•Connect to Twitter’s streaming API and find all tweets
 containing “beer”
•Needs to run as a daemon, outside of the web
 request / response cycle
TorqueBox Services
•Long-running, non-web daemons that share the
 runtime environment and deployment lifecycle of your
 app
•A class with initialize( Hash ), start(), and stop()
 methods
Twitter Streaming API Client
class BeerService

 def initialize(options)
  @client = StreamingTwitter.new(options["username"],
                         options["password"])
 end

 def start
  Thread.new { find_beer }
 end

 def stop
  @client.disconnect
 end

end
Twitter Streaming API Client
class BeerService

 def find_beer
  @client.search('beer') do |tweet|
   Beer.create_from_json(tweet)
  end
 end

end
Twitter Streaming API Client
config/torquebox.yml:

services:
 beer_service:
  username: ilikebeer
  password: sodoyou
Clean Stale Beer
•Delete all beer-related tweets older than 7 days
•Run once an hour to prune in manageable chunks
Scheduled Jobs
•Tasks that need to be executed on a recurring
 schedule
•A class with a run() method
Clean Stale Beer
class BeerCleaner

 def run()
  Beer.clean_older_than(7.days)
 end

end
Clean Stale Beer
config/torquebox.yml:

jobs:
  beer_cleaner:
   description: Clean stale beer-related tweets
   job: BeerCleaner
   cron: '0 44 * * * ?'
Caching
We’re showing the same list of most popular beers to all
users so why hit the database on every request?
Caching Web Front-end
class BeersController < ApplicationController

 caches_action :most_popular, :expires_in => 30.seconds

 def most_popular
  @popular_beers = Beer.most_popular(:limit => 25)
 end

end
Beer Tweets
We’re collecting tweets about beer, serving the results
up via a cached web interface, and keeping our
database cleaned of stale data.
We’re Done, Right?
We’ve added all our features and deployed on
TorqueBox so we can handle limitless load, right?
Benchmarks
Benchmarks
We’re Done, Right?
No way - it’s beer and Twitter! This will be wildly
popular with social alcoholics and we need to plan
accordingly - we need to scale!
Performance != Scalability
Just because an application performs well on a single
server doesn’t mean it can scale.
Add More Servers
Well, before we can do that we need a load balancer to
route requests to multiple servers.
mod_cluster
The same mod_cluster you know and love to use with
JBoss AS works with TorqueBox.
mod_cluster
Based on Apache’s mod_proxy but with two-way
communication to JBoss and TorqueBox providing
intelligent request routing based on load.
mod_cluster
Add More Servers
As each TorqueBox instance boots it will find the other
TorqueBox and mod_cluster instances and add itself to
the cluster.
Sessions
•By default Rails stores all session data in cookies
•Production Rails applications usually use a database or
 memcached for session storage
•TorqueBox provides its own session storage
TorqueBox Sessions
config/initializers/session_store.rb:

BeerTweets::Application.config.
 session_store TorqueBox::Session::ServletStore
TorqueBox Sessions
•Server-side sessions without hitting the database or
 requiring an external process (memcached)
•Uses JBoss AS session replication under the hood
Are We Scaled Yet?
We’ve taken care of the load balancer and session
replication, but what about our Twitter Streaming API
client? How will it scale?
Twitter Streaming API Client
•By default our service will start on every node in the
 cluster
•Sometimes that’s what you want, but not in this case;
 we only want one copy of each beer tweet to be saved.
HASingleton Services
•TorqueBox supports highly-available singleton
 services
•The service will only run on one node in the cluster
•If that node goes down, another node will start the
 service
HASingleton Services
config/torquebox.yml:

services:
 beer_service:
  username: ilikebeer
  password: sodoyou
  singleton: true
Twitter Streaming API Client
•Now our service will only run on one node, but what
 happens if tweets come in from Twitter faster than that
 one node can process them?
Backgroundable
•Convert any method call into an asynchronous call
•Uses HornetQ under the hood and calls are load-
 balanced across the cluster
Backgroundable
class BeerService

 def find_beer
  @client.search('beer') do |tweet|
   Beer.background.create_from_json(tweet)
  end
 end

end
Asynchronous Tasks
class BeerTask < TorqueBox::Messaging::Task

 def create_from_json(payload)
  Beer.create_from_json(payload[:tweet])
 end

end
Asynchronous Tasks
class BeerService

 def find_beer
  @client.search('beer') do |tweet|
   BeerTask.async(:create_from_json, :tweet => tweet)
  end
 end

end
Twitter Streaming API Client
All nodes in our cluster will now process incoming
tweets even though only a single node maintains a http
connection to Twitter.
Now We’re Scaled, Right?
Not quite - we still have that pesky job that cleans stale
beer to deal with.
Clean Stale Beer
•By default, scheduled jobs will run on all nodes in a
 cluster.
•We only want our beer cleaning job to run on a single
 node.
HASingleton Jobs
config/torquebox.yml:

jobs:
  beer_cleaner:
   description: Clean stale beer-related tweets
   job: BeerCleaner
   cron: '0 44 * * * ?'
   singleton: true
All Scaled?
Almost! We still need to take care of our caching.
Caching
•Rails ships with support for multiple cache stores (file-
 based, in-memory, memcached)
•None allow multiple nodes to share a common cache
 without setting up an external process
TorqueBoxStore
•Rails 3 ActiveSupport::Cache::Store implementation
 backed by Infinispan
•Supports invalidated, replicated, and distributed
 clustering modes
TorqueBoxStore
module BeerTweets
 class Application < Rails::Application

  config.cache_store :torque_box_store(:mode => :distributed,
                         :sync => false)

 end
end
Are We Scaled?
As we add additional nodes to the cluster they increase
our web request throughput, background job
throughput, and cache capacity. We’re scaled!
But Wait, There’s More!
Injection
Inject CDI resources, messaging destinations, JNDI
entries, MBeans into your Ruby application

@questions = inject(‘/queues/questions’)
@datasource = inject(‘java:comp/env/jdbc/myDS’)
@thing = inject(com.mycorp.Something)
@bean = inject(‘SomeMCBean’)
Message Processors
class SeniorHandler < TorqueBox::Messaging::MessageProcessor

 def on_message(body)
  puts “Processing #{body} of #{message}”
 end

end
Message Processors
config/torquebox.yml:

messaging:
 /queues/people:
  SeniorHandler:
   filter: “age >= 55”
   concurrency: 2
Queues and Topics
questions = inject(‘/queues/questions’)
answers = inject(‘/queues/answers’)

Thread.new do
 questions.publish ‘What time is it?’
 puts answers.receive(:timeout => 1000)
end

puts questions.receive
answers.publish Time.now
Queues and Topics
config/torquebox.yml:

queues:
 /queues/questions:
 /queues/answers:
BackStage
Dashboard and RESTful API to inspect and control Ruby
components
BackStage
StompBox
Easy Heroku-esque git-based deployments
StompBox
Roadmap
1.0.0 Just Released!

Upcoming:
AS7
Transactions
SSO
Drools / jBPM
Mobicents
WebSockets
Resources
•http://torquebox.org
•https://github.com/torquebox
•#torquebox on FreeNode
•@torquebox
Thanks!
Questions?
1 of 67

More Related Content

What's hot(20)

Similar to Scaling Rails With Torquebox Presented at JUDCon:2011 Boston(20)

CI/CD on AWS Deploy Everything All the TimeCI/CD on AWS Deploy Everything All the Time
CI/CD on AWS Deploy Everything All the Time
Amazon Web Services2.3K views
App fabric introductionApp fabric introduction
App fabric introduction
Dennis van der Stelt2.1K views
Getting Started with Serverless ArchitecturesGetting Started with Serverless Architectures
Getting Started with Serverless Architectures
Amazon Web Services4.3K views
Azure Functions Real World Examples Azure Functions Real World Examples
Azure Functions Real World Examples
Yochay Kiriaty9.4K views
Serverless Meetup - Event SourcingServerless Meetup - Event Sourcing
Serverless Meetup - Event Sourcing
Luca Bianchi507 views
ITB2017 - KeynoteITB2017 - Keynote
ITB2017 - Keynote
Ortus Solutions, Corp995 views
Kubernetes @ meeticKubernetes @ meetic
Kubernetes @ meetic
Sébastien Le Gall652 views

Recently uploaded(20)

Green Leaf Consulting: Capabilities DeckGreen Leaf Consulting: Capabilities Deck
Green Leaf Consulting: Capabilities Deck
GreenLeafConsulting147 views
Java Platform Approach 1.0 - Picnic MeetupJava Platform Approach 1.0 - Picnic Meetup
Java Platform Approach 1.0 - Picnic Meetup
Rick Ossendrijver20 views

Scaling Rails With Torquebox Presented at JUDCon:2011 Boston

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. myths &amp;#x201C;Ruby doesn&amp;#x2019;t scale, Rails doesn&amp;#x2019;t scale&amp;#x201D;\n
  7. scaling out vs scaling up\n
  8. \n
  9. \n
  10. simple Rails controller w/ an accompanying view (not shown) to render the HTML\n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. normal load balancers just forward requests to the backend server\nwith mod_cluster, TorqueBox and JBoss AS can send load and other information to the load balancer\n
  31. \n
  32. When using multicast discovery - there are some other tricks for networks that don&amp;#x2019;t support multicast\n
  33. \n
  34. \n
  35. Java and Rails applications can share session data\nAS session replication is battle-proven, very configurable\n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. If backgroundable is too magic for you, we also support explicit asynchronous tasks\n
  44. \n
  45. \n
  46. \n
  47. \n
  48. Just like HASingleton services\n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n