Re: Mapping REST requests across multiple app contexts
Charles Caldarale recommended UrlRewriteFilter and after experimenting with it, I agree it's very nice: great performance, very flexible and handles cross-context forwarding. The custom Valve option is still attractive because it has slightly better performance, slightly better cross-context support, and much simpler configuration--at the expense of generality of course. Can someone look at the following Valve logic and let me know if this is safe on Tomcat 6? It has been working fine and is stable under load, but I'm totally new to the Tomcat code base and would really appreciate another pair of eyes. Thanks. public class MapRESTRequest extends ValveBase { public void invoke(Request request, Response response) { if (/v1.equals(request.getContextPath())) { // map the in-bound REST URI to the app handling it String newRequestURI = /new-app/some/derived/uri; org.apache.coyote.Request req = request.getCoyoteRequest(); req.requestURI().setString(newRequestURI); req.decodedURI().setString(newRequestURI); MessageBytes uriMB = MessageBytes.newInstance(); uriMB.duplicate(req.decodedURI()); MessageBytes hostMB = MessageBytes.newInstance(); hostMB.setString(request.getHost().getName()); MappingData mappingData = request.getMappingData(); mappingData.recycle(); request.getConnector().getMapper().map(hostMB, uriMB, mappingData); request.setContext((Context) mappingData.context); request.setWrapper((Wrapper) mappingData.wrapper); } getNext().invoke(request, response); } If anyone is interested in this, I can share the source. What I have allows you to implement a REST resource name space as a collection of web apps (I mainly use Jersey for the apps). The public URLs are mapped onto the web apps however you want by configuring each app's web.xml. Here's a web.xml fragment that shows the configuration (this servlet is only used for Valve configuration; it doesn't handle any requests itself): servlet servlet-classcom.vulpes.tomcat.MapResources/servlet-class load-on-startup2/load-on-startup init-param param-nameresourcePaths/param-name param-value/game/**;/profile/*/tokens;/profile/*/awards/param-value /init-param /servlet That mapping accepts request URLs like /v1/foo/bar/game/123 and forwards them to /a-service/game/123. Collisions between resources are resolved with deepest-match wins (individual path elements are resolved with longest-match wins). A trie is used for the mapping, so it is reasonably fast for large numbers of patterns. - Ken On Sat, Aug 21, 2010 at 2:04 PM, Ken Fox k...@vulpes.com wrote: I'm looking for advice on the best way to map REST requests onto a collection of Tomcat apps all running in the same JVM. The REST name space was designed for client use and doesn't reflect how the apps implement it. For example, the resource /v1/x/123 is implemented by app X, but the resource /v1/x/123/y is implemented by app Y. A proxy (e.g. Apache mod_proxy or Squid) in front of Tomcat can rewrite the URLs to go to the correct app, but this gives us some pretty ugly proxy configurations which have to be kept in lock-step with the Tomcat apps. Relying on a proxy also makes it a bit harder to use Amazon's load balancer because it doesn't do rewrites (I think we'd have to run a proxy on each Tomcat instance). I'm trying to implement the rewrite as a Valve (code outline below) registered with the Engine which will run before any Hosts or Contexts. This seems like a good approach and may even let me grab the JAX-RS annotations from the apps to dynamically build the rewrite rules. Does anyone have advice for REST name spaces in Tomcat in general? Has anyone had good experiences with a rewrite proxy in front of Tomcat on Amazon EC2 with Amazon's ELB? Has anybody tried a rewrite Valve similar to this? It has to modify the CoyoteRequest and generate new Request.mappingData which seems kind of risky. (Though I think it will work in Tomcat 7, I've only tried Tomcat 6.) This is my favorite approach so far. Thanks, - Ken public void invoke(Request request, Response response) { if (/v1.equals(request.getContextPath())) { // map the in-bound REST URI to the app handling it String newRequestURI = /new-app/some/derived/uri; org.apache.coyote.Request req = request.getCoyoteRequest(); req.requestURI().setString(newRequestURI); req.decodedURI().setString(newRequestURI); MessageBytes uriMB = MessageBytes.newInstance(); uriMB.duplicate(req.decodedURI()); MessageBytes hostMB = MessageBytes.newInstance(); hostMB.setString(request.getHost().getName()); MappingData mappingData = request.getMappingData(); mappingData.recycle(); request.getConnector().getMapper().map(hostMB, uriMB, mappingData
Re: Mapping REST requests across multiple app contexts
chuck.caldar...@unisys.com wrote: If you place the standard rewrite filter in the ROOT context, you can catch any requests that do not directly map to the appropriate webapp and forward or redirect them appropriately. I looked at UrlRewriteFilter and it seemed designed for forwarding within a context, not between contexts. Can it forward from ROOT to a context loaded by a Host finding the app in its appBase? I don't have Context declarations for my apps and I'd really like to maintain isolation between them. The advantage of doing context mapping in a Valve is that the context switch can happen very early in the request and before any host-specific code runs. I'm not concerned about portability--this is a very small amount of code and it's fine to rewrite it entirely if I switch containers. - Ken
Re: How stable is Tomcat?
My company has run Tomcat apps on Amazon's EC2 that have exceeded 1,500 hits per *second*. We use Amazon's load balancer in front of a variable number of Tomcat instances (each on their own EC2 instance). For 1,500 hits per day you probably only need one small EC2 instance running a single Tomcat. We had some database scaling problems due to a misunderstanding of how Amazon throttling works--at about 3,000 hits per second the traffic we were sending to SimpleDB caused Amazon to fail every request. Tomcat continued to run very well at that load. We do not have a web tier in front of Tomcat, but we do use Akamai for caching (as a vanilla CDN). Given your low traffic numbers, you probably don't need a web tier or a CDN in front of Tomcat. You can get by even without a load balancer, but I'd recommend using one to give yourself more options for rolling code and adding capacity. - Ken On Sat, Aug 21, 2010 at 8:59 AM, Yawar Khan khanya...@yahoo.com wrote: Guys, is tomcat stable enough to host large scale production applications getting 1500+ hits everyday? and as much concurrent database connections. I know alot depends on the applications architecture but just how good is tomcat?
Mapping REST requests across multiple app contexts
I'm looking for advice on the best way to map REST requests onto a collection of Tomcat apps all running in the same JVM. The REST name space was designed for client use and doesn't reflect how the apps implement it. For example, the resource /v1/x/123 is implemented by app X, but the resource /v1/x/123/y is implemented by app Y. A proxy (e.g. Apache mod_proxy or Squid) in front of Tomcat can rewrite the URLs to go to the correct app, but this gives us some pretty ugly proxy configurations which have to be kept in lock-step with the Tomcat apps. Relying on a proxy also makes it a bit harder to use Amazon's load balancer because it doesn't do rewrites (I think we'd have to run a proxy on each Tomcat instance). I'm trying to implement the rewrite as a Valve (code outline below) registered with the Engine which will run before any Hosts or Contexts. This seems like a good approach and may even let me grab the JAX-RS annotations from the apps to dynamically build the rewrite rules. Does anyone have advice for REST name spaces in Tomcat in general? Has anyone had good experiences with a rewrite proxy in front of Tomcat on Amazon EC2 with Amazon's ELB? Has anybody tried a rewrite Valve similar to this? It has to modify the CoyoteRequest and generate new Request.mappingData which seems kind of risky. (Though I think it will work in Tomcat 7, I've only tried Tomcat 6.) This is my favorite approach so far. Thanks, - Ken public void invoke(Request request, Response response) { if (/v1.equals(request.getContextPath())) { // map the in-bound REST URI to the app handling it String newRequestURI = /new-app/some/derived/uri; org.apache.coyote.Request req = request.getCoyoteRequest(); req.requestURI().setString(newRequestURI); req.decodedURI().setString(newRequestURI); MessageBytes uriMB = MessageBytes.newInstance(); uriMB.duplicate(req.decodedURI()); MessageBytes hostMB = MessageBytes.newInstance(); hostMB.setString(request.getHost().getName()); MappingData mappingData = request.getMappingData(); mappingData.recycle(); request.getConnector().getMapper().map(hostMB, uriMB, mappingData); request.setContext((Context) mappingData.context); request.setWrapper((Wrapper) mappingData.wrapper); } getNext().invoke(request, response); }
Re: How stable is Tomcat?
On Sat, Aug 21, 2010 at 2:42 PM, Pid * p...@pidster.com wrote: We don't usually count web traffic in hits any more, because a single page could easily cause 100 hits. I think hits to your app servers is still an appropriate way to think about your server load. If a page view generates 100 hits to your Tomcat instances, your CDN is probably busted. Marketing and ad revenue talk a lot about page views, but that's a useless stat for sizing your Tomcat servers. Don't give in to the dark side. ;) On a related topic, anybody have trouble scaling Comet-based sites with Tomcat? It seems like ad revenue could be at least as big a hurdle as server scaling. - Ken - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org