Monday Apr 30, 2007

Ruby on Rails meets GlassFish High Availability

One of the key features of GlassFish v2 release is its cluster support. Various GlassFish server instances can be grouped together to form a single virtual entity - a cluster. One of the salient services offered via clustering is high availability, which is implemented as in-memory replication of state across participating server instances.

Since, I've been looking at getting Ruby on Rails applications running as web applications in a Java EE container, I was asked a couple of weeks ago if RoR applications could run in a GlassFish cluster. Well, with Rails-Integration 1.1.1, you can ! Its relatively straightforward to enable failover support for a web application in GlassFish and is no different for RoR (as a web application). The hard part, or so it seems at first, is setting up the GlassFish cluster.

For the easy part first, the only changes needed to enable failover session support for a web application are :

  • The deployment descriptor, web.xml, needs a marking distributable element - <distributable/>
  • Enable the high availability flag during deployment. For command line, this would be of the form
    ${GLASSFISH_HOME}/bin/asadmin deploy --target ${CLUSTER_NAME} --availabilityenabled=true ${path-to-war-file}

One important fact that I learned during this process, was that a load balancer facade is not necessarily needed for development/testing scenario. In other words if server instances, that share application state, are listening on the same host (different port), then failover can be simulated by simply sending requests to the other node (port).
Now, the part about setting up a GlassFish cluster. The references below give detailed information about the clustering architecture and setup steps but the takeaway is a lot simpler.

  • Download GlassFish v2 from https://glassfish.dev.java.net/public/downloadsindex.html
  • java -Xmx256m -jar ${GLASSFISH-v2.jar downloaded above}
  • cd glassfish; ant -f setup-cluster.xml

  • {GLASSFISH_HOME}/bin/asadmin start-domain ${domain-name} // ${domain-name} typically is 'domain1'

  • cd ${GLASSFISH_HOME}/samples/quickstart/clusterjsp/
  • ${GLASSFISH_HOME}/bin/asant setup-one-machine-cluster
  • ${GLASSFISH_HOME}/bin/asant start_cluster // stop_cluster to stop
  • (The last 2 steps will create a cluster named 'cluster1' with two instances, instance-ONE and instance-TWO listening for HTTP requests on port 1110 and 1111 respectively. Of course, you could do the same(creating/starting/stopping) via the asadmin command options like '(create|start|stop)-(cluster|instance|node-agent)', but it's a lot easier to get started via the clusterjsp sample)
That's all there is to it !

References
http://wiki.glassfish.java.net/gfwiki/Wiki.jsp?page=GlassFishV2Architecture
http://developers.sun.com/appserver/reference/techart/load-balancing.html
https://glassfish.dev.java.net/javaee5/build/GlassFish_LB_Cluster.html
http://wiki.glassfish.java.net/gfwiki/attach/OnePagersOrFunctionalSpecs/memory-replication-one-pager.html

Tuesday Apr 24, 2007

Rails-Integration 1.1.1

rails-integration 1.1.1 has just been released !
Source and binaries can be downloaded from http://rubyforge.org/frs/?group_id=2014
rails-integration details can be found at http://www.headius.com/jrubywiki/index.php/Rails_Integration

The fundamental change in this release as compared to 1.0, is performance and compatibility. When used in standalone mode, rails-integration 1.0 had this hack wherein it performed installation of JRuby and the rails libraries at runtime (during web application initialization i.e., once per web container process lifetime). Not only was this ugly, but it also caused compatibility problems with GlassFish since it expected the web application constituents after deployment (implementation dependent)in a particular format. No runtime installation needed with 1.1.1 !
Aiding to the performance improvements is JRuby 0.9.9 which has made great strides in improving performance as compared to its previous versions.
Also, this release is compatible with rails 1.2.x, solves session related and other issues that plagued 1.0.

All in all, a great release that blends the two architectures - RoR and Java EE - giving you the best of both worlds - the development convenience of RoR and the enterprise level features of the Java EE platform. No longer do you have to pick and choose one !

Many thanks to all the folks involved in getting the release out !

Wednesday Jan 24, 2007

Grizzlicious ... Part II

Part I described how to get a RoR application working on GlassFish. However, if you want something lightweight for development only or do not want anything to do with configuration changes(which btw, will only get simpler) or any other reason, read on ...

The elegant design of Grizzly allows you to write just a few lines of code and have a custom HTTP server suited to your specific requirements. The rails module does just that for primarily running a RoR application. This is how:

  1. Download rails-module-0.1-SNAPSHOT.jar
  2. The latest Grizzly binaries
  3. And of course, the JRuby binaries, Rails framework libraries and database specific JDBC drivers. For JRuby, I recommend working with the current trunk version as there are issues with the 0.9.2 release and the rails-module. Copy plaincharset.jar(in ${JRUBY_HOME}/lib) to jre/lib/ext of your Java runtime. For installing the Rails framework including activerecord-jdbc see steps #3 and #4. Use the flags(--no-rdoc --no-ri) for faster gem installation.

    Steps 1,2 and 3 are one time only.

  4. Create the Rails applications. Perform the following edits
    • Database related configuration edits - db config and step #8 here
    • In config/development.rb set config.breakpoint_server to false. See JRuby issue for more details.
  5. That's it ! Run it as something like
    # set the CLASSPATH variable to include
    # rails-module, grizzly, JDBC driver, 
    # JRuby libs(jruby.jar, jvyaml, asm, jline and jruby-openssl)
    java -classpath ${CLASSPATH} -Djruby.base=${JRUBY_HOME}
        com.sun.grizzly.rails.standalone.Main ${RAILS_ROOT}
    
    Or download the script and modify it to run in your environment.

Friday Jan 19, 2007

Grizzlicious ... RoR on GlassFish

In some of the previous episodes, I described how to go about deploying a Ruby on Rails(RoR) application on GlassFish. The first post described the method of deployment in which the RoR application is packaged as a WAR file, whereas the later posts(here and here) utilized the native Ruby interpreter at runtime(RoR-as-WAR runs on JRuby).

However, both deployment models are not quite ideal for a production deployment scenario. Enter Grizzly ! The NIO based HTTP connector for GlassFish. The beauty of Grizzly is not only that it's fast and scalable but that it is also highly extensible. TAKAI Naoto was quick to realize this fact and quickly dished out the first version of the adapter code needed to deploy RoR applications directly on top of Grizzly.

Without further ado, the steps to get a RoR application working as a first-class citizen within GlassFish:

  1. Download and install GlassFish in ${GLASSFISH_HOME}
  2. Download rails-module-0.1-SNAPSHOT.jar to ${GLASSFISH_HOME}/lib
  3. Checkout the latest source of JRuby and build it.
    Copy jruby.jar jvyaml.jar and asm-2.2.2.jar and to ${GLASSFISH_HOME}/lib
  4. Copy plaincharset.jar(in ${JRUBY_HOME}/lib) to jre/lib/ext of your Java runtime installation.
  5. Install the rails libraries including activerecord-jdbc. See step #3, #4 .
  6. The rails applications should installed under ${GLASSFISH_HOME}/domains/${domain-name}/applications/rails and you still need to do edits to get jdbc adapter working with JRuby. See steps #7 and #8 from the previous post
  7. Modify GlassFish configuration (which persists in ${GLASSFISH_HOME}/domains/${domain-name}/config/domain.xml - you could use the great administration UI - typically available at port 4848 via the browser or the command line interface to perform the changes) as below.
    • Add RoR specific http listener
          <http-listener acceptor-threads="1" address="0.0.0.0" 
                blocking-enabled="false" default-virtual-server="server" enabled="true" 
                family="inet" id="http-listener-rails" port="8081"
                security-enabled="false" server-name="" xpowered-by="true">
      
              <property name="selectorThreadImpl" value="com.sun.grizzly.rails.RailsSelectorThread"/>
          </http-listener>
      
    • To the java-config add the system property 'jruby.base'
          <jvm-options>-Djruby.base=jruby-home-value-here</jvm-options>
      
  8. Modify $GLASSFISH_HOME}/domains/${domain-name}/applications/rails/config/environments/development.rb by setting the property config.breakpoint_server to false. Once issue #427 in JRuby is fixed this step will not be needed.
Give it a shot !

Monday Jan 08, 2007

Derby's Identity column trivia

In a previous post, I described the SQL command to create a table with an auto increment column in the Derby database. It turns out that the 'GENERATED' keyword can be used in a couple of way.
  • GENERATED ALWAYS AS IDENTITY
  • GENERATED BY DEFAULT AS IDENTITY
For details see the relevant section of the Derby manual here. Essentially the distinguishing fact being - by using 'BY DEFAULT' the user has the ability to specify a value for the identity column as part of a (insert) SQL statement, whereas with 'ALWAYS', the column can never be explicitly edited by the user. Also 'ALWAYS' guarantees uniqueness, but 'BY DEFAULT' does not (use the UNIQUE/PRIMARY KEY attribute to achieve the same effect though)

So, the better suited SQL statement for creating a table in Derby in a RoR application would be

CREATE TABLE ${table-name} ( 
    ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
    ${other-columns-and-constraints} )
Running a simple RoR application with the underlying identifier created via either option works without any issues. However, if you want to run the tests that comes in built with Rails framework the difference is detrimental (since the test framework seems to explicitly want to insert a value for the identifier column).
About

whacko

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today