Deploying Grails - Things I learned from Feedlr

When I was about to deploy Feedlr on my VPS server there wasn’t much information about the deployment of Grails out there. I know that deploying a Grails war is just like a Java war. But are there going to be any differences? How much memory do I need? Will it eat any more hardware than a plain old Java app? I really have no idea. So this post is about the server stuff I’ve learned by doing the deployment for Feedlr.

I started by deploying my Grails app on Tomcat 6 on a 256M RAM VPS. And since my blogs are also hosted on this VPS, I use mod_proxy_ajp to connect Tomcat to Apache for Feedlr.

My first attempt on the 256 VPS turned out very badly. When I started Tomcat with Feedlr deployed, the server simply becomes very unresponsive and swap activity started flying. That’s a bad sign for “low memory”, I think. So I upgraded the server to 512M RAM and things began to look normal.

Then comes the optimization part. I really don’t have much server tuning experience, especially with a limited resource VPS. So all this is new and interesting to me, solving issues one by one.

The first bad thing happened was that whenever Tomcat ran for a while, like a couple hours, the whole VPS box began to eat a low of swap, and connection will often timeout. I suspected Tomcat, but it turned out to be Apache. The default installation on Ubuntu for Apache + PHP5 uses the Apache mpm_prefork module. The problem is that mpm_prefork spawns multiple Apache instances to handle requests to the server. And the default config is like

<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule>

The default config worked fine when I was only hosting a couple blogs on the 256 box. But with a Grails app on Tomcat running, memory becomes critical. So then I changed the settings to smaller numbers and it has been working fine now.

<IfModule mpm_prefork_module>
StartServers 2
MinSpareServers 2
MaxSpareServers 4
MaxClients 150
MaxRequestsPerChild 0
</IfModule>

I will replace mpm_prefork with mpm_worker module since the latter is more efficient for concurrency. Aptitude on Ubuntu can’t figure out for you how to put mpm_worker and PHP5 together so there are some config work to do. Currently I’m running mpm_worker on my development/staging server and it’s working fine but I just don’t know how it’s gonna behave on a low memory environment. BTW. If you have anything to say about this I’m all ears.

Then it’s about Tomcat. Actually Tomcat is working great with Grails out of the box. The tuning is all about memory and efficiency. Here’s my Tomcat startup opts:

CATALINA_OPTS=”-server -Xmx420m -Xms420m -XX:MaxPermSize=128m -Dcom.sun.management.jmxremote”

I set the heap size to 420M since I want to leave some room for my blogs. And so far this setting has worked fine for me. The “-Dcom.sun.management.jmxremote” part is for LambdaProbe which I’m using as the server management app.

Besides, for the production environment, it’s better to set reloadable=”false” for the Tomcat Context of the app. It should be false by default. In this way new code won’t be reloaded on the fly, but it saves quite some server overhead which can be notable on a low memory environment.

And finally, server logging. Here’s my logging settings in Config.groovy. Log files will be saved daily for stdout and stacktrace.

log4j {
    appender.stdout = "org.apache.log4j.ConsoleAppender"
    appender.'stdout.layout'="org.apache.log4j.PatternLayout"
    appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n'

//    	rolling file logger
    appender.logfile = "org.apache.log4j.DailyRollingFileAppender"
    appender.'logfile.File' = "/path/to/public_html/feedlr.com/logs/feedlr_grails.log"
    appender.'logfile.layout' = "org.apache.log4j.PatternLayout"
    appender.'logfile.layout.ConversionPattern' = '%d{[ dd.MM.yy HH:mm:ss.SSS]} [%t] %-5p %c %x - %m%n'

    appender.errors = "org.apache.log4j.DailyRollingFileAppender"
    appender.'errors.layout'="org.apache.log4j.PatternLayout"
    appender.'errors.layout.ConversionPattern'='%d{[ dd.MM.yy HH:mm:ss.SSS]} [%t] %-5p %c %x - %m%n'
    appender.'errors.File'="/path/to/public_html/feedlr.com/logs/feedlr_grails_stacktrace.log" //prod setting
    rootLogger="error,stdout"
    logger {
        grails="info,stdout,logfile" //prod settings
        StackTrace="error,errors"
        org {
            codehaus.groovy.grails.web.servlet="info,stdout,logfile"  //  controllers
            codehaus.groovy.grails.web.pages="info,stdout,logfile" //  GSP
            codehaus.groovy.grails.web.sitemesh="info,stdout,logfile" //  layouts
            codehaus.groovy.grails."web.mapping.filter"="info,stdout,logfile" // URL mapping
            codehaus.groovy.grails."web.mapping"="info,stdout,logfile" // URL mapping
            codehaus.groovy.grails.commons="info,stdout,logfile" // core / classloading
            codehaus.groovy.grails.plugins="info,stdout,logfile" // plugins
            codehaus.groovy.grails.orm.hibernate="info,stdout,logfile" // hibernate integration
            springframework="off,stdout,logfile"
            hibernate="off,stdout,logfile"
        }
    }
    additivity.StackTrace=false
}

P.S. I’m using SliceHost’s VPS and it’s great. I especially love the on-demand slice resizing which will automatically resize your VPS in minutes, with data completely intact. So you can totally start with a frugal setup and grow as needed. And did I mention completely full control over your server? I won’t say more but I know your inner geek would love it once you use it. So if you are seeking some good server space for your project why not give it a try with my referral link :)

