Rate this page del.icio.us  Digg slashdot StumbleUpon

LAMP and Java EE in Harmony

by the editorial team

This tip article has been edited and republished from the original source.

by Michael Juntao Yuan

LAMP and Java EE are two important middleware stacks for developing web applications. LAMP stands for Linux, Apache, MySQL, and PHP. They are all open source software included in Red Hat Enterprise Linux system. Java EE stands for Java Enterprise Edition. Red Hat chooses the open source JBoss Application Server (JBoss AS), which is an implementation of Java EE, as its official middleware stack.

The Apache and PHP parts of the LAMP stack compete with Java EE / JBoss AS. They both provide the presentation, business logic, and data access layers of the web application. Traditionally, LAMP is used in small web applications that have relatively simple logic and require fast development turnaround time; Java EE / JBoss AS is used in enterprise applications that require scalability, high level of data integrity, and maintainability over long term. But for many development teams, there is strong desire to use Apache / PHP together with Java EE for the following reasons.

  • As a native application, the Apache web server is a more efficient HTTP server than the Java-based web server included in JBoss AS. That is especially true for static contents (e.g., pictures), keep-alive requests, and HTTPS requests. It would be ideal to have JBoss AS serve up dynamic, database-related content, while having Apache serve static content in the same application.
  • Apache has a rich set of modules for almost every aspects of a web application, including security, logging, URL rewriting, performance enhancement, etc. JBoss AS is rich in supporting business and transactional logic, but has fewer features when it comes to manipulating HTTP request / response directly.
  • PHP is a very popular scripting language for web applications. A large number of open source PHP libraries and applications have been built and are widely used. It would be great if we could leverage them in Java EE enterprise applications.
  • Aside from PHP, Apache also supports other scripting languages for web applications; including Perl, Python, and others.

The best way to leverage Apache / PHP in Java EE is to setup an Apache server in front of JBoss AS. The Apache server handles all web requests, manages access security and logging, serves static content, and runs PHP / Perl / Python scripts. It forwards complex enterprise tasks to a JBoss AS instance, which could run on the same server as Apache or on a different server on the network.

