complex made simple: sleep better with torquebox

Post on 08-May-2015

5.339 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Complex Made SimpleSleep Better With TorqueBox

Lance BallSenior Software EngineerRed Hat

Creative Commons BY-SA 3.0

Friday, April 27, 12

Complex Made SimpleSleep Better With TorqueBox

Lance BallSenior Software EngineerRed Hat

Creative Commons BY-SA 3.0

Friday, April 27, 12

Who am I?

๏ Senior Software Engineer @ Red Hat๏ TorqueBox core developer๏ Part of the project:odd team๏ Open source contributor

Lance Ball

Friday, April 27, 12

Scenario

You've got a Ruby application to deploy, for production.

Friday, April 27, 12

Ruby AppRails

Rack

Sinatra

Apache/Nginx

Passenger/Thin

Friday, April 27, 12

But...

The app you deploy today will grow in the future, if you’re successful.

Friday, April 27, 12

Eventual Complexity

Friday, April 27, 12

Ruby AppRails

Rack

Sinatra

Apache/Nginx

Passenger/ThinResque/

DelayedJob

Tasks

Friday, April 27, 12

Ruby AppRails

Rack

Sinatra

Apache/Nginx

Passenger/Thin

crond

JobsResque/

DelayedJob

Tasks

Friday, April 27, 12

Ruby AppRails

Rack

Sinatra

Apache/Nginx

Passenger/Thin

crond

JobsResque/

DelayedJob

Tasks

god/monit

Daemons

Friday, April 27, 12

Deploy Continuum

Friday, April 27, 12

Deploy Continuum

Friday, April 27, 12

Deploy Continuum

Friday, April 27, 12

What is TorqueBox?

TorqueBox is a Ruby Application Server.

Based on JRuby and JBoss AS7.

Friday, April 27, 12

Rails

Rack

Sinatra

ProcsTasks DaemonsJobs

HAClustering Load Balancing

JBoss ASWeb Messaging Scheduling Services

TorqueBox AS

Friday, April 27, 12

Roll your own

๏ Install OS๏ Install packages๏ Configure everything๏ Manage everything

Friday, April 27, 12

Roll your own๏ Apache httpd๏ Load balancer๏ Unicorn, pack of Mongrels๏ crontab๏ SMTP๏ memcached๏ Database๏ deployment๏ monitoring

Friday, April 27, 12

Or outsource some...

Friday, April 27, 12

Roll your own >>๏ Apache httpd๏ Load balancer๏ Unicorn, pack of Mongrels๏ crontab๏ SMTP Amazon SES, SendGrid๏ memcached๏ Database๏ deployment Capistrano๏ monitoring New Relic

Friday, April 27, 12

Use a Paas

Outsource everything but your app.

Friday, April 27, 12

Heroku๏ Apache httpd Heroku๏ Load balancer Heroku๏ Unicorn, pack of Mongrels Heroku๏ crontab Heroku๏ SMTP SendGrid๏ memcached Heroku๏ Database Heroku๏ deployment Heroku๏ monitoring New Relic

Friday, April 27, 12

TorqueBox๏ Apache httpd๏ Load balancer JBoss mod_cluster๏ Unicorn, pack of Mongrels TorqueBox๏ crontab TorqueBox๏ SMTP Amazon SES, SendGrid๏ memcached TorqueBox๏ Database๏ deployment Capistrano๏ monitoring NewRelic

Friday, April 27, 12

Case Study!

Friday, April 27, 12

Appalachian Sustainable Agriculture Project (ASAP)

Friday, April 27, 12

Application Needs๏ Rails 2.x web app๏ Caching๏ Background tasks๏ Cron jobs๏ Deployment from SCM๏ Sending email๏ Database queries๏ Monitoring & metrics

Friday, April 27, 12

As deployed on Heroku

Friday, April 27, 12

Migration Motivation

In this particular case, client feels it could save money, and have a better system by moving to an affordable VPS, letting TorqueBox absorb some of the roll-your-own complexity.

Friday, April 27, 12

Install

$ rvm install jruby-1.6.7$ rvm use jruby-1.6.7$ gem install torquebox-server

Friday, April 27, 12

Templatize

$ torquebox rails myapp

Friday, April 27, 12

torquebox.rb template

๏ torquebox-* and activerecord-jdbc-adapter gems

๏ torquebox-rake-support๏ Directories for services, jobs, etc๏ Web session store๏ Rails.cache with TorqueBox๏ Background jobs

Friday, April 27, 12

“Porting” the application

Friday, April 27, 12

Background Jobs

Friday, April 27, 12

Delayed::Job

App uses Delayed::Job

Replace with TorqueBox Backgroundable

Friday, April 27, 12

controller.rb

Delayed Job

def create  @export = ExcelExport.create(...)  job = ExcelExportJob.new   job.excel_export_id = @export.id  Delayed::Job.enqueue job  @export.set_status "Queued for Export"  @export.save!end

