On Grails, Trails and Sails (via Kalle Korhonen)

June 4th, 2007

In this year’s JavaOne, there was a presentation on “Grails, Trails and Sails - Rails Through a Coffee Filter”. There’s been a few comments on it scattered in various blog posts (at least http://www.juixe.com/techknow/index.php/2007/05/29/grails-sails-and-trails-rails-through-a-coffee-filter/ and http://blog.shinetech.com/?p=18), so it seems fitting to have some reply to it here. As mentioned in the blogs, I had the honor of announcing that I had just weekend before JavaOne tagged Trails 1.0 release.

Overall, I thought Trails faired well against the competition, and while the presenter used several months old version of Trails, he made a decent job demonstrating it. Only Sails doesn’t seem like an active project, so mainly it was a comparison of Trails to Grails. The presenter mentioned that Grails is semantically closest to Rails and it’s picking up steam compared to others, and that he’s not sure if Trails is addressing enough pain-points. Certainly, even the whole Tapestry community is small compared to Struts or JSF, which already has an effect on the number of people interested in Trails or those who’ve even heard about it. But I’d have to disagree with the latter statement about pain-points. I’ve always thought that besides helping you to start quickly with your project (which all of these Rails-like projects do), the greatest strength of Trails is that it combines all of these state-of-the art frameworks into one and leverages their strenghts rather than introducing yet another way of doing things, such as the custom presentation layer in Grails. Tapestry has already solved some hard problems, like concurrency issues, caching the templates and re-using presentation objects, which allows us to focus on cases that none of the current web frameworks support: instance-based security, web flows, long conversations and modularizing the framework in order to have built-in support for different persistence layers etc. Currently, Trails uses Tapestry 4.0.2, but we are committed to moving to Tapestry 4.1.2 in Trails 1.1, and when new versions come out, we get the improvements to the presentation layer “for free”.

Whenever these comparisons happen, there’s always the question whether the separate projects could leverage each others or even merge. It’s said many a times that it probably wouldn’t have been possible to implement Trails-like framework without Tapestry, and so Trails is dependent on it. There’s no way nor need for Trails to change to something else, and therefore couldn’t merge with any other project. Similarly, Grails is married with Groovy - the project undoubtedly wouldn’t exist without it. Groovy is cool though, and you could technically write Trails/Tapestry code with it, but it wouldn’t help any when writing the Tapestry code templates - arguably the hardest but most powerful part of Tapestry. And that’s final advantage of Trails: it is a remarkably flat framework, there are no additional layers obscuring you from customizing the application with the techniques available in each framework. So, if you are versed with Tapestry, Spring and Hibernate, it’s almost a no-brainer to use Trails for a new web application.

Kalle Korhonen

Tags:

Book: Groovy Recipes (O’Reilly)

June 1st, 2007

Groovy Recipes Greasing the Wheels of Java

By Scott Davis, Venkat Subramaniam
First Edition July 2007 (est.)
Publisher: Pragmatic Bookshelf
Pages: 200 (More details)
Buy 2 Get 1 FreeFree ShippingGuarantee

Book description

Groovy Recipes is targeted at the busy Java professional who needs quick solutions to everyday problems. Each recipe shows a concise code example right away. If you need more information, each recipe is explained in plain English.

Nearly every aspect of the development process can be sped up using Groovy. Groovy makes mundane file management tasks like copying and renaming files trivial. Reading and writing XML has never been easier with XmlParsers and XmlBuilders. JDBC gets a fresh makeover. Breathe new life into Arrays, Maps, and Lists with a number of convenience methods. Even Ant gets turbo-charged. You can mix Groovy right into your build.xml, or replace it completely with code from an AntBuilder.

As an added bonus, this book also covers Grails. You’ll be amazed at how quickly you can have a first-class web application up and running from ground zero. Grails includes everything you need in a single zip file, a web server (Jetty), a database (HSQLDB), Spring, Hibernate, Sitemesh, even Ant. If you’re looking for Ajax support, Grails ships with leading libraries like Prototype, script.aculo.us, Yahoo UI, and Dojo. We cover everything from getting a basic application up and running to advanced features such as deploying to other webservers and databases, adding a Captcha, integrating with legacy EJB applications, and even adding a Google Map.

Groovy and Grails give you the power of the Java platform together with the flexibility and dynamism of a scripting language. Pick one of the many example projects in this book: at first you’ll scratch your head and ask, “where’s all the code?” Then you’ll smile as you realize that Groovy allows you to write code the way you always thought you should. You will never look at Java the same way again. Groovy Recipes is targeted at the busy Java professional who needs quick solutions to everyday problems. Each recipe shows a concise code example right away. If you need more information, each recipe is explained in plain English.

Nearly every aspect of the development process can be sped up using Groovy. Groovy makes mundane file management tasks like copying and renaming files trivial. Reading and writing XML has never been easier with XmlParsers and XmlBuilders. JDBC gets a fresh makeover. Breathe new life into Arrays, Maps, and Lists with a number of convenience methods. Even Ant gets turbo-charged. You can mix Groovy right into your build.xml, or replace it completely with code from an AntBuilder.

As an added bonus, this book also covers Grails. You’ll be amazed at how quickly you can have a first-class web application up and running from ground zero. Grails includes everything you need in a single zip file, a web server (Jetty), a database (HSQLDB), Spring, Hibernate, Sitemesh, even Ant. If you’re looking for Ajax support, Grails ships with leading libraries like Prototype, script.aculo.us, Yahoo UI, and Dojo. We cover everything from getting a basic application up and running to advanced features such as deploying to other webservers and databases, adding a Captcha, integrating with legacy EJB applications, and even adding a Google Map.

- O’Reilly

Tags:

Oracle backs Groovy and Grails

May 29th, 2007

Around JavaOne 06, Oracle made a significant announcement which perhaps because of the hype around Ajax and EJB 3.0, was missed by many Java developers. Oracle announced its plan to support Groovy and Grails and the new JSR-223 specification to enable scripting languages. Groovy is an agile dynamic language for the Java Platform while Grails is an open-source web application framework that uses Groovy to bring Ruby On Rails ideas to the java world.

Although scripting languages have been a topic for discussion for some time now, none of the major Java players had invested much time, money and effort in pushing these languages. With this announcement, Oracle has got behind Groovy and Grails, which are both still in an early stage of development.

It is still anybody’s guess if scripting languages will catch on and maybe even replace the Java language, but with this Oracle announcement, languages like Groovy now have a better chance. Unless the marketing guys get to work very rarely does a technology become mainstream. We have a recent example of SOA, which many believe is an old idea recycled and hyped up.

The reason why Groovy and Grails are expected to do well is because although they introduce many new concepts meant to simplify development, they still stay close to the Java platform and enterprise Java development. While Groovy generates bytecodes that will run on the Java platform, Grails generates a J2EE application that can run on any J2EE server.

IndicThreads

Tags:

G2One Report (via Juixe TechKnow)

May 28th, 2007

The G2One, Groovy and Grails mini-pre-JavaOne conference, was put together by the folks behind No Fluff, Just Stuff conferences. The G2One mini-conference brought together Guillaume LaForge, the Groovy project lead, Graeme Rocher, Grails project lead, and Groovy in Action author Dierk Koenig amongst other Groovy developers and evangelist.

Guillaume started the event by proving a quick introduction of Groovy and going into the details of the upcoming release. Groovy provides semantic sugar and sweetness to the Java VM. Groovy is Java-like and compiles down to Java to byte code but with the added bonus of the GDK, the Groovy Development Kit. You can mix and match Java/Groovy classes seamlessly, no bridge/connector required. I think that Groovy is what Java 3 should and might be. For example, Groovy provides string substitution, array and map literals, and regex literals. There are Eclipse plugins for Groovy that come with code completion, navigation, and highlighting. Groovy 1.1-beta has support for annotations.

Graeme talked about the currently available Grails 0.5 release. Grails builds on top of Groovy as the language used in the models and controllers, Spring for the Inversion of Control container, Hibernate for the Object Relational Mapping, Quartz for task scheduler, and Sitemesh for templeting. Grails comes with an embedded Jetty servlet container and embedded HSQLDB database for quick turn around agile development. Graeme stated that most of the behavior in Grails is provided by plugins. So what is new in Grails 0.5? Command Objects in controllers. List and map support in GORM. Cascading validation. Script event hooks. Converter plugin to automatic convert models too XML, JSON, or RSS.

There was a series of rapid fire demoes by Guillaume, Graeme, Dierk, and other Groovy developers. One demo used the SwingBuilder groovy class to mashup GMaps and Flickr data. The demo used XMLSlurp to consume XML RSS feeds. Remixing and mashing up Google Maps and Flickr is like the ‘Hello, World’ first program of Web 2.0 mashups. When demoing the Swing-based mashup, Dierk Koenig said of the aesthetics of his demo, “This is what happens when you program in Swing, the first attempt is usually ugly.”

Juxie TechKnow

Tags:

Groovy Scripting Tips for Oracle ADF Business Components (Steve Muench)

May 22nd, 2007

Groovy Scripting Tips for ADF Business Components

ADF BC now provides integrated support for Groovy, a dynamic scripting language for the Java platform standardized in JSR 241. Groovy in ADF Business Components is dynamically compiled and evaluated at runtime. The JDeveloper/ADF 11.1.1.0.0 Technology Preview release is using the Groovy 1.0 release. The primary benefits of the ADF Business Components Groovy integration are:

  • Customization - because it is dynamically compiled, Groovy script can be stored inline in our XML and is eligible for customization
  • Simplification - Groovy supports object access via dot-separated notation

    so we can support syntax like:

    Salary * 0.10

    instead of

    ((Number)getAttribute(”Sal”).multiply(new Number(0.10))

    in Java in a calculated field expression,  or syntax like:

    PromotionDate > HireDate

    instead of

    ((Date)getAttribute(”PromotionDate”)).compareTo((Date)getAttribute(”HireDate”)) > 0

    in a validation rule.

You can use Groovy script expressions in the following different places in ADF Business Components:

  • Validation - you can use a Groovy script (that returns true or false) for declarative validation.
  • Validation Error Messages - you can use Groovy expressions to substitute the named tokens (e.g. “The value {val} is not legal.”}) in the error message
  • Bind Variables - you may define the value for a bind variable using a groovy script expression
    • Default Values
    • View Criteria
  • View Accessor Bind Variable Values - you may supply bind variable values in a view accessor using Groovy script
  • Attributes - you may base a transient attribute on a Groovy script
  • Attribute Default Values - you may define a default value expression on an attribute using groovy script

Keywords and Available names

The current object is passed in into the script as the ‘this’ object so to reference any attributes inside the current object, simply use the attribute name. For example, in an attribute-level or entity-level Groovy Script Expression validator, to refer to an attribute named “Ename”, the script may say simply reference Ename.

There is one top level reserved name adf to get to objects that the framework makes available to the groovy script. Currently these objects include:

  • adf.context - to reference the ADFContext object
  • adf.object - to reference the object on which the expression is being applied. This can also be referenced just using the keyword object without the adf prefix.
  • adf.error - in validation rules, to access the error handler that allows the validation expression to generate exceptions or warnings

All the other accessible member names come from the context in which the script is applied:

  • Bind Variable - the context is the variable object itself. You can reference the structureDef property to access other information as well as the viewObject property to access the view object in which the bind variable is defined.
  • Transient Attribute -  the context is the current entity or view row. You can reference all attributes by name in the entity or view row in which it appears, as well as any public method on that entity or view row. To access methods on the current object, you must use the object keyword to reference the current object like this object.yourMethodName(…) The object keyword is equivalent to the this keyword in java.  Without it, in transient expressions, the method will be assumed to exist on the dynamically-compiled Groovy script object itself.
  • Expression Validation Rule : the context is the validator object (JboValidatorContext) merged with the entity on which the validator is applied. You can reference keywords like:
    • newValue - in an attribute-level validator, to access the attribute value being set
    • oldValue - in an attribute-level validator, to access the current value of the attribute being set
    • source - to access the entity on which the validator is applied in order to invoke methods on it (accessing simply accessing attribute values in the entity does not require using the source keyword)

Usage Notes

This scripting logic works like JSF Expression Language (EL)  in the sense that you can use a dot-separated path to reference properties of an object and its nested objects. However one big difference is that if a Java object implements the java.util.Map interface, then only the map lookup is performed (instead of the bean style property lookup). For Maps that extend ADF’s JboAbstractMap class however, you get the same EL-style behavior: map lookup first followed by bean lookup. Additional usage notes include:

  • All Java methods, language constructs and groovy language constructs are available in the script.
  • You can use built-in aggregate functions on ADF RowSet objects by referencing the functions:
    sum(String attrName) — e.g. sum(”Salary”)
    count(String attrName)
    avg(String attrName) on a RowSet object where expr can be any groovy expression that returns a numeric value (or number domain).
  • Use the return keyword just like in Java to return a value, unless it’s a one liner expression in which case the return is assumed to be the result of the expression itself (like “Sal + Comm” or “Sal > 0“).
  • Use the ternary operator to implement functionality like SQL’s NVL() function. For example: Sal + (Comm != null ? Comm : 0)
  • Do not use { } to surround the entire script. Groovy treats { as a beginning of a Closure object - See groovy documentation for more on Closures.
  • Any object that implements oracle.jbo.Row, oracle.jbo.RowSet or oracle.jbo.ExprValueSupplier is automatically wrapped by the ADF runtime into a Groovy “Expando” object to extend the properties available for those objects beyond the bean properties (to enable easy reference to ADF row properties even if no Java class is generated, and as a way to avoid introspection for most used names).

Examples

This is a simple example of a view-object bind variable default expression that references the value of a key named FunctionalRole from the ADFBC Session’s user data hashtable:

viewObject.DBTransaction.session.userData.FunctionalRole

This is a simple example of an entity-level Groovy script expression validator. The strings ExcGreaterThanApplicationLimit, WarnGreaterThan5000, and ExcTooLow are message bundle keys to error/warning messages.

if (Sal >= 5000){
  /*
   * If Sal is greater than a property value set on the custom
   * properties map on the root AM raise a custom exception else
   * raise a custom warning
   */
  if (EmpSal >= source.DBTransaction.rootApplicationModule.propertiesMap.salHigh) {
    adf.error.raise("ExcGreaterThanApplicationLimit")
  }
  else {
    adf.error.warn("WarnGreaterThan5000")
  }
}
else if (Sal <= 1000) {
  adf.error.raise("ExcTooLow")
}
return true

Steve Muench

Tags:

Groovy and Grails On A Roll (Charles Ditzel)

May 8th, 2007

There were 600 developers sitting in on the Groovy session this morning.  I missed it.  I came in late - saw how huge the line was and saw that the room was already almost filled and I abandoned all hope.  Afterwards I met with Guillaume LaForge (Groovy) and Graeme Rocher (Grails). It is clear that these symbiotic communities are growing quickly. Leveraging the the  large advantage of being a Java-based framework with culturally and syntactic closeness to Java there is an increasing number of Java developers that are finding it to be closer to their developer culture than alternatives (like Ruby). Incidentally, Grails 0.5 is now out.  New features included are : Custom URL mappings DSL, command objects/form validation, list and map support in GORM, support for composition in domain class (Hibernate “components”),  Base64 codec,  dependency resolution with Ivy, Project metadata and versioning support, script event hooks, new Artifact API available to plugins and much more.

Charles Ditzel

Tags:

Cool New Features In Grails 0.5 (Jeff Brown)

May 1st, 2007

Grails 0.5 was released today and this release is one of the most exciting releases yet. This release has closed the gap on a number of key features that needed to be knocked out before the coming 1.0 release. Some of the new features will be more appealing to some projects and other features more appealing to other pojects. For me some of the coolest new features added in 0.5 are Command Objects, List and Map Support in GORM and Custom URL Mappings. Hundres of JIRA issues have been addressed in this release and significant performance enhancements have been made. The development team got a whole lot done during this iteration. See the release notes for a more complete list of new features.

With the recent release of the first beta of Groovy 1.1, things continue to heat up in the Groovy and Grails communities.

This year I have been speaking at Java User Groups, internal training events and on the No Fluff Just Stuff Tour about Groovy and Grails and I am finding that folks in the Java community are really excited about both Groovy and Grails and the possibilities that these technologies bring to their projects. After a bit of time that really seemed kind of dull for the JVM, Groovy and Grails are making it all fun again and at the same time adding a lot of value to the enterprise by increasing productivity and expanding the possibilities. For example, defining a DSL using Antlr or similar technologies may not have been a realistic possibility for many applications but dynamic technologies like Groovy make things like that not only possible but simple to build. There are many many examples just like that which represent ways Groovy can help developers get their jobs done faster and more simply. Frankly, I don’t think Grails would be anywhere near as compelling as it is if it weren’t for all of the coolness made possible by Groovy. Grails has taken the possibilities that Groovy provides and leveraged them all over the framework to provide simple concise techniques for web application developers to use to build powerful web applications very quickly.

Grails has earned a lot of respect in the community by getting very far along in a short amount of time. While Grails applications are already being deployed in production environments, both private and public facing sites, the coming 1.0 release is going to push Grails right out there to the front of the pack. This is exciting stuff!

More to come… :)

Jeff Brown

Tags:

Grails vs Rails Performance Benchmarking (Grails.org)

March 31st, 2007

Intro

Recently someone asked the question: “Where are the Grails vs Rails benchmarks??”. Since we actually haven’t got round to optimising Grails I thought it was silly that we should benchmark a 0.4.2 release against Rails which is now at 1.2.x. Nevertheless, to allay concerns about Grails I decided we should do it anyway. This page represents the results.

The reality of this benchmark is that it is actually more like Rails vs Groovy + Spring MVC + Hibernate + Sitemesh. Grails can take some credit of course, but the heavy lifting is being done by Spring & Hibernate in particular.

I am by no means a benchmarking expert, so if you have any changes or recommendations please shout


Update - After feedback from Jared Richardson who detailed how with Rails & Mongrel you actually need multiple Mongrel instances to be equivalent to tomcat I decided to conduct some further tests. This basically showed my naivety when configuring Rails, but there you go, so I apologise for the falseness of the original benchmarks.

To be clear what I have done is do configure Rails with a 10 Mongrel cluster and Pound as per Jared’s tutorial here. To make things fair I also reduced Tomcat to use only 10 Java threads. The results can be seen in the updated benchmarks that follow.

If I have done something wrong in the Rails configuration please point it out, because if you read on, doing the clustering didn’t help much.

Hardware Specs

We are trying to be entirely open about this benchmark. Personally I feel benchmarks are of limited value, but some live by them so there you go. To get some of the details out the way then. The test hardware is as follows:

Apple MacBook
1.83ghz Intel Core Duo
1GB 667 Mhz DDR2 SDRAM

Ok I know, I know it isn’t a server, but I didn’t have one lying around, so this will have to do. It has dual cores after all

Software Specs

Now onto the software platforms:

Grails

  • OS: Mac OS X 10.4.9
  • Server: Apache Tomcat 5.5.20
  • Version: 0.5-SNAPSHOT from 20th of March
  • Environment: Production
  • Database: MySQL 5.0.27
  • Java: Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164)
  • JDBC Driver: mysql-connector-java-3.1.10-bin.jar
    I decided to benchmark with 0.5-SNAPSHOT because it implements the new URL mapping feature and since Rails has routes it evens the playing field out a bit. In other words it would be unfair on Rails if we benchmarked with Grails not having a routing feature, as it does in the upcoming 0.5


