Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Scaling Rails With Torquebox Presented at JUDCon:2011 Boston


Published on

Published in: Technology
  • Must read for Ruby users who can understand it...
    Are you sure you want to  Yes  No
    Your message goes here

Scaling Rails With Torquebox Presented at JUDCon:2011 Boston

  1. 1. Scaling Rails Applications with TorqueBox Ben Browning
  2. 2. Ben Browning•TorqueBox Contributor•Red Hat Senior Engineer since July 2010•Ruby yay! JVM yay! Java boo! JRuby yay!
  3. 3. The Team
  4. 4. 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
  5. 5. Rails“Ruby on Rails® is an open-source web frameworkthat’s optimized for programmer happiness andsustainable productivity. It lets you write beautiful codeby favoring convention over configuration.” -
  6. 6. ScalingAbility to increase throughput by adding hardware
  7. 7. Learn By (Beer) ExampleLet’s create an application to find the most popular beeraccording to Twitter.
  8. 8. Beer Tweets•Web front-end•Twitter Streaming API client•Scheduled job to clean old beer tweets•Caching so our database doesn’t fall over
  9. 9. Web Front-endclass BeersController < ApplicationController def most_popular @popular_beers = Beer.most_popular(:limit => 25) endend
  10. 10. 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
  11. 11. 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
  12. 12. Twitter Streaming API Clientclass BeerService def initialize(options) @client =["username"], options["password"]) end def start { find_beer } end def stop @client.disconnect endend
  13. 13. Twitter Streaming API Clientclass BeerService def find_beer do |tweet| Beer.create_from_json(tweet) end endend
  14. 14. Twitter Streaming API Clientconfig/torquebox.yml:services: beer_service: username: ilikebeer password: sodoyou
  15. 15. Clean Stale Beer•Delete all beer-related tweets older than 7 days•Run once an hour to prune in manageable chunks
  16. 16. Scheduled Jobs•Tasks that need to be executed on a recurring schedule•A class with a run() method
  17. 17. Clean Stale Beerclass BeerCleaner def run() Beer.clean_older_than(7.days) endend
  18. 18. Clean Stale Beerconfig/torquebox.yml:jobs: beer_cleaner: description: Clean stale beer-related tweets job: BeerCleaner cron: 0 44 * * * ?
  19. 19. CachingWe’re showing the same list of most popular beers to allusers so why hit the database on every request?
  20. 20. Caching Web Front-endclass BeersController < ApplicationController caches_action :most_popular, :expires_in => 30.seconds def most_popular @popular_beers = Beer.most_popular(:limit => 25) endend
  21. 21. Beer TweetsWe’re collecting tweets about beer, serving the resultsup via a cached web interface, and keeping ourdatabase cleaned of stale data.
  22. 22. We’re Done, Right?We’ve added all our features and deployed onTorqueBox so we can handle limitless load, right?
  23. 23. Benchmarks
  24. 24. Benchmarks
  25. 25. We’re Done, Right?No way - it’s beer and Twitter! This will be wildlypopular with social alcoholics and we need to planaccordingly - we need to scale!
  26. 26. Performance != ScalabilityJust because an application performs well on a singleserver doesn’t mean it can scale.
  27. 27. Add More ServersWell, before we can do that we need a load balancer toroute requests to multiple servers.
  28. 28. mod_clusterThe same mod_cluster you know and love to use withJBoss AS works with TorqueBox.
  29. 29. mod_clusterBased on Apache’s mod_proxy but with two-waycommunication to JBoss and TorqueBox providingintelligent request routing based on load.
  30. 30. mod_cluster
  31. 31. Add More ServersAs each TorqueBox instance boots it will find the otherTorqueBox and mod_cluster instances and add itself tothe cluster.
  32. 32. 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
  33. 33. TorqueBox Sessionsconfig/initializers/session_store.rb:BeerTweets::Application.config. session_store TorqueBox::Session::ServletStore
  34. 34. TorqueBox Sessions•Server-side sessions without hitting the database or requiring an external process (memcached)•Uses JBoss AS session replication under the hood
  35. 35. Are We Scaled Yet?We’ve taken care of the load balancer and sessionreplication, but what about our Twitter Streaming APIclient? How will it scale?
  36. 36. 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.
  37. 37. 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
  38. 38. HASingleton Servicesconfig/torquebox.yml:services: beer_service: username: ilikebeer password: sodoyou singleton: true
  39. 39. 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?
  40. 40. Backgroundable•Convert any method call into an asynchronous call•Uses HornetQ under the hood and calls are load- balanced across the cluster
  41. 41. Backgroundableclass BeerService def find_beer do |tweet| Beer.background.create_from_json(tweet) end endend
  42. 42. Asynchronous Tasksclass BeerTask < TorqueBox::Messaging::Task def create_from_json(payload) Beer.create_from_json(payload[:tweet]) endend
  43. 43. Asynchronous Tasksclass BeerService def find_beer do |tweet| BeerTask.async(:create_from_json, :tweet => tweet) end endend
  44. 44. Twitter Streaming API ClientAll nodes in our cluster will now process incomingtweets even though only a single node maintains a httpconnection to Twitter.
  45. 45. Now We’re Scaled, Right?Not quite - we still have that pesky job that cleans stalebeer to deal with.
  46. 46. 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.
  47. 47. HASingleton Jobsconfig/torquebox.yml:jobs: beer_cleaner: description: Clean stale beer-related tweets job: BeerCleaner cron: 0 44 * * * ? singleton: true
  48. 48. All Scaled?Almost! We still need to take care of our caching.
  49. 49. 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
  50. 50. TorqueBoxStore•Rails 3 ActiveSupport::Cache::Store implementation backed by Infinispan•Supports invalidated, replicated, and distributed clustering modes
  51. 51. TorqueBoxStoremodule BeerTweets class Application < Rails::Application config.cache_store :torque_box_store(:mode => :distributed, :sync => false) endend
  52. 52. Are We Scaled?As we add additional nodes to the cluster they increaseour web request throughput, background jobthroughput, and cache capacity. We’re scaled!
  53. 53. But Wait, There’s More!
  54. 54. InjectionInject CDI resources, messaging destinations, JNDIentries, MBeans into your Ruby application@questions = inject(‘/queues/questions’)@datasource = inject(‘java:comp/env/jdbc/myDS’)@thing = inject(com.mycorp.Something)@bean = inject(‘SomeMCBean’)
  55. 55. Message Processorsclass SeniorHandler < TorqueBox::Messaging::MessageProcessor def on_message(body) puts “Processing #{body} of #{message}” endend
  56. 56. Message Processorsconfig/torquebox.yml:messaging: /queues/people: SeniorHandler: filter: “age >= 55” concurrency: 2
  57. 57. Queues and Topicsquestions = inject(‘/queues/questions’)answers = inject(‘/queues/answers’) do questions.publish ‘What time is it?’ puts answers.receive(:timeout => 1000)endputs questions.receiveanswers.publish
  58. 58. Queues and Topicsconfig/torquebox.yml:queues: /queues/questions: /queues/answers:
  59. 59. BackStageDashboard and RESTful API to inspect and control Rubycomponents
  60. 60. BackStage
  61. 61. StompBoxEasy Heroku-esque git-based deployments
  62. 62. StompBox
  63. 63. Roadmap1.0.0 Just Released!Upcoming:AS7TransactionsSSODrools / jBPMMobicentsWebSockets
  64. 64. Resources•••#torquebox on FreeNode•@torquebox
  65. 65. Thanks!
  66. 66. Questions?