Friday, April 27, 12

controller.rb

Delayed Job

def create  @export = ExcelExport.create(...)  job = ExcelExportJob.new   job.excel_export_id = @export.id  Delayed::Job.enqueue job  @export.set_status "Queued for Export"  @export.save!end

job = ExcelExportJob.new job.excel_export_id = @export.id Delayed::Job.enqueue job

Friday, April 27, 12

excel_export_job.rb

class ExcelExportJob < Struct.new(:excel_export_id)  def perform    ExcelExport.find(self.excel_export_id).generate_report  endend

Delayed Job

Friday, April 27, 12

excel_export.rb

Delayed Job

class ExcelExport < ActiveRecord::Base  def generate_report    begin      set_status 'Processing'      spreadsheet = Spreadsheet.new(self.businesses)       spreadsheet.write_workbook self.workbook_file      set_status 'Storing on S3'      File.open(self.workbook_file) {|out|self.output = out}          File.delete(self.workbook_file)          set_status 'Complete'    rescue      set_status 'Export Error'    end  endend

Friday, April 27, 12

Delayed Job

Mayhap you need to run a worker, also...

Friday, April 27, 12

Delayed::Job

Exporter < AR::Base

ExportJob < Struct

Database

Worker

Friday, April 27, 12

That's pretty explicit

TorqueBox allows you to very easily run methods asynchronously.

Friday, April 27, 12

excel_export.rb

Backgroundable

class ExcelExport < ActiveRecord::Base  always_background :generate_report

  def generate_report    begin      set_status 'Processing' ...    rescue      set_status 'Export Error'    end  end

end  

Friday, April 27, 12

excel_export.rb

Backgroundable

class ExcelExport < ActiveRecord::Base  always_background :generate_report

  def generate_report    begin      set_status 'Processing' ...    rescue      set_status 'Export Error'    end  end

end  

  always_background :generate_report

Friday, April 27, 12

export_controller.rb

Backgroundable

def create  @export = ExcelExport.create(...)  @export.set_status "Queued for Export"  @export.save @export.generate_reportend

Friday, April 27, 12

export_controller.rb

Backgroundable

def create  @export = ExcelExport.create(...)  @export.set_status "Queued for Export"  @export.save @export.generate_reportend

@export.generate_report

Friday, April 27, 12

$ git rm excel_export_job.rb

excel_export_job.rb

Backgroundable

Kill it!

Friday, April 27, 12

Backgroundable

Exporter < AR::Base

ExportJob < Struct

Database

Worker

Queue Processor

Implicit!magic!

Friday, April 27, 12

Caching

Friday, April 27, 12

Caching

๏ template.rb does the work๏Web sessions๏Fragment and other caching

Friday, April 27, 12

No more memcached!

Friday, April 27, 12

cache = TorqueBox::Infinispan::Cache.newcache.put(“something”, anything)cache.get(“something”)

Cache

Friday, April 27, 12

cron0 0 2 * * ?/WTF??

Friday, April 27, 12

Heroku Cron

๏Free version runs 1x daily๏ Implemented as a rake task๏ Includes app environment

Friday, April 27, 12

Rakefile

Heroku Cron

desc "This task is called by the heroku cron add-on"task :cron => [:environment, :heroku_backup, :refresh_trip_planner]

desc "Refresh the trip planner business data cache"task :refresh_trip_planner => :environment do  #  # update GIS cache #end

Friday, April 27, 12

Scheduled Jobs

In TorqueBox, a scheduled job is a component of your application.

Friday, April 27, 12

refresh_trip_planner.rb

Straight-forward

class RefreshTripPlanner  def run() #    # update the GIS cache #  endend

Friday, April 27, 12

torquebox.yml

Configuration

jobs:  cache.updater:    job: RefreshTripPlanner    cron: '0 0 2 * * ?'    description: Refresh trip cache

Friday, April 27, 12

But...

Doing a huge query once-a-day isn't ideal, it was just "free".

Friday, April 27, 12

Services

Friday, April 27, 12

TorqueBox Services

๏Avoid the huge query๏Keep data more fresher

Friday, April 27, 12

trip_planner_service.rb

Keep it fresher class TripPlannerService  def initialize( options={} )    @queue = TorqueBox::Messaging::Queue.new('/queues/trip_planner')  end    def start    Thread.new do      initialize_cache      while should_run        update_cache(@queue.receive)      end    end  end

  def update_cache( business_id )    TripPlanner.insert_or_update business_id  end # initialize_cache(), stop(), etcend

Friday, April 27, 12

trip_planner_service.rb

Keep it fresher TripPlannerService  def initialize( options={} )    @queue = TorqueBox::Messaging::Queue.new( '/queues/trip_planner' )  end    def start    Thread.new do      initialize_cache      while should_run        update_cache @queue.receive      end    end  end

  def update_cache( business_id )    TripPlanner.insert_or_update business_id  end # initialize_cache(), stop(), etcend