Configuration A: Standard Tomcat

The first test was with a standard Apache Tomcat 5.5.20 configuration, with the following settings:

<Connector port=“8080″ maxHttpHeaderSize=“8192″
               maxThreads=“150″ minSpareThreads=“25″ maxSpareThreads=“75″
               enableLookups=“false” redirectPort=“8443″ acceptCount=“100″
               connectionTimeout=“20000″ disableUploadTimeout=“true” />

Configuration B: Tomcat configured with a 10 thread pool

To even things up with Rails having 10 mongrel’s I decided to configure Tomcat with only 10 threads with the following configuration:

<Connector port=“8080″ maxHttpHeaderSize=“8192″
               maxThreads=“10″ minSpareThreads=“1″ maxSpareThreads=“1″
               enableLookups=“false” redirectPort=“8443″ acceptCount=“100″
               connectionTimeout=“20000″ disableUploadTimeout=“true” />

Rails

Set-up according to the article here: http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx

  • OS: Mac OS X 10.4.9
  • Server: Mongrel 1.0.1
  • Version 1.2.3
  • Environment: Production (Started with mongrel_rails start -e production)
  • Database: MySQL 5.0.27
  • Other notes: I installed the Ruby MySQL native bindings as per the aforementioned article

So the same database for both and the most commonly deployed container for Grails (there might be faster containers out there, but I’m not here to test containers). As for Rails I have been told by multiple sources that Mongrel is THE container to deploy to for maximum performance, but I’m no expert so please correct me if I’m wrong here.

