This is an article of mine first published on Wazi
The mod_jk connector serves as the glue between the Apache HTTP server and a Java application server such as Tomcat or JBoss. While most adminstrators concentrate on optimizing Apache or the Java server, setting up mod_jk optimally can also improve your users’ experience.
To be precise, mod_jk connects the Apache web server to the AJP port of a Java server. Apache Jserv Protocol is a binary version of HTTP that is optimized for communication over TCP between the Apache HTTP server and Apache Tomcat or other software.
Mod_jk is available for many Linux distributions, so you can install it with your package manager, or if you prefer you can download it from the offical site, where new versions are released as source and binary packages. The file mod_jk.so is the Apache HTTP server module that you install with your release of Apache. Once that’s done, you need to configure mod_jk in your httpd.conf file so that you can use it. Edit the file, and add the directive to load mod_jk:
LoadModule jk_module path/to/mod_jk.so
Next, set the path to the workers.properties configuration file, where you can define more options for mod_jk. It should be in the same directory as httpd.conf:
Mod_jk uses shared memory to store configuration and runtime information for load balancer workers and their members. It specifies that all Apache children
- share the same status information for load balancing members (OK, ERROR, etc.)
- share information about load taken by the individual workers
- share information about the parts of the configuration that are changeable during runtime.
The next directive tells Apache where to put mod_jk logs. This path should point to the same logs directory as the HTTPD access_log:
Set the mod_jk log level to debug, error, or info:
Set the timestamp log format:
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
The next directive maps a worker to a namespace or URL. Workers represent Tomcat instances that are listening for requests. With the directive below, we say that any request that comes to the URL http://mysite.com/tomcat/ must be redirected via mod_jk to worker1, which we’ll configure in a moment. Multiple JkMount attributes can be used simultaneously for the same worker or multiple workers:
JkMount /tomcat/* worker1
To define the Tomcat workers you specified in the httpd.conf file, create the file /path/to/httpd/conf/workers.properties. In a simple configuration example, we can set the environment for mod_jk and define the list of workers; this list has just one worker, named “worker1”:
workers.tomcat_home=/tomcat workers.java_home=$JAVA_HOME ps=/ worker.list=worker1
Now we define the parameters of the Tomcat AJP host and port:
worker.worker1.port=8009 worker.worker1.host=192.168.1.1 worker.worker1.type=ajp13
We could also try a slightly more complex example that uses one Apache HTTP server to load-balance the requests for three Tomcat instances. We have to change the httpd.conf file to tell with the JkMount directive to use a special worker, which we’ll call “ldbalance”:
JkMount /tomcat/* ldbalance
The file /path/to/httpd/conf/workers.properties should then contain these directives:
workers.tomcat_home=/tomcat workers.java_home=$JAVA_HOME ps=/ worker.list=worker1,worker2,worker3
When we define each worker, we add the directive
lbfactor, which specifies the “weight” of this worker when balancing – that is, how much we expect this worker to take on, or the worker’s work quota relative to other load balancer workers. If one worker has an lbfactor five times higher than another, for example, it will receive five times more requests.
worker.worker1.port=8009 worker.worker1.host=192.168.1.1 worker.worker1.type=ajp13 worker.worker1.lbfactor=1 worker.worker2.port=8009 worker.worker2.host=192.168.1.2 worker.worker2.type=ajp13 worker.worker2.lbfactor=1 worker.worker3.port=8009 worker.worker3.host=192.168.1.3 worker.worker3.type=ajp13 worker.worker3.lbfactor=1
We also need to define a special load-balancer worker with type “lb,” and specify our three workers as its balanced workers. The “sticky” setting specifies whether requests with SESSION IDs should be routed back to the same Tomcat worker; if
sticky_session is set to True or 1, sessions are sticky. You should set
sticky_session to False when Tomcat is using a session manager that can persist session data across multiple instances of Tomcat, such as Memcached, Terracotta, or the one embedded.
worker.ldbalance.type=lb worker.ldbalance.balanced_workers=worker1,worker2,worker3 worker.ldbalance.sticky_session=1
So far everything we’ve seen is pretty standard configuration. Now let’s take a look at some of the less frequently used mod_jk configuration parameters.
You can use connection directives with any worker to ensure that the communication is working between mod_jk and a remote Tomcat instance. Start with the time in seconds that mod_jk will wait for an answer from Tomcat:
If set to zero, which is the default, mod_jk will wait for an infinite amount of time on all socket operations. This is not a good idea, because when you have a problem on one of your back end workers, you’ll have a lot of Apache connections starting to hang while waiting for an answer, which could eat all the available connections. Set this value to 30 seconds, or less if you know that your Tomcat answers quickly.
This is a timeout, in milliseconds, for connections to be established. The default is the socket_timeout value multiplied by 1,000. If the remote host does not respond to the first connection inside the timeout specified, mod_jk will generate an error and retry. Socket_connect_timeout works on most platforms, even if socket_timeout is not supported by the operating system. You should use socket_connect_timeout, because in some network failure situations failure detection during connection establishment can take several minutes due to TCP retransmits. Depending on the quality of your network, a timeout somewhere between 1000 and 5000 milliseconds should be fine.
This worker property determines under which conditions established connections are probed to make sure they are still working. Mod_jk probes with an empty AJP13 packet (called CPing) and expects to receive an appropriate answer (CPong) within some timeout. ping_mode can be set to a combination of characters to decide in which situations test packets are used:
- C: connect mode, timeout set with ping_timeout (see below) overwritten by connect_timeout
- P: prepost mode, timeout set with ping_timeout overwritten by prepost_timeout
- I: interval mode, timeout set with ping_timeout, idle time connection_ping_interval
- A: all modes
The suggested setup is to use A (all modes) and set a ping_timeout:
This property sets the timeout in milliseconds used when waiting for the CPong answer of a CPing connection probe. The default is 10000, or 10 seconds. In general that’s good enough, but you can lower the value if you know that your back end should answer faster than 10 seconds. Please note that if you enable ping_mode you must pay attention also to the other timeout parameters in the list above that could influence this directive. My suggestion is to use only ping_timeout if possible.
These configuration parameters set reasonable limits for the connections mod_jk makes. You should also set ping_mode to a value equal to what you set in the server.xml file’s connection timeout directive for your Tomcat (or equivalent directive for other server) so that you have no half connection hanging around on one end. Even if a connection issue happens, if you’ve set properties like
ping_mode=A, the bad connection will be detected and closed.
Back-end Health Directives
These directives define how mod_jk knows whether the back-end server is alive or dead and how to handle this.
Set this property to the value of an HTTP status code that will cause a worker to fail if returned from a Servlet container. This tells mod_jk to declare a back end dead when a specific HTTP status code is returned. Starting with mod_jk 1.2.25 you can also tell the load balancer to not put a member into an error state even if a response returned by one of the status codes in fail_on_status usually would put the member in this state. Do this by putting a minus sign in front of those status codes:
worker.xxx.fail_on_status=-404,-500,503With that directive I’ve removed as error state codes 404 and 500, while 503 still puts the back end in error state.
As further example, I use
worker.xxx.fail_on_status=302,404,500,503 because in my environment those codes mean that an automatic undeploy/deploy has failed and so no page is found (404 code), and I want to put the back end in error state when this happens.
The recover time is the time in seconds the load balancer will not try to use a worker after it went into an error state. After this time has passed a worker in error state is marked recovering, and will be tried for new requests. The default is 60, so if your back end worker has an error, it will take 60 seconds before that worker receives a new request. I usually set this threshold lower, to 30 seconds, so a recovered back end can come back online sooner. This can be important for big websites where it is normal to have some failing pages and you don’t want to put the back end offline for too much time.
That’s a look at some of the less common properties you can use to optimize mod_jk. I’ve made some suggestions for appropriate values, but good and bad limits depend on your applications. For example, for your site it could be normal to see a 404 error, and you don’t want to set as “broken” a back end that gives that answer. But as long as you know these property exist, you can use them to fine-tune the communication between your web server and your Java server.