The HTTP request’s URL indicates whether this request should be forwarded to JBoss AS. For instance, you could require that all requests with the /javaee/* URL be handled by JBoss AS. It does not matter whether the /javaee/* URL is loaded directly by a user, submitted as an action URL for a form, or included as part of a PHP page — it is processed by JBoss AS, and the response is passed back to the user via Apache. Figure 1 shows the above described architecture.

Figure 1: Fronting JBoss AS
with Apache web server

Fronting JBoss AS with Apache has other benefits as well. First, you can place the Apache server outside of the firewall, and JBoss AS, which opens many ports for internal services, inside the firewall for better security. Second, for large Java EE applications that need to scale beyond a single server, Apache can act as a load balancer in front of a cluster of JBoss AS nodes. In this article, I will discuss how to use Apache together with JBoss AS, how to setup the load balancer, and how to improve the performance of the entire stack.

Basic Setup

JBoss AS is shipped with the necessary connectors to communicate with Apache. But for Apache to understand how to talk with JBoss AS, you have to install an Apache module called mod_jk. You can download mod_jk from the Apache Tomcat Connectors project. Make sure that you download mod_jk 1.2 (do NOT use mod_jk2, as it is no long being actively developed).

You can download the mod_jk source and compile it by yourself. Or you can download the pre-compiled mod_jk.so library file for your hardware and operating system. Drop mod_jk.so into Apache’s modules directory (or libexec directory on some systems), and then add the following line to your conf/httpd.conf file.

# Include mod_jk configuration file
Include conf/mod_jk.conf

The mod_jk.conf file configures mod_jk. Here is an example.

# Load mod_jk module
# Specify the filename of the mod_jk lib
LoadModule jk_module modules/mod_jk.so

# Where to find workers.properties
JkWorkersFile conf/workers.properties

# Where to put jk logs and shared memory
JkLogFile logs/mod_jk.log
JkShmFile logs/jk.shm

# Set the jk log level [debug/error/info]
JkLogLevel info

# Select the log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

# JkOptions indicates to send SSK KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories

# JkRequestLogFormat
JkRequestLogFormat "%w %V %T"

# Mount your applications
JkMount /javaee/* jboss
JkMount /jmx-console jboss
JkMount /jmx-console/* jboss
JkMount /web-console jboss
JkMount /web-console/* jboss

# Add jkstatus for managing runtime data
<Location /jkstatus/>
  JkMount status
  Order deny,allow
  Deny from all
  Allow from 127.0.0.1
</Location>
	

The JkMount directive is especially important as it specifies the URL pattern for request that needs to be forwarded to JBoss AS. In the above example, the /javaee/*, /jmx-console/*, as well as /web-console/* URLs are forward to the JBoss AS instance named jboss. You can have multiple JBoss AS instances mapped to different URL patterns. All the JBoss AS instances are defined in the conf/workers.properties file. Here is an example of the workers.properties file.

# Define list of workers that will be used
# for mapping requests
worker.list=jboss,status

# Define instance "jboss"
worker.jboss.port=8009
worker.jboss.host=127.0.0.1
worker.jboss.type=ajp13

# Status worker for managing load balancer
worker.status.type=status

The above workers.properties file defines a single JBoss AS instance running on localhost and listens for Apache mod_jk requests at port 8009.

Now, start Apache and JBoss AS. Load URL http://localhost/ in your browser, and you should see the Apache root page; load http://localhost/jmx-console/ and you should see the JBoss JMX management console.

Configure load balancer

As I mentioned earlier, you can setup multiple JBoss AS instances for the same Apache server, and Apache can forward request to different JBoss AS instances based on the URL pattern specified in JkMount. Or, it could act as a load balancer and forward requests alternatively to JBoss AS instances. In fact, load balancer is one of the most common use cases for Apache + mod_jk. It allows us to setup a JBoss cluster with completely free and open source software.

To use the load balancer, just map the JBoss application URL pattern to the loadbalancer worker node in the mod_jk.conf file.

# Mount your applications
JkMount /javaee/* loadbalancer
JkMount /jmx-console loadbalancer
JkMount /jmx-console/* loadbalancer
JkMount /web-console loadbalancer
JkMount /web-console/* loadbalancer

Then, in the workers.properties file, you can define JBoss AS nodes to be load balanced as well as the load balancing policies.

# Define list of workers that will be used
# for mapping requests
# The configuration directives are valid
# for the mod_jk version 1.2.18
#
worker.list=loadbalancer,status

# Define Node1
# modify the host as your host IP or DNS name.
worker.node1.port=8009
worker.node1.host=node1.mydomain.com
worker.node1.type=ajp13
worker.node1.lbfactor=1

# Define Node2
# modify the host as your host IP or DNS name.
worker.node2.port=8009
worker.node2.host= node2.mydomain.com
worker.node2.type=ajp13
worker.node2.lbfactor=1

# Load-balancing behaviour
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node1,node2

# Status worker for managing load balancer
worker.status.type=status

The above load balancer balances incoming requests evenly between JBoss AS node1 and node2. By default, the load balancer keeps track of user sessions and always forwards the requests in the same session to the same JBoss AS node. This way, each JBoss AS node can manage its own HTTP session states independent of others. But in order for session identification to be properly tagged to each JBoss instance, we need to name each JBoss node according to the names specified in workers.properties.

Edit the $JBOSS_HOME/server/default/deploy/jbossweb-tomcat50.sar/server.xml file and add a jvmRoute attribute to the <Engine> element.

<Engine name="jboss.web"
        defaultHost="localhost"
        jvmRoute="node1">
  ... ...
</Engine>

The jvmRoute attribute must match the name specified for this JBoss AS instance in the workers.properties file. Next, edit the $JBOSS_HOME/server/default/deploy/jbossweb-tomcat50.sar/META-INF/jboss-service.xml file, and set the UserJK attribute to true.

<attribute name="UseJK">true</attribute>

Now, the load balancer is properly configured and the application is balanced between node1 and node2.

Optimize thread configuration

For the optimal performance, make sure that Apache and JBoss AS have matching thread pools (i.e., number of concurrent users). The mod_jk connector achieves good performance by maintaining persistent connections between Apache and JBoss AS instances. If Apache accepts more concurrent users than its backend JBoss AS nodes are configured to accept, Apache would get connection errors when it forwards requests and the users would see errors; if Apache accepts much less concurrent users than JBoss AS can handle, the entire system would support smaller number of concurrent users than it is physically capable of, and the server resources on the JBoss AS nodes would be insufficiently utilized.

Ideally, the Apache MaxClients parameter (specified in the httpd.conf file) should be the sum of the maxThreads parameter (specified in the $JBOSS_HOME/server/default/deploy/jbossweb-tomcat50.sar/META-INF/jboss-service.xml file, see below) in JBoss AS.

<!-- A AJP 1.3 Connector on port 8009 -->
<Connector port="8009"
           address="${jboss.bind.address}"
           maxThreads="250"
           emptySessionPath="true"
           enableLookups="false"
           redirectPort="8443"
           protocol="AJP/1.3"/>

The above works when we have a single node of JBoss AS. It is slightly more complex when you use Apache and mod_jk to load balance a cluster of JBoss AS nodes. In that case, you have take into account errors the load balancer might make when it keeps track of the number concurrent threads to JBoss AS nodes. In most cases, the rule of thumb is to set the Apache maxClients value at 80% of the sum of the JBoss AS maxThreads values.

The future

Fronting JBoss AS with Apache and mod_jk allows us to take advantage of both Java EE and LAMP. But there is still plenty of room for improvement. If we could “embed” Apache into JBoss AS, we would be able to take advantage of the performance enhancements without going through the “middleman” mod_jk. If we could run PHP scripts inside the JVM, we would be able to access Java objects from PHP – and vice versa – in the same application. The JBoss Web Server project aims to do just those things.

JBoss Web Server leverages the Apache Portable Runtime to build a native HTTP module to work with the JBoss Java-based runtime. It has performance comparable to the native Apache. It also supports popular Apache modules such as the URL re-writing. Furthermore, JBoss Web Server can run PHP scripts through a special Java servlet. The PHP script has access to Java objects in the rest of the system.

I strongly recommend you to check out JBoss Web Server if your are interested in an integrated stack of both LAMP and Java EE.

More resources

About the author

Michael Yuan is the author of four books and a technical evangelist with JBoss. His upcoming book “JBoss Seam: Power and Simplicity Beyond Java EE 5.0″ is the first book on JBoss’s next generation lightweight application framework. Michael has a PhD from the University of Texas at Austin.

Copyright (C) by 2006 Red Hat Inc. This article is licensed under a Creative Commons Attribution 2.5 License (CC BY-SA): http://creativecommons.org/licenses/by-sa/2.5/.

Leave a reply