def initialize( options={} )  @queue = TorqueBox::Messaging::Queue.new( ... )end

Friday, April 27, 12

trip_planner_service.rb

Keep it fresher TripPlannerService  def initialize( options={} )    @queue = TorqueBox::Messaging::Queue.new( '/queues/trip_planner' )  end    def start    Thread.new do      initialize_cache      while should_run        update_cache @queue.receive      end    end  end

  def update_cache( business_id )    TripPlanner.insert_or_update business_id  end # initialize_cache(), stop(), etcend

def start  Thread.new do    initialize_cache    while should_run      update_cache(@queue.receive)    end  endend

Friday, April 27, 12

require 'torquebox-messaging'

class Business < ActiveRecord::Base

  after_save :update_trip_planner

  def update_trip_planner    queue = TorqueBox::Messaging::Queue.new('/queues/trip_planner')    queue.publish( self.id )  end

end

app/models/business.rb

Keep it fresher

Friday, April 27, 12

require 'torquebox-messaging'

class Business < ActiveRecord::Base

  after_save :update_trip_planner

  def update_trip_planner    queue = TorqueBox::Messaging::Queue.new('/queues/trip_planner')    queue.publish( self.id )  end

end

app/models/business.rb

Keep it fresher

queue = TorqueBox::Messaging::Queue.new(...)queue.publish( self.id )

Friday, April 27, 12

Queue, Service, Cache

Non-blocking

Service

Cache

ActiveRecord

Business

Queue

Friday, April 27, 12

Production!

Friday, April 27, 12

(Remember, I work for Red Hat)

Friday, April 27, 12

Set up the server

$ yum install \ java-1.6.0-openjdk \ httpd \ mod_cluster \ git \ postgresql-server

Friday, April 27, 12

Launch on boot

Friday, April 27, 12

init.d

Install /etc/init.d/jboss-asfrom the stock distribution

Friday, April 27, 12

/etc/jboss-as/jboss-as.conf

JBoss configuration

# General configuration for the init.d script# Place this file in /etc/jboss-as/jboss-as.conf# and copy $JBOSS_HOME/bin/init.d/jboss-as-standalone.sh # to /etc/init.d/jboss-as-standalone

JBOSS_USER=torqueboxJBOSS_HOME=/opt/torquebox/current/jbossJBOSS_PIDFILE=/var/run/torquebox/torquebox.pidJBOSS_CONSOLE_LOG=/var/log/torquebox/console.logJBOSS_CONFIG=standalone-ha.xml

Friday, April 27, 12

Load Balance with mod_cluster

Friday, April 27, 12

httpd.conf

mod_cluster

LoadModule slotmem_module modules/mod_slotmem.soLoadModule proxy_cluster_module modules/mod_proxy_cluster.soLoadModule advertise_module modules/mod_advertise.soLoadModule manager_module modules/mod_manager.so

<Location /mod_cluster_manager>    SetHandler mod_cluster-manager    AllowDisplay On</Location>

Listen torquebox-balancer:6666

Friday, April 27, 12

httpd.conf (continued)

mod_cluster<VirtualHost torquebox-balancer:6666>   <Directory />    Order deny,allow    Deny from all    Allow from all  </Directory>   KeepAliveTimeout 60  MaxKeepAliveRequests 0

  EnableMCPMReceive   ManagerBalancerName torquebox-balancer  AllowDisplay On  AdvertiseFrequency 5  AdvertiseSecurityKey secret </VirtualHost>

Friday, April 27, 12

Deploy with Capistrano

Friday, April 27, 12

Capistrano

Regular capistrano deployments are supported given the recipes provided by torquebox-capistrano-support.gem

Friday, April 27, 12

Deployed

[root@torquebox opt]# ls -l apps/buyappalachian.org/total 8lrwxrwxrwx 1 23 Mar 16 15:10 current -> releases/20120315230553drwxrwxr-x 5 4096 Mar 15 19:05 releasesdrwxrwxr-x 6 4096 Mar 15 17:29 shared

Friday, April 27, 12

And then it grows...

As your app evolves, you might add stuff like WebSockets/STOMP, or HA or other facilities already in the tin.

Friday, April 27, 12

Can we go further?

Friday, April 27, 12

What's a PaaS?

Application

Queues

DB Email

Cache Jobs

Friday, April 27, 12

OPENSHIFT

http://openshift.redhat.comhttps://github.com/torquebox/torquebox-openshift-express

Friday, April 27, 12

Roadmap & Status

๏Current 2.0.1๏Continued Red Hat investment๏ Interop with other languages, such as Clojure via Immutant

Friday, April 27, 12

Resources

http://torquebox.org/

@torquebox on Twitter

#torquebox on IRC

Friday, April 27, 12

Question everything.

Friday, April 27, 12

Creative Commons BY-SA 3.0

Friday, April 27, 12

top related