Also note that I have not bothered to connect Grails or Rails up to Apache using mod_jk or the equivalent Rails FastCGI connector.


Configuration A: A single mongrel instance

The first Rails configuration was using only a single mongrel instance and hitting it directly on port 3000.

Configuration B: 10 mongrels with load balancing by Pound

The second configuration I used a 10 mongrel cluster configured as per Jared Richardson’s instructions here and configured it with this command:

sudo mongrel_rails cluster::configure -e production -p 8001 -N 10

To start-up the cluster I did:

sudo mongrel_rails cluster::start

I then used Pound as a load balancer with the following configuration again setup as per Jared’s instructions:

ListenHTTP
   Address 0.0.0.0
   Port 3000
End

Service
  BackEnd
    Address 127.0.0.1
    Port 8001
  End
  BackEnd
    Address 127.0.0.1
    Port 8002
  End
  .. etc ..
  BackEnd
    Address 127.0.0.1
    Port 8011
  End

Session
Type BASIC
TTL 300
End
End

The Test Applications

Now onto the nature of the tests. So basically I didn’t want to get into anything too fancy, so I’m testing these things:

  1. Read operations
  2. Create operations
  3. Queries
  4. Update operations
  5. View rendering vs. writing directly to the response

I am not going to be testing any really complex operations as the more complex an application is the more it becomes application performance and not framework performance that is being compared. Moving on then I set-up the test with the scaffolding capability of each framework. So with Grails I created a domain class like:

