Archive for April, 2008

Performance tuning for Grails app in a memory constrained environment

Sunday, April 20th, 2008

Feedlr has been running quite well for a while, until a couple weeks ago, the server started to choke a lot. And I realized I had to do something to improve the performance. Actually, until then I had barely paid any attention performance-wise - getting the app up and running was the goal. And then with the growth of the app it’s time to do some work for that.

The Problem

The symptom of the performance bottleneck was that from time to time Tomcat would take a long time to respond, resulting in timeouts at the browser clients. This is caused by heavy swapping - apparently the 512MB RAM shared by all the services on the VPS, including Apache (with worker mpm), php, MySQL, and Tomcat, is less than abundant. But before upgrading my VPS, I want to see how far I can go with the current specs.

Attempting to optimize the code

My first attempt was to review my code and try to identify any possible memory leaks and memory inefficient spots. After working with profiling tools (I used an evaluation version of JProfiler, which is very good), and several refractory efforts, there was no obvious improvement. It didn’t look like a memory leak. And the effort trying to squeeze more memory from the code didn’t seem to pay off.

Tuning the JVM

Then I began to focus on tuning the JVM. The sporadic heavy swapping hints at inefficient garbage collections. But why is GC taking so much resources? Using GCViewer, I can see that the throughput can be as low as around 70%. And full GC time constantly reaches several minutes. (SliceHost has sent me a dozen heavy swap usage report already)

After some searching and study, first thing I tried was to decrease the maximum heap size. Yes, decrease it. Previously, I was assigning 384MB to the heap. Because while Tomcat is not running, I have a little less than 440MB free physical memory. Leaving some buffer, 384MB seems a reasonable number. But the excessive swapping and very long full GC time indicates that part of the heap must be slipping into the virtual memory. And virtual memory is the biggest enemy of JVM garbage collection. So I decreased the heap size incrementally, arriving at 270MB. And the GC log shows that the time full GC takes has considerably dropped.

To further improve the situation, I tried different GC policies. First I tried the Concurrent Mark Sweep GC policy, which is supposed to work very well with multi-processor servers and is optimized for response time. Profiling with the CMS options on my local workstation shows good results. And since “cat /proc/cpuinfo” shows that my VPS is equipped with 4 CPU’s, I was expecting to see obvious improvements.

However, to my great disappointment, CMS totally strangled my VPS. Soon after Tomcat starts up, CPU usage became constantly high and the Grails app responds even slower! I’m not exactly sure why, but it looks like the number of CPU’s shown at your VPS doesn’t mean it has the comparable concurrent processing power.

Then I gave up the CMS policy and tried the other GC policy suitable for servers, the Parallel policy. This turned out to work quite well on the VPS, together with “-XX:+UseParallelOldGC” which is available since Java 5 update 6 and enhanced in Java 6 which I’m running my app on.

The Results

I experimented with a few other JVM options, and finally achieved a throughput of above 98%. Full GC now usually takes around 1 second, occasionally maxing at over 10 seconds. I think there are some hard limitations to the server, but the results are already good enough for now. Here are the current ones which have achieved reasonable performance for my Grails app. These may not be the perfect setup since I haven’t tried the combinations exhaustively.

-server -Xmx270m -Xms270m -XX:MaxPermSize=80m -Xverify:none -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy -XX:SurvivorRatio=4 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -XX:+AggressiveOpts

References

Below are some useful articles I’ve come across while tuning the JVM.

Further thoughts

I really love Grails for what it is: remarkably agile development with real joy. But as the person running the app, I have to deal with various issues of the stack that Grails sits on, which sometimes frustrates me.
On one hand this robust stack really grants Grails an advantage in the enterprise market. But on the other hand, this is no good news for the creators of hundreds and thousands of small web apps, pet projects, interesting weekend hacks and alike. The most obvious obstacle is Java hosting. It’s 2008 already, and there are still simply _no_ easily affordable and good enough hosting services for the Java stack! The entry cost is too high. With innovative services like Heroku and Googel App Engine emerging, the gap is even increasing. The barrier to actually making something useful on the web is being dramatically lowered. But yet, the Java stack is left out in the cold.

