Upload
bobmcwhirter
View
2.225
Download
0
Embed Size (px)
DESCRIPTION
Presentation about TorqueBox to the DC:JBUG in November, 2011.
Citation preview
TorqueBoxThe expressiveness of Ruby
The power of Java
Bob McWhirterJBoss Fellow
Bob McWhirter‣ JBoss Fellow at Red Hat
‣ Founder of...
‣ The Codehaus
‣ Drools
‣ TorqueBox
‣ DeltaCloud API
but it’s a team
What is TorqueBox?
TorqueBox glues JRuby to the JBoss Java Application Server (JBoss AS).
‣ Real threads
‣Many garbage-collection options
‣ Lots of JVM research
‣ Integration with Java
‣ Fast!
Why JRuby
What is JBoss AS?
JBoss AS is full JavaEE application server, providing web, caching, messaging, clustering, failover, etc.
TorqueBoxCore
TorqueBoxCore
Java Virtual Machine
Managed Services ContainerJRuby with JIT
Security
Transactions
JBoss Web
Infinispan
HornetQ
Quartz
PicketLink
Rack
Sinatra Rails
Daemons
WebSocketsSTOMP
Tasks
Jobs
MessageProcessors
POJO
Spring
REST
JMS
Servlet
JavaEE
Messaging
Cache
Ruby!APIs!/!Programming!Models Java!APIs!/!Programming!Models
Polyglot Injection
Java!Enterprise!ServicesJRuby!Component!Deployers!&!Gems
But Java is enterprisey, while Ruby is agile...!
“Java is a DSL for taking large XML files and converting them to stack traces”
Scott Bellware
XML means we’ve
<failed/>
One of our mantras:
Be a great traditional Ruby environment
‣Rack
‣Rails
‣Sinatra
‣Padrino
First Order Goals
‣ Services‣ Jobs‣ Messaging‣ Transactions
‣ Caching‣ WebSockets‣ HA/Failover
Second Order Goals
Be better than a traditional environment:
First: web
myapp/ config.ru config/ application.rb database.yml torquebox.yml app/ views/ controllers/ models/
Your app
config/torquebox.yml
application: root: /path/to/myapp
web: context: / host: www.myapp.com
environment: RAILS_ENV: production MAIL_HOST: mail.myapp.com
1 AS, many apps
WEB-INF/web.xml<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param> <param-name>mail.host</param-name> <param-value>mail.myapp.com</param-value> </context-param>
<servlet> <display-name>Servlet1</display-name> <servlet-name>Servlet1</servlet-name> <servlet-class>test.Servlet1</servlet-class> </servlet>
<servlet-mapping> <servlet-name>Servlet1</servlet-name> <url-pattern>/Servlet1</url-pattern> </servlet-mapping>
<welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list>
</web-app>
Compare to...
Make Love, not WAR
Live, where it sits on disk.
No archive required.
(caveat)
Requires runtime reloading support in your framework, but not redeployment.
Rails Rack::Reloader
Works as expected,almost
boring
http://www.flickr.com/photos/djbadly/2052098189/
servicesSecond order goal:
start()
...time passes...
stop()
Daemons!
app/services/my_service.rbclass MyServer
def initialize(opts) end
def start end
def stop end
end
Example service
config/torquebox.ymlService config
services:
MyService: some_key: some_value
MyCriticalService: singleton: true
singleton?
true
Ensures one (and only one) instance is running within the cluster at a time, with failover.
singleton?
false(default)
scheduled jobsSecond order goal:
-every 3 hours...- the first of each month...-on Tuesdays...-when the world ends...
cron-like
http://www.flickr.com/photos/spine/2408967576/
apps/jobs/my_job.rbJob example
class MyJob def run()
# your code here
end
end
config/torquebox.ymlJob config
jobs: monthly_reminder: description: sends reminders job: MyJob cron: ‘0 0 0 1 * ?’ singleton: true
file_cleaner: description: clean files on node job: FileCleaner cron: ‘5 * * * * ?’
messagingmessaging
messaging
Second order goal:
(we really like messaging)
Darn zippy JMS broker
config/torquebox.yml
queues: /queues/puppies: /queues/kittens: durable: false
topics: /topics/memes:
Where to, my friend?
Topic Queue
Consumer Consumer Consumer Consumer
arbitrary_app_stuff.rbLet’s go!
class MyController < ApplicationController
include TorqueBox::Injectors
def index @queue = inject( ‘/queues/puppies’ ) @queue.publish( “Oh, puppies!” ) end
end
app/processors/my_processorNow arriving...
include TorqueBox::Messaging
class MyProcessor < MessageProcessor
def initialize(opts) end
def on_message(body) # your code here. end
end
config/torquebox.ymlProcessor config
messaging: /queues/puppies: MyHandler: concurrency: 5 config: some_key: some_value
/queues/kittens: MyOtherHandler: singleton: true
But that’s not all!
What makes messaging special?
Async
http://www.flickr.com/photos/photogaby/4129740673/
Backgroundables
Go asynchronous without having to think about messaging.
my_arbitrary_file.rbEnabling
class User
include TorqueBox::Messaging::Backgroundable
def do_something_slowly() upload_over_300baud_modem() end
end
What?
Teaches your class how to invoke methods across an implicit queue.
Yay mix-ins!
my_other_arbitrary_file.rbUsing explicitly
u = User.new
u.do_something_slowly()
u.background.do_something_slowly()
my_arbitrary_file.rbForcing
class User
include TorqueBox::Messaging::Backgroundable always_background :do_something_slowly
def do_something_slowly() upload_over_300baud_modem() end
end
my_other_arbitrary_file.rbUsing implicitly
u = User.new
u.do_something_slowly()
The FUTURE!future = user.do_something_slowly()
future.started?
future.complete?
future.error?
future.result
Progress!class User
include TorqueBox::Backgroundable always_background :do_something_slowly
def do_something_slowly upload_over_modem() future.status = “uploaded”
alert_authorities future.status = “alerted” endend
Query
future = user.do_something_slowly()
future.status_changed?
future.status # => “uploaded”
transactionsSecond order goal:
Queue Database Infinispan
TopicYour!Code
Transactions
Queue Database Infinispan
TopicYour!Code[ ]XA distributed, multi-resource transaction
Transactions
XA
‣ HornetQ supports XA
‣ Infinispan supports XA
‣ TorqueBox makes ActiveRecord support XA, if your database does.
Everything succeeds or everything fails
cachingSecond order goal:
and more
Infinispan
Node Node Node Node
Item #1 Item #1Item #2
Item #2Item #3
Item #3Item #4Item #4
Replicated & Distributed
Places Rails can use memcached?
Now you’re using Infinispan.
Replace memcached
As an object-store
Usable behind DataMapper through
dm-infinispan-adapter.
my_arbitrary_file.rbDirectly
my_cache = TorqueBoxStore.new( :name=>‘my-cache’, :mode=>:replicated )
my_cache.put(...)my_cache.get(...)
Clustered web sessions...
websocketsSecond order goal:
Stream-Oriented Message Protocol
to the browser
(I did say we really really liked messaging)
Bare WebSockets and clusters don’t get along.
http://www.flickr.com/photos/greencolander/4299692892/
WebSockets is already frame-based, not streaming...
Use messaging!
But directly exposing your JMS to the internet seems unwise...
http://www.flickr.com/photos/ell-r-brown/4686613540/
Stomplets act as a controller between user and JMS.
Browser Stomplet JMS!Stuff
app/stomplets/my_stomplet.rbclass MyStomplet
def on_subscribe(subscriber) end
def on_unsubscribe(subscriber) end
def on_message(stomp_message, session) end
end
Example Stomplet
config/torquebox.ymlConfiguration
stomp: stomplets: animals: route: ‘/animals/:type’ class: MyStomplet
JMS helpers
subscribe_to( subscriber, jms_dest )
send_to( jms_dest, message, headers= )
injectionSecond order goal:
‣ Inversion of control
‣ Allows for easier testing
‣ Inject non-Ruby things
Resource Injection
Injectables
‣ Services
‣ Queues & Topics
‣ Java CDI components
Destinations
inject( ‘/queues/kittens’ ).publish(...)
inject( ‘/topics/puppies’ ).publish(...)
MyJavaThing.javaCDI
package com.mycorp;;
@ApplicationScopedpublic class MyJavaThing
public void frob() ...
my_arbitrary_file.rbCDI
inject( com.mycorp.MyJavaThing ).frob()
Clustering
There is no cluster (noun),but things can cluster (verb).
‣Web sessions
‣Web load-balancing
‣ Caches
‣Messaging destinations
‣ HA coordination
Clusterstuff
Many discovery and communication options.‣ Multicast
‣ Rendezvous
‣ S3
‣ File
JGroups
(Caveat: except
HornetQ)
mod_cluster
httpd!+!mod_cluster
AS AS AS
performance
Throughput
TorqueBox
TrinidadPassengerUnicorn
0
40
80
120
40min
Higher is better
Latency
TorqueBox
TrinidadPassengerUnicorn
64ms
256ms
1s
4s
16s
65s
40min
Lower is better
CPU Usage
TorqueBox
TrinidadPassengerUnicorn
0
20
60
40min
Lower is better
40
80
Free Memory
TorqueBox
TrinidadPassengerUnicorn
0
1gb
40min
Higher is better
2gb
3gb
4gb
5gb
6gb
7gb
Management
Managing groups of servers is orthogonal to the clustering of servers.
Domain!Controller
Host!Controller Host!Controller
AS AS AS AS AS AS
API
API API
API API
Ecosystem
Backstage
Dashboard to monitor and control Ruby components.
With a RESTful API.
StompBox
Git-based application deployment straight to your server.
TorqueSpec
RSpec enhancements for integration testing.
Start TorqueBox & deploy apps are part of your specs.
In-container testing, too!
Cloudrific!
‣ Ruby
‣ Java
‣ PHP
‣ Python
‣ Perl
openshift.redhat.com
‣ Multi-tenant machines
‣ High density (let OS swap)
‣ Git-based deployment
‣ Constrained to achieve density
‣ SELinux to secure tenants
‣ http://torquebox.org/
‣ http://github.com/torquebox/torquebox
‣ #torquebox on Freenode
‣ @torquebox on Twitter
‣ The tall guy up front
Resources
http://www.flickr.com/photos/21496790@N06/5065834411/
Hey,
thanks for having me!
http://www.flickr.com/photos/stevendepolo/4582437563/