class Book {
	String title
	String author
	String description
	Date  dateCreated = new Date()

	static constraints = {
		title(nullable:false, blank:false)
		author(nullable:false, blank:false)
	}
}


Then ran the following command to generate the base controllers and views:

grails generate-all


Similarly with Rails I created the following table in mysql:

To create this yourself you can do it in MySQL’s tools or by running the DDL:

CREATE TABLE `books`.`books` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `title` VARCHAR( 255 ) NOT NULL,
  `author` VARCHAR( 255 ) NOT NULL,
  `description` TEXT,
  `date_created` TIMESTAMP NOT NULL,
  PRIMARY KEY (`id`)
)
CHARACTER SET utf8;


I then created the following model in Rails:

class Book < ActiveRecord::Base
end


And then ran the command

ruby script/generate scaffold book


The Test Data

With that done, the way I setup some test data was to create an action to do so in each respective controller. In Grails I did this:

def data = {
     def i = 1000
     while( i > 0 ) {
         def book = new Book()
         book.title = “Book ${i}”
         book.author = “Author ${i}”
         book.description = “The description for book ${i}”
         book.save()
         i = i - 1
	 }
     render “Created data!”
	}


In Rails to achieve the same thing I did this:

def data
   i = 1000
   while i > 0
       @book = Book.new
       @book.title = “Book #{i}”
       @book.author = “Author #{i}”
       @book.description = “The description for book #{i}”
       @book.save
       i = i - 1
   end
   render :text => “Created data!”
end


Sending a request to each action created the data. Job done. Now we have some test data and the respective list views of each app look like this:

If you want to download the full test applications they can be downloaded from here:

Test Tools

To perform the tests I used ApacheBench which is available with the “ab” command on Mac OS X. Just for clarity here is the version info

This is ApacheBench, Version 1.3d <$Revision: 1.73 $> apache-1.3
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

The results have then been graphed up using Apple Pages. The full PDF can be download here

Test A: Read Performance

So after creating the test data we now have 1000 records in each applications respective database. Just to be clear the code that renders the above view is the standard scaffolded list view for both apps with the server side code in Grails being:

def list = {
    if(!params.max)params.max = 10
    [ bookList: Book.list( params ) ]
}


And in Rails:

def list
  @book_pages, @books = paginate :books, :per_page => 10
end


To run the read performance test I executed the commands:

// for rails
ab -c 50 -n 1000 -e “rails_list_test.csv” http://localhost:3000/books/list

// for grails
ab -c 50 -n 1000 -e “grails_list_test.csv” http://localhost:8080/books/book/list


Obviously not at the same time!
So what this does is send 1000 requests to the respective servers with 50 concurrency. I made sure all other applications were closed to make sure the figures were as accurate as possible. The results of the read test are below:


Grails is able to handle 40 requests per second to Rails 32. Significantly you can notice Grails has a much poorer worst case response time, but a superior mean response time (The mean time is the average time taken per request over all 1000 requests). This can be put down the Java threading model and the Thread pool in Tomcat at some point running out of available threads and blocking for a moment. It just reflects the differences in architecture more than anything else. If you ran the same test against Grails with a concurrency of 1 you would see linear performance as expected:

ab -c 1 -n 1000 -e “grails_list_test.csv” http://localhost:8080/books/book/list


Interestingly, Grails with only 10 threads is even more performant and is able to cope with 54 requests per second. We also see that the spikes in the max response time are gone with a configuration for less threads. If you think about it this makes sense given the hardware I’m testing on. I only have dual cores on this Macbook, so the more threads there are the more processes have to share the two cores and hence the overall performance degrades with more threads. If I was running a machine with 8 processors then having more threads would obviously be more beneficial.

Rails on the other hand with 10 mongrels and Pound degrades in performance. I guess this is down to more processes having to share the two cores, but if someone can explain if I’ve done anything wrong in the config please say so

Test B: Creating Records

The next test was to test creating new records. In this case I used a simple action for both. The Rails code is:

def createTest
   i = 5
   while i > 0
       @book = Book.new
       @book.title = “Book #{i}”
       @book.author = “Author #{i}”
       @book.description = “The description for book #{i}”
       @book.save
       i = i - 1
   end
   render :text => “Created 5 records data!”
end


As you can see it just creates 5 records in a loop and then renders some text to the response. No view involved. The Grails code for this is:

def createTest = {
 def i = 5
 while( i > 0 ) {
     def book = new Book()
     book.title = “Book ${i}”
     book.author = “Author ${i}”
     book.description = “The description for book ${i}”
     book.save()
     i = i - 1
 }
 render “Created 5 records data!”
}


To run the create performance test I executed the following ab commands framework:

// for rails
ab -c 50 -n 1000 -e “rails_create_test.csv” http://localhost:3000/books/createTest

// for grails
ab -c 50 -n 1000 -e “grails_create_test.csv” http://localhost:8080/books/book/createTest


Again with a 1000 requests, and 50 concurrency. The results are as follows:


The differences here are quite astounding, Grails is able to cope with 140 requests per second and has a mean average of 345ms per request compared to Rails’ 35 (and a half) and 1.3 seconds per request. I believe, without having done any real profiling, the reasons for this can largely put down to Hibernate’s session-based model. Each call to save() in ActiveRecord immediately persists the data whilst Hibernate batches updates up until the end.

Again Grails with only 10 threads is faster, whilst Rails with 10 mongrels degrades performance.

Test C: Querying

The next test tackled querying using a like query. The bottleneck here is likely to be MySQL’s query performance. The code for this test for Rails is as follows:

def queryTest
    @books = Book.find(:all, :conditions => [“title like ?”, “Book 6%”])
end


The view used is the same as the default list view just cloned and renamed to queryTest.rhtml. For Grails the same thing is done:

def queryTest = {
   [bookList:Book.findAllByTitleLike(“Book 6%”)]
}


There is no equivalent to Rails’ :conditions element in Grails so we use a finder expression. Again to execute this test we use similar commands:

// for rails
ab -c 50 -n 1000 -e “rails_query_test.csv” http://localhost:3000/books/queryTest

// for grails
ab -c 50 -n 1000 -e “grails_query_test.csv” http://localhost:8080/books/book/queryTest


The results for this test can be seen below:


As you can see the results here are much more equal as it is really reliant on database performance. Notably we can see Grails’ worst case is poor down to blocking in the thread pool, but overall the mean time of 5.387ms is superior to Rails’ 6.386, which illustrates why Grails’ is able to deal with 8.92 requests per second as oppose to Rails’ 7.65.

Neither framework comes off particularly well here, but in reality if you had this kind of load for queries you would need consider using some sort of caching and/or indexing solution (lucene/ferret).

This is the one test though, where Rails with 10 mongrels gets close to matching the default Grails tomcat configuration and where Grails with 10 threads is slower than the default tomcat config.

Test D: Updating record and rendering a view

For this test we’re trying out updating and then rendering a view. To do so we’re going to retrieve some random records from the database and update each and then store the value. To achieve this in Rails we do:

def updateTest
   count = Book.count
   ids = [rand(count),rand(count),rand(count)]
   @books = []
   ids.each { |id|
     book = Book.find(id)

     if book
        book.author = “Fred Flintstone #{Time.new}”
        book.save
        @books << book
     end
   }
end


To explain this logic we basically create 3 random ids from the total, retrieve them from the database, update the author field and then save. And before you ask I definitely checked that the databases of both were dropped and re-created with fresh test data with the ids on the tables indexing from 1-1000. The view for this action is again copied from the list view and renamed to updateTest.rhtml.

For Grails to achieve the same thing we do:

static final rand = new Random()
def updateTest = {
	def count = Book.count()

	def ids = [rand.nextInt(count), rand.nextInt(count),rand.nextInt(count)]
	def result = []
	ids.each { id ->
		def book = Book.get(id.toLong())
		if(book) {
			book.author = “Fred Flintstone ${new Date()}”
			book.save()
			result << book
		}
	}
	[bookList:result]
}


Again the same logic, instead of the C rand(num) function in Ruby we use Java’s java.util.Random class and calculate a bunch of ids, iterate over each, saving each one to formulate the results.

Again to execute this test we use similar commands:

// for rails
ab -c 50 -n 1000 -e “rails_update_test.csv” http://localhost:3000/books/updateTest

// for grails
ab -c 50 -n 1000 -e “grails_update_test.csv” http://localhost:8080/books/book/updateTest


The outcome of this test can be seen below:


Once again we see a similar graph, Grails having the higher max, but a superior mean average response time. Grails is able to deal with 44.95 requests per second to Rails’ 30.88. This can be put down to a number of things, again I believe it is the difference between Hibernate’s session based approach and ActiveRecord.

Another thing to note is during the Grails test 2 Hibernate StaleObjectExceptions were thrown because Grails uses Hibernate’s optimistic locking feature, which ActiveRecord doesn’t seem to have any concept of (correct me if I’m wrong). In a real circumstance when dealing with high concurrency you would of course catch this exception in Grails, which would actually be a Spring HibernateOptimisticLockingFailureException and deal with it appropriately by getting fresh data or returning an error (the default case).

Again similar to the first two tests, we see Grails with only 10 threads being even more performant and Rails with 10 mongrels degrading.

Test E: Updating 3 random records and return idiomatic XML

So after the above result I wanted to see what the performance would be like when not using a view (RHTML or GSP). So instead we return some XML. In rails the code for this is:

def updateTest2
   count = Book.count
   ids = [rand(count),rand(count),rand(count)]
   @books = []
   ids.each { |id|
     book = Book.find(id)

     if book
        book.author = “Fred Flintstone #{Time.new}”
        book.save
        @books << book
     end
   }
   render_text @books.to_xml
end


Note here we call to to_xml method to auto-convert to XML which is a nice feature. The resulting XML looks something like:

<?xml version=“1.0″ encoding=“UTF-8″?>
<books>
  <book>
    <author>Fred Flintstone Thu Mar 22 15:35:54 +0000 2007</author>
    <date-created type=“timestamp”>Thu Mar 22 12:20:21 +0000 2007</date-created>
    <description>The description for book 3</description>
    <id type=“integer”>5908</id>
    <title>Book 3</title>

  </book></books>