While this is a problem, it’s also an incredible opportunity. With Grails emerging, the Java stereotype can be changed. People can build agile web apps on top of the proven stack, which is the core competency of Grails as I see it. I want to build things with Grails. But I don’t want to worry about how to host my app. Now, who’s gonna give us the ultimate service to grow little ideas into reality?

Feedlr新功能:预览消息样例

Tuesday, April 8th, 2008

在Feedlr建立一个新Feed的时候,现在可以直接预览在当前设置下播发到微博客帐号上的消息格式样例了!

image

在新建Feed向导的Feed信息设置页面上,如果在Feed地址里填上了正确的地址,点击“预览消息样例”按钮,就能看到以最新一条Feed内容为例子,机器人将会播发的消息格式。

如果没有正确的Feed地址,那么样例会用“标题”,“摘要”和“链接”来代表Feed的内容部分。在修改了Feed地址以及“更多选项”里面的消息前缀,播发标题、摘要、和链接的选项后,再点预览按钮就能更新消息格式。

消息预览是为了让用户更方便的理解并选择合适的选项,但并不一定100%和最终播发的消息完全一致。比如Feed条目的链接默认会转换成tinyurl以后再播发出去,但也会根据Bot选项来决定是否使用原来的完整地址。

希望这项小功能给各位带来一些实用的帮助。

Feedlr十八般用法之:消息前缀的妙用

Sunday, April 6th, 2008

不知道大家有没有注意到,在新建一个Feed广播的时候,可以在Feed信息的“更多选项”里填上给每条消息加上的前缀。

image

这个功能有什么用呢?最简单的用法,可以用博客的标题,Feed的内容关键字,等等作为前缀,这样关注者收到就知道消息是从哪里来,关于什么的了。但今天我想介绍的是几种更有趣的用法。

@通知某人

如果设定了前缀“@用户名”,那么发送的每条消息都能通过@功能让某人(用户名)收到。目前Twitter,叽歪,饭否都支持@功能。

有什么用呢?比如你向自己的微博客帐号发送消息,如果不加@前缀,那么新消息别人都能收到而你自己收不到。如果加上前缀“@你自己的用户名”,那么你和你的帐号的关注者都能收到新消息了。

另外,@功能可以让不关注这个帐号的人也能收到消息通知。

把消息做为私信发送给某人

想到了@的用法,可能你也就想到了d的用法。在Twitter和叽歪,支持用格式“d 用户名 消息内容”来直接发送私信给某人。如果给你的feed消息加上前缀“d 用户名”,那么每条feed消息都会直接做为私信发送给这个用户。

这样的话,你的feed机器人就成为某人(大多是你自己吧)的专用了,feed的消息不会被微博客上的其他人看到。

用前缀定义track关键字

Twitter和叽歪都支持关键字track功能,但是各自的使用方式有所不同。

在Twitter,用户可以通过GTalk或者手机发送“track 关键字”来自定义关键字跟踪。这样,只要有人在Twitter发表了包含关键字的消息,用户就能收到这条消息。

而在叽歪,如果一条消息带有“[关键字]”的内容,那么方括号里的关键字就自动成为一条线索。用户可以通过访问“http://jiwai.de/t/关键字”的地址来看到所有带有这个关键字的消息。在关键字页面上,用户可以订阅feed或者关注这个关键字。在IM和手机上,也可以发送“on [关键字]”来直接关注。

那么,如果你用feedlr广播到Twitter或者叽歪的话,你自然可以给你的feed加上相应的关键字前缀,就能保证关注这个关键字的用户都能收到feed的更新了,而不论用户是不是关注了你的机器人帐号。