Tags: , , , ,

  • thats a lot of info you packed in there, thanks :-)
  • Great post, definitely a holy grail of information as to what goes on with feedlr
  • nice mate! thanks for the information. hope it works
  • The production environment, it’s better to set reloadable=”false” for the Tomcat Context of the app to share.
  • And finally, server logging. Here’s my logging settings in Config.groovy. Log files will be saved daily for stdout and stacktrace.
  • durvetwormer
    The thinking of the site is really great. I wanna thank the service provider.
  • The server simply becomes very unresponsive and swap activity started flying.That’s a bad sign for “low memory" which is quite unusual now day's.
  • livingeek
    I was wondering if you would be willing to try this on say a Windows Hyper-V VDS/VPS system running Linux? We have started to offer VDS/VPS solutions to our customers and it would be interesting to see how this reacts compared to your SliceHost system
  • Grails is cool. Thanks for the post!! It gives me more idea..
  • I am interested with it and I would also like to learn this thing you called grails. Anyway what is grails?Thanks for posting
  • aldhika
    hi, im a grails newb, i would like to ask a few things :

    1. may i get your mod_proxy_ajp configurations?
    2. do you use absolute url in your app? coz im trying to do is remove the app in url, so my url would be like this www.mysite.com/controller/action, and not like this www.mysite.com/myapp/controller/action. but it seems not working some how for post request and redirect. get is working fine.

    ill appreciate it if you reply on my email.
  • Awesome post. I try to learning grails and it's difficult!
  • Denis Wang
    Thanks for your post. I further enhance it to customize the log file path across different env's. The trick is to define a global variable inside Config.groovy, customized it in the environment blocks, and use the variable location inside log4j closure.

    Sample Code can be found at:
    http://denistek.blogspot.com/2010/02/grails-environment-specific-logging-to.html
  • Great notes on deploying Grails
  • millipo12
    I would like to thank you for the efforts you have made in writing this article. I am hoping the same best work from you in the future as well. In fact your creative writing abilities has inspired me to start my own BlogEngine blog now. Really the blogging is spreading its wings rapidly. Your write up is a fine example of it.

    Have a nice day
    Floyd
    ______________________________________________
    miracle cabbage soup diet | miracle cabbage soup diet | miracle cabbage soup diet | miracle cabbage soup diet | cayenne pepper detox | cayenne pepper detox | cayenne pepper detox | cayenne pepper detox | maple syrup detox | maple syrup detox | maple syrup detox | maple syrup detox | british heart foundation diet | british heart foundation diet | british heart foundation diet | british heart foundation diet | weight gain diets | weight gain diets | weight gain diets | weight gain diets | easy diet plans | easy diet plans | easy diet plans | easy diet plans | sugar busters diet | sugar busters diet | sugar busters diet | sugar busters diet | diets for quick weight loss | diets for quick weight loss | diets for quick weight loss | diets for quick weight loss | diets for quick weight loss
  • zak
    Hey feedlr;

    I am desperately trying to get Tomcat and Apache to play together via mod_ajp_proxy. I cannot seem to find a good howto anywhere (everything is about the mod_jk connector). I am currently running my grails apps via Tomcat alone but I would like to get both up and running for additional flexibility.

    Think you might find time to post your setup here (on your blog) sometime?

    Thanks!
  • I have a problem to change context root...when i deploy my application and tomcat deploy it under application_name-version....do you have idea how to force it to a defined context-root?

    thanks
    luca
  • I had some problems with Tomcat5.5 on Ubuntu; tried then to use Jetty which refused to deploy my WAR; after googling the error in the catalina log I found I had to turn off Tomcat security, then I used the manager to upload and deploy my first Grails app.
  • Hi cjferic,
    Glad this could be helpful to you! I recently switched to apache mpm_worker and have been checking out the performance. I would update the article in a couple days about that.
  • cjferic
    Lucky enough to read your article. I have tried a whole day deploying a grails application on a machine with 256M memory. And the result is the same as yours. Now I got the reason. Thanks!
  • I've added a link to this post at the Grails Wiki Tutorials page, under Articles. http://grails.codehaus.org/Tutorials
  • Thanks Darryl! Definitely want to try jetty some time. And glassfish 2 since I've heard it's quite good too.
  • I have been a big fan of jetty since version 6 (beta) was introduced a few years ago. Prior to that I used tomcat 4 & 5 and found it a bit unstable, but I'm sure the problems have been fixed since 5.5.

    I haven't used resin for more than a jsp container but I haven't had any problems with it. I am looking forward to bench testing glassfish 2, especially for grails, but until then, jetty works fine, especially for groovy/groovlets.
  • I was wondering which app server to use, tomcat, jetty, or resin, which would run with the least memory and work nice with apache. I decided to use tomcat since I'm more familiar with it. I'd be interested to know how the other ones perform in real environments.
  • I recently deployed a grails application to slicehost using a 1M slice, jetty and MySql on fedora 7. The site also has resin running non-grails jsp pages, and occasionally rails for test/staging.

    I have yet to do anything to it except monitor, but I'm not using apache (yet). Thanks for your post.
  • The Grails wiki is user-editable, just click the little edit link, register an account of you don't have one, and you're ready to go!
  • Hi Matt,
    Cool to see you up here:) Sure I'd love to have it up. How shall I do that?
  • Great post, maybe we could get this up on the wiki?
  • Nice. Thanks for your post. I only started learning about grails recently, and i'm quite excited about it.
blog comments powered by Disqus