To do the same thing in Grails requires a little more code as Grails doesn’t have a toXML() yet (actually it does, but it is currently in the REST plug-in, see http://grails.org/Plugins). So instead of toXML() we use Groovy mark-up building:

def updateTest2 = {
	def count = Book.count()

	def ids = [rand.nextInt(count), rand.nextInt(count),rand.nextInt(count)]
	def result = []
	render(contentType:“text/xml”) {
		books {
			for( ident in ids ) {
				def b = Book.get(ident.toLong())
				if(b) {
					b.author = “Fred Flintstone ${new Date()}”
					b.save()
                    book {
                    	author(b.author)
               			‘date-created’(b.dateCreated)
               			‘description’(b.description)
						id(b.id)
						title(b.title)
					}
				}
			}
		}
	}
}


The result of the two methods is exactly the same XML (changing data of course). Now for running the tests, again the same commands:

// for rails
ab -c 50 -n 1000 -e “rails_update_test2.csv” http://localhost:3000/books/updateTest2

// for grails
ab -c 50 -n 1000 -e “grails_update_test2.csv” http://localhost:8080/books/book/updateTest2


And the result is:


So that is pretty similar to the first update test. Again Grails is around 40-50% faster. Now there is a lot of dynamic stuff going on when producing the XML from these two actions so I thought I would have a go at building up a String and writing it to the response.

Again similar to the first two tests, we see Grails with only 10 threads being even more performant and Rails with 10 mongrels degrading.

Test F: Updating 3 random records and returning a String generated response

This test actually is more a like for like as we don’t have to deal with the differences between to_xml in Rails and mark-up building in Grails. The Rails code for this is:

def updateTest3
  count = Book.count
   ids = [rand(count),rand(count),rand(count)]
   xml = “<books>”
   ids.each { |id|
     book = Book.find(id)

     if book
       xml << “<book>”

        book.author = “Fred Flintstone #{Time.new}”
        book.save
          xml << “<author>#{book.author}</author>”
          xml << “<date-created>#{book.date_created}</date-created>”
          xml << “<description>#{book.description}</description>”
          xml << “<id>#{book.id}</id>”
          xml << “<title>#{book.title}</title>”
       xml << “</book>”
     end
   }
   xml << “</books>”
   render_text xml
end


The XML that is produced is exactly the same as in the previous test, except constructed manually from a String. The equivalent Grails code looks like:

def updateTest3 = {
	def count = Book.count()

	def ids = [rand.nextInt(count), rand.nextInt(count),rand.nextInt(count)]

	def xml = new StringBuffer(“<books>”)
	ids.each { id ->
		def b = Book.get(id.toLong())
		if(b) {
			b.author = “Fred Flintstone ${new Date()}”
			b.save()
               xml << “<book>”
               	 xml << “<author>${b.author}</author>”
				 xml << “<date-created>${b.dateCreated}</date-created>”
             	 xml << “<description>${b.description}</description>”
             	 xml << “<id>${b.id}</id>”
             	 xml << “<title>${b.title}</title>”
			   xml << “</book>”
		}
	}
	xml << “</books>”
	render xml.toString()
}


Again it uses the static java.util.Random instance and constructs the String from a StringBuffer. Now we execute the commands:

// for rails
ab -c 50 -n 1000 -e “rails_update_test3.csv” http://localhost:3000/books/updateTest3

// for grails
ab -c 50 -n 1000 -e “grails_update_test3.csv” http://localhost:8080/books/book/updateTest3


Again with a 1000 requests, and 50 concurrency. The results are as follows:


Grails in this case is able to process nearly 3 times as many requests as Rails per second. So why are the first 2 update tests so much slower for Grails (although still faster than Rails?). Well what these tests have helped us identify is that with a large amount of load Groovy Server Pages, Grails’ view technology, certainly needs some improvement.

And again similar to the first two tests, we see Grails with only 10 threads being even more performant and Rails with 10 mongrels degrading.

The way GSP works internally with tag libraries is that it uses try/catch blocks to intercept exceptions thrown by Groovy when it doesn’t find a method. These are of course expensive as the JVM has to take a snapshot of the exception when it is thrown which causes all threads to freeze momentarily. So one area where we can improve Grails’ performance is to look at tweaking GSP to not do this (there are other techniques for doing this).

So why does this effect the second example? Groovy’s streaming markup builder is using the same technique!

Summary

Overall, as expected, given its base on solid Java technologies, Grails out performs Rails (100% Ruby) in pretty much every test. As I said at the start I’m no Rails performance tuning wizard, so if someone can suggest ways to get Rails to perform better please say so. We are conducting these tests purely to inform concerned Grails users who are asking for figures, and hope to review them as Grails progresses.

Interestingly, Grails, at least on this machine, sees performance increases when lowering the thread pool to 10, whilst Rails suffers when 10 mongrels are configured with Pound.

Grails hasn’t undergone much optimisation at all yet and there are certainly areas we can improve on, GSP rendering being one. GSP is of course a much more complex view rendering technology in comparison to RHTML due to its support for dynamic tag libraries, plus Sitemesh decoration. However, there are definitely areas in GSP, such as the way it uses exceptions, that can be improved upon.

Another point to remember is performance != scalability. The way you would scale an application to deal with the kind of load we have here differs greatly between Grails & Rails I imagine. With Grails you could stick a Terracotta or Coherence distributed cache on the back of it to implement SSI (singe system image) or use HTTP session replication across a cluster whilst with Rails you could ??? (a Rails user please feel free to provide an answer to this question in the comments, I’m not qualified to answer).

Nevertheless, I am quite satisfied that Grails performs sufficiently well to be competitive and there is little point in optimising prematurely. Our main goals is to focus on getting 1.0 out towards the middle of this year.

Resources

Grails.org

Tags:

Grails vs Rails performance (Refactr)

March 23rd, 2007

Graeme has taken the time to respond to some of the comments floating about in the blogosphere about the performance of Grails vs Rails. This benchmarking comes out very favorably for Grails. In nearly every case, the requests per second and mean response time come out with Grails performing better than Rails. And in some cases, Grails literally blows Rails away (140 vs 35.5 requests/sec on the create test!!). The max response time for Grails is higher in nearly every test case, but this is completely understandable as Graeme points out. I also wonder if he took note of the fact that Grails is always going to be slower for the first hit, but over time will speed up due to the nature of the JVM.

It’s important to keep in mind that Grails has yet to be optimized much (or at all), whereas Rails has been around longer and has been optimized much more. This is the part that makes me feel the best, actually, because it means that there are probably a lot of places where relatively simple changes can improve the performance of a Grails app significantly. Add to that the fact that in Grails you can always drop down and write native Java to increase efficiency (vs. having to write C in Ruby/Rails) and I think it’s clear that Grails is at the very least on par with Rails and likely has even better performance characteristics.

Refactr

Tags:

Where are all the Groovy (and/or Grails) benchmarks? (Thoughtmining)

March 19th, 2007

Ok, I’ve been dipping my toe into Groovy for the past week or so, including some Grails thrown in for good measure. I like what I see. In a previous life, I was a long-time Java developer, and even after a shift to management almost four years ago, I still code on an almost daily basis.

I’ve been searching for awhile now for a dynamic language to use as our “standard” in-house “scripting” tool. We’ve too many perls, pythons, bashes, and more running amok on various boxes and projects across our enterprise. In the last two years, I’ve become quite enamored with Ruby — both with Rails and down at my Linux command prompt, where it finally gave Perl the “don’t have to go home but you can’t code here” hint — but I’ve missed some of the libraries I’d taken for granted in the Java world.

And, for what we do, integration with Java is highly desirable. In my mind (and for the feature set I desire) this points to two possibilities: JRuby and Groovy.

JRuby is very nice. It has my nice comfortable Ruby syntax, open classes, and more. But two things trouble me currently:

  1. Java integration isn’t fully there. You can write Ruby classes that call Java classes, BUT, you can’t develop classes in Ruby and then make use of them from Java as if they were “real” java classes. The JRuby guys are moving in this direction, but it’s not there yet.
  2. While others in our group really like Ruby, a few, especially the more junior guys, are still getting their heads around some of the more interesting (read painful) nuances of our architecture and J2EE technology in general. If I forced Ruby upon them now, they’d probably walk (albeit missing a great opportunity).

Enter Groovy. I’ve eyed it on more than one occasion, but it wasn’t until I picked up a copy of GinA a few weeks ago that I finally gave it a shot. And it’s nice! Many parts feel as if they come directly from Ruby, so much so that it’s not a stretch to pick up very quickly. It also provides the Holy Grail of Java integration: Java->Groovy->Java call capabilities….in other words, your Java can call your Groovy can call your Java. That’s extremely cool, and creates a whole new realm of possibilities for a Java shop like ours. Throw in syntax that is welcoming to a Java developer and compilation to byte code, and the case for Groovy is a strong one!

So, being the good PHB^H^H^H CIO that I am, I began the due diligence process. What due diligence, you ask? When looking at technology that could become a significant part of our development environment, I, as a PHB, look for general indicators that give warm fuzzy feelings (while in reality, could mean nothing):

  1. Review of the architecture and design decisions made by the developers.
  2. Size, responsiveness and general attitude of the community, particularly on the mailing lists.
  3. Current buzz surround the technology on blogs, tech pubs, etc.
  4. Benchmarks comparing the technology to other competing options.
  5. Commercial uptake.

I’ll leave the reasoning behind these questions for another discussion, but over the years I found that (right or wrong) they’ve served me well in assessing new tools or frameworks.

Groovy (and Grails, to a certain extent) scores well on 1, 2, and 3 above. I like the technology so far, and from what I understand of the overall design it is very well thought out. The community is very welcoming, and the lists have been extremely helpful. There is quite a bit of effort to market Groovy and Grails, and with the release of GinA, seems like there is a new article daily.

However, when I went after 4 and 5, I was surprised. Regarding 4: I can’t find a SINGLE benchmark comparing Groovy to competing technologies on the JVM (JRuby, Beanshell, Jython) or dynamic languages in general (Ruby, Python, Perl, and so on). Nor can I find any benchmarks concerning how Grails stacks up to JRuby on Rails, Ruby on Rails, vanilla Hibernate/Spring (something Grails uses under the covers), etc.

Surely, a technology that’s got 1, 2, and 3 down has had someone do this sort of research?!? Surely someone close to the respective projects has asked these hard questions of themselves?

Because I know the previous paragraph has to, has to, be true, then I can only assume one thing: someone has done this as an exercise…and the results were depressing. Why else would the results not be published? If Groovy or Grails was faster, even slightly so, then you can bet it would trumpeted far and wide. The fact that it’s not leaves an unsettling feeling.

I’ve asked the questions on the mailing lists, and I’ve only gotten vague wishful answers, to the tune of “well, we use Java (Spring/Hibernate) under the covers, so we’ve got to be as fast or faster”. Really? Then where are the numbers? Why this gap?

I think it would behoove the Groovy guys (and Grails guys as well) to put some of this research in the public eye. I don’t necessarily care that it’s slower…I just want to know how it compares. It doesn’t rule it out in any way regarding whether we use it or not…it only lets us know where we stand. It gives warm management fuzzies.

So I’m now working on my own benchmarks, but given time limitations it’ll be rough. Don’t hold it against me…after all, I’m just a PHB. I will definitely post the results here when I have them. Anyone with suggestions on the best way to approach this sort of benchmark, please let me know.

Regarding commercial uptake, or number 5 above, the explanations that are offered regarding this in both camps is that many big companies are using Groovy and Grails, but because of competitive advantage they won’t allow themselves to be revealed. That’s a hard point to prove or disprove, but it would help if there were at least a few successful products out there constructed in Groovy or Grails. In the Ruby on Rails world, it seems there are more than a few companies very willing to divulge that they use Rails…no doubt to ride the Rails marketing machine’s coat tails. Why should we accept that, given significant adoption, the adverse would be true for Groovy/Grails?

So, there you have it. It is not my intent to offend anyone in the Groovy or Grails communities…as I said, you’ve been great so far. I’m only trying to give you the perspective of one decision maker, in one company, who is taking a hard look at your projects and assessing the viability of adoption. I really like what you guys are doing, but I need your help in understanding how well it’s working. I’m sure others do as well.

Thoughtmining

Tags: