Friday April 11, 2008
Jetty and Resin closing in on Tomcat's popularity From Greg Wilkin's Jetty Improves in Netcraft survey (again):
As with most open source projects, it's very hard to get a measure of who/how/where/why Jetty is being used a deployed. Downloads long ago became meaningless with the advent of many available bundling and distribution channels. The Netcraft Web Survey is one good measure, as it scans the internet and identifies which server sites run. In the results released April 2008, Jetty is identified for 278,501 public server, which is 80% of the market share of our closest "competitor" tomcat (identified as coyote in the survey). Jetty is currently 12th in the league table of identified servers of all types and will be top 10 in 6 months if the current trajectory continues.
If you look at the Netcraft numbers, you might also notice that Resin isn't far behind Jetty. If you look at the Indeed Job Trends graphs for the three, there seems to be some interesting information there too. The first graph is absolute and the second is relative.
If you're using Spring Dynamic Modules to deploy a web application, which server do you think is better? Both Tomcat 6 and Jetty 6 seem to work just fine in Equinox. Posted in Java at Apr 11 2008, 08:42:48 AM MDT 4 Comments
GlassFish 2 vs. Tomcat 6 In Switched, Dave says:
Now that Glassfish V2 is out I'm switching from Tomcat to Glassfish for all of my development. It's more than fast enough. With Glassfish on my MacBook Pro, Roller restart time is about 8 seconds compared to 16 with Tomcat. And the quality is high; the admin console, the asadmin command-line utility and the docs are all excellent. The dog food is surprisingly tasty ;-)
I did some brief and very non-scientific performance comparisons myself:
Startup Time with no applications deployed:
- Tomcat 6: 3 seconds
- GlassFish 2: 8 seconds
Startup Time with AppFuse 2.0 (Struts + Hibernate version) as a WAR
- Tomcat 6: 15 seconds
- GlassFish 2: 16 seconds
Environment:
- JAVA_OPTS="-Xms768M -Xmx768M -XX:PermSize=512m -XX:MaxPermSize=512m -Djava.awt.headless=true -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -XX:+UseConcMarkSweepGC -server"
- OS X 10.4.10, 2.2 GHz Intel Core 2 Duo, 4 GB 667 MHz DDR2 SDRAM
Since this was a very non-scientific experiment, it's possible the last two are actually the same. It's strange that Dave is seeing Roller startup twice as fast on GlassFish. Maybe they've done some Roller deployment optimization?
I realize startup times aren't that important. However, as Dave mentions, they (and context reloading) can be extremely important when developing.
Update: I got to thinking that Dave is probably referring to context reloading. Here's a comparison of how long it takes for both servers to pick up a new WAR (and start the application) when it's dropped into their autodeploy directories.
- Tomcat 6: 14-16 seconds
- GlassFish 2: 9 seconds
The strange thing about Tomcat is it takes 6-8 seconds to recognize a new WAR has been deployed. Does Tomcat have a polling increment that can be increased during development?
Regardless, it's impressive that the GlassFish guys have made things that much faster for developers. Nice work folks!
These days, I try to use mvn jetty:run on projects. Then I don't have to worry about deploying, just save and wait for the reload. Time to wait for AppFuse 2.0 to reload using the Maven Jetty Plugin (version 6.1.5)? 7 seconds. Of course, it'd be nice if I could somehow get this down to 1 or 2 seconds.
Maybe Dave should use the Maven integration for Roller to decrease his reload times. ;-) Posted in Java at Sep 19 2007, 04:55:31 PM MDT 15 Comments
Proposed Tomcat Enhancement: Add flag to escape JSP's EL by default I posted the following to the Tomcat Developers mailing list. Unfortunately, it didn't get any responses, which means (to me) that no one cares about this feature. I guess the good thing is they didn't veto it.
Hello all,
I'm working for a client that's using a proprietary Servlet/JSP-based framework that runs on Tomcat. They have their own custom JSP compiler and they're looking to move to a standard JSP compiler. One of the things their compiler supports is automatic escaping of XML in expressions. For example, ${foo} would be escaped so <body> -> <body>. JSP EL does not do this. It *doesn't* escape by default and instead requires you to wrap your expressions with <c:out/> if you want escaping.
I'd like to ask what developers think about adding a flag (similar to trimSpaces in conf/web.xml) that allows users to change the escaping behavior from false to true?
I think this is a good option to have as it allows security-conscious organizations to paranoid and escape all content by default.
Thanks,
Matt
Related: http://raibledesigns.com/rd/entry/java_web_frameworks_and_xss
What do you think? Is there anything wrong with adding this (optional) feature to Tomcat? Enhancing security is a good thing - right?
Update: I've entered an enhancement request for this feature and attached a patch. Posted in Java at Sep 19 2007, 04:29:11 PM MDT 7 Comments
Jetty 6.x versus Tomcat 6.x An AppFuse user asks:
Has anyone done any performance benchmarking between Jetty 6.x and Tomcat 6.x to see which one is better for production use in terms of scalability, performance and ease-of-use? I'm gearing towards Jetty 6.1 but want to hear other's opinions first.
I admit, I completely changed the wording in this quote to make it more readable.
Most of the companies I've worked with in recent years have been using Tomcat (very successfully) in production. However, I also know the Contegix and JavaLobby guys continue to swear by Resin for the most part. What's your opinion?
IMHO, I don't think it really matters - they're all good enough for production use. Posted in Java at Aug 15 2007, 09:50:17 AM MDT 6 Comments
Configuring Tomcat for Production From The Atlassian Developer Blog:
You appear to be running Tomcat in development mode.
(http://tomcat.apache.org/tomcat-5.5-doc/jasper-howto.html)
This means that source of every JSP is held in memory to provide
detailed messages in the event of an error. If you have large JSPs
this will hurt. It looks like this accounts for 50MB+
From Tomcat's Production Configuration documentation:
The main JSP optimization which can be done is precompilation of JSPs. However, this might not be possible (for example, when using the jsp-property-group feature) or practical, in which case the configuration of the Jasper servlet becomes critical.
When using Jasper 2 in a production Tomcat server you should consider making the following changes from the default configuration.
- development - To disable on access checks for JSP
pages compilation set this to
false. - genStringAsCharArray - To generate slightly more efficient
char arrays, set this to
true. - modificationTestInterval - If development has to be set to
truefor any reason (such as dynamic generation of JSPs), setting this to a high value will improve performance a lot. - trimSpaces - To remove useless bytes from the response,
set this to
true.
Seems like good information to know. Posted in Java at Apr 16 2007, 04:05:03 PM MDT 1 Comment
Mixing Apache HTTP Server, mod_rewrite and mod_jk I'm trying to configure Apache and Tomcat to work with a desired architecture for doing A/B Testing on my current project. Our basic idea is that we'll deploy entirely new WAR files when we have a test, then use the magic of Apache's mod_rewrite, mod_jk and possible the UrlRewriteFilter to keep the URLs somewhat consistent between version A and version B. Here's some questions I have for those folks who might've done this before:
- Is it possible to use Apache's mod_rewrite to map http://www.domain.com/?v=1 to http://www.domain.com/1 (this allows us to have two different applications/wars served up to the same domain).
- If #1 is possible, what's the RewriteRule for allowing the parameter to be anywhere in the query string, but still allowing the target to use it as the context name?
- Is it possible to use something in the WAR (likely the UrlRewriteFilter) to produce HTML that has rewritten links (i.e. http://www.domain.com/?id=1 in the WAR whose context is 1)?
In other words, can Apache forward to the correct app going in, and can that app rewrite its URLs so those same URLs are used when going out?
I believe this is all possible. However, I am having difficulty getting mod_jk to allow mod_rewrite to be processed first. If I have the following in httpd.conf, it seems like htdocs/.htaccess gets bypassed.
JkMount /* loadbalancer
Is it possible to configure Apache/mod_jk so WARs can hang off the root, but still use mod_rewrite? If not, the only solution I can think of is to use UrlRewriteFilter in the WAR to forward to another context when a "v" parameter is in the URL. Currently, the UrlRewriteFilter doesn't allow forwarding to another context. The good news is the Servlet API allows it. I got it working in Tomcat (with crossContext enabled) and wrote a patch for the UrlRewriteFilter.
Anyone out there have experience doing A/B Testing in a Java webapp? If so, did you try to disguise the URLs for the different versions?
Update:
I've got a bit of this working. The magic formula seems to be don't try to hang things off the root - use mod_rewrite to make things appear to hang off the root.
First of all, I posted a message similar to this post to the tomcat-user mailing list. Before I did so, I discovered mod_proxy_ajp, which happens to look like the successor to mod_jk. AFAICT, it doesn't allow fine-grained rules (i.e. only serve up *.jsp and *.do from Tomcat), so I'll stick with mod_jk for now.
Rather than proxying all root-level requests to Tomcat, I changed my JkMount to expect all Tomcat applications to have a common prefix. For example, "app".
JkMount /app* loadbalancer
This allows me to create RewriteRules in htdocs/.htaccess to detect the "v" parameter and forward to Tomcat.
RewriteEngine On
RewriteCond %{QUERY_STRING} ^v=(.*)$
RewriteRule ^(.*)$ /app%1/ [L]
This isn't that robust as adding another parameter causes the forward to fail. However, it does successfully forward http://localhost/?v=1 to /app1 on Tomcat and http://localhost/?v=2 to /app2 on Tomcat.
What about when ?v=3 is passed in? There's no /app3 installed on Tomcat, so Tomcat's ROOT application will be hit. Using the UrlRewriteFilter, I installed a root application (which we'll likely need anyway) with the following rule:
<rule>
<from>^/app(.*)$</from>
<to type="forward">/</to>
</rule>
So I've solved problem #1: Using URL parameters to serve up different web applications. To solve the second issue (webapps should rewrite their URLs to delete their context path), I found two solutions:
- Use mod_proxy_html. Sounds reasonable, but requires the use of mod_proxy.
- Use the UrlRewriteFilter and outbound-rules.
Since I'm using mod_jk, #2 is the reasonable choice. I added the following link in my /app1/index.jsp:
<a href="<c:url value="/products.jsp"/>">link to products</a>
By default, this gets written out as http://localhost/app1/products.jsp. To change it to http://localhost/products.jsp?v=1, I added the following to urlrewrite.xml:
<outbound-rule>
<from>^/app1/(.*)$</from>
<to>/$1?v=1</to>
</outbound-rule>
This produces the desired effect, except that when I click on the link, a new session is created every time. AFAICT, I probably need to do something with cookies so the jsessionid cookie is set for the proper path.
Not bad for a day's work. Only 2 questions remain:
- What's a more robust RewriteRule that doesn't care about other parameters being passed in?
- What do I need to do so new sessions aren't created when using an outbound-rule?
It's entirely possible that mod_proxy_ajp with mod_rewrite_html is best tool for this. Can mod_proxy handle wildcards like JkMount can? I've heard it's faster than mod_jk, so it probably warrants further investigation.
Update 2: I achieved the desired result using mod_rewrite, mod_jk and the UrlRewriteFilter (for outgoing links). Here's what I put in htdocs/.htaccess (on Apache):
RewriteEngine On
# http://domain/?v=1 --> http://domain/app1/?v=1
RewriteCond %{QUERY_STRING} v=([^&]+)
RewriteRule ^(.*)$ /app%1/$1 [L]
# http://domain --> http://domain/app (default ROOT in Tomcat)
RewriteRule ^$ /app/ [L]
And in the urlrewrite.xml of each webapp:
<outbound-rule>
<from>^/app([0-9])/([A-Za-z0-9]+)\.([A-Za-z0-9]+)$</from>
<to>/$2.$3?v=$1</to>
</outbound-rule>
<outbound-rule>
<from>^/app([0-9])/([A-Za-z0-9]+)\.([A-Za-z0-9]+)\?(.*)$</from>
<to>/$2.$3?$4&v=$1</to>
</outbound-rule>
Next I'll try to see if I can get it all working with mod_proxy_ajp and mod_proxy_html. Anyone know the equivalent of "JkMount /app*" when using LocationMatch with mod_proxy? Posted in Java at Apr 16 2007, 12:07:10 PM MDT 11 Comments
Upgrading to Tomcat 6
Erik did it, so I tried it as well. This site is now running Tomcat 6.0.10 and it has to be the least painful major Tomcat upgrade I've ever done. By major, I mean upgrading from one version number (5.5.17) to the next. Apparently, no XML files changed (like they did from 4.1.x -> 5.0.x -> 5.5.x) because I was able to copy over conf/server.xml and conf/Catalina/** without any issues. The only change I had to make was to copy commons-logging.jar from Roller's WEB-INF/lib to JSPWiki's.
I have seen a couple of the following errors in my log files since I upgraded, so if you see any strange behavior, please let me know.
2-Mar-2007 12:36:10 AM org.apache.tomcat.util.http.Parameters processParameters
WARNING: Parameters: Character decoding failed. Parameter skipped.
java.io.CharConversionException: EOF
at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:83)
at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:49)
at org.apache.tomcat.util.http.Parameters.urlDecode(Parameters.java:410)
at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:392)
at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:508)
at org.apache.tomcat.util.http.Parameters.handleQueryParameters(Parameters.java:266)
at org.apache.catalina.connector.Request.parseParameters(Request.java:2404)
at org.apache.catalina.connector.Request.getParameterValues(Request.java:1089)
at org.apache.catalina.connector.RequestFacade.getParameterValues(RequestFacade.java:396)
at javax.servlet.ServletRequestWrapper.getParameterValues(ServletRequestWrapper.java:189)
at org.acegisecurity.wrapper.SavedRequestAwareWrapper.getParameter(SavedRequestAwareWrapper.java:325)
at org.apache.roller.ui.rendering.velocity.deprecated.OldPageRequest.(OldPageRequest.java:164)
at org.apache.roller.ui.rendering.velocity.deprecated.RedirectServlet.figurePageRedirect(RedirectServlet.java:285)
at org.apache.roller.ui.rendering.velocity.deprecated.RedirectServlet.doGet(RedirectServlet.java:131)
I tested AppFuse 2.0 on Tomcat 6.0.10 earlier today and impressed that 1) Cargo worked perfectly and 2) most of the web frameworks worked. Which one didn't? You guessed it - good ol' JSF. That's OK though, the JSF version of AppFuse (MyFaces 1.1.5 with Facelets 1.1.11) doesn't work with Jetty 6.1.1 either. The good news is I found a workaround - removing the el-api dependency from my pom.xml makes it work on both.
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>1.2</version>
</dependency>
If I remove this dependency, everything works fine on Tomcat 6.0.10 and Jetty 6.1.1. Unfortunately, it seems this dependency is needed for Tomcat 5.x. Hopefully some fancy stuff with Maven profiles can fix this incompatibility. Posted in Java at Mar 02 2007, 12:44:46 AM MST 9 Comments
Search This Site
Recent Entries
- The 416
- LinkedIn Tech Talk: Kevin Brown on Shindig
- Happy Birthday to Me
- My iPhone Review
- Bus Project Update
- Raible Road Trip #12 Vacation Report
- Raible Road Trip #12
- Bike to Work Day
- LinkedIn has the Biggest Rails app in the World
- RE: Are people blogging less?