Tomcat Virtual Host Configuration, JVM Memory Management, and Memcached Session Clustering

To implement multiple virtual machines in Tomcat, follow these steps:

  1. Modify the configuration file
[root@server conf]# pwd
/usr/local/tomcat/conf
[root@server conf]# vim server.xml

Add the following configuration within the section:

<host appbase="/data/webapps1/" autodeploy="true" name="webapp1.example.com" unpackwars="true">
    <valve classname="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="webapp1_access_log" suffix=".txt"></valve>
</host>
<host appbase="/data/webapps2/" autodeploy="true" name="webapp2.example.com" unpackwars="true">
    <valve classname="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="webapp2_access_log" suffix=".txt"></valve>
</host>

  1. Prepare the web application data
[root@server conf]# mkdir -pv /data/webapps{1,2}/ROOT
[root@server conf]# vim /data/webapps1/ROOT/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>


    <meta charset="utf-8"></meta>
    <title>JSP Example</title>


    The following content is dynamically generated by the server
    <br></br>
    <%=request.getRequestURL()%>



[root@server conf]# vim /data/webapps2/ROOT/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>


    <meta charset="utf-8"></meta>
    <title>JSP Example</title>


    The following content is dynamically generated by the server
    <br></br>
    <%=request.getRequestURL()%>



  1. Set proper permissions
[root@server conf]# chown -R tomcat.tomcat /data/webapps{1,2}/

  1. Test the configuration
[root@client ~]# vim /etc/hosts
10.0.0.159 webapp1.example.com webapp2.example.com
[root@client ~]# curl http://webapp1.example.com:8080/
[root@client ~]# curl http://webapp2.example.com:8080/

Customizing Tomcat Access Logs and Reverse Proxy Configuration

  1. Customizing Access Log Format

To customize the access log format in Tomcat, modify the AccessLogValve configuration:

<valve classname="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log" suffix=".txt"></valve>

The pattern parameter defines the format of the log entries. Common placeholders include:

  • %h - Remote host address
  • %l - Remote logical username (always '-')
  • %u - Remote user if authenticated
  • %t - Date and time of the request
  • %r - First line of the request
  • %s - HTTP status code
  • %b - Size of response in bytes
  1. Setting Up Reverse Proxy

To configure Nginx as a reverse proxy for Tomcat:

# Install Nginx from your repository
# yum install nginx -y
# vim /etc/nginx/nginx.conf

# Configure reverse proxy for all requests
location / {
    proxy_pass http://backend-server1.example.com:8080;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

# Test configuration and restart
nginx -t
systemctl restart nginx

Important: The proxy_pass directive determines which backend server receives the requests. If you need to route based on the original request, ensure the Host header is properly forwarded using proxy_set_header.

Implementing Tomcat Cluster with Memcached Session Manager

Environment Preparation

  • Ensure time synchronization is properly configured (NTP or Chrony)
  • Configure firewall rules appropriately
IP Address Hostname Role Services
10.0.0.156 proxy.example.com Nginx, Apache HTTPD
10.0.0.157 tomcat1.example.com Application Server 1 JDK8, Tomcat8
10.0.0.158 tomcat2.example.com Application Server 2 JDK8, Tomcat8
  1. Configure Load Balancer on Proxy Server

Using Apache HTTPD as a load balancer:

[root@proxy ~]# vim /etc/httpd/conf.d/tomcat.conf
<Proxy balancer://tomcat-cluster>
    BalancerMember http://tomcat1.example.com:8080 loadfactor=1
    BalancerMember http://tomcat2.example.com:8080 loadfactor=1
</Proxy>
<VirtualHost *:80>
    ServerName       proxy.example.com
    ProxyRequests     Off
    ProxyVia         On
    ProxyPreserveHost On  
    ProxyPass       / balancer://tomcat-cluster/
    ProxyPassReverse / balancer://tomcat-cluster/
</VirtualHost>
[root@proxy ~]# systemctl restart httpd

  1. Configure Tomcat Servers for Clustering

2.1 Configure First Tomcat Server

[root@tomcat1 ~]# vim /usr/local/tomcat/conf/server.xml
<Host name="tomcat1.example.com" appBase="/data/webapps" autoDeploy="true">
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
              address="10.0.0.157"
              port="4000"
              autoBind="100"
              selectorTimeout="5000"
              maxThreads="6"/>
</Host>
[root@tomcat1 ~]# systemctl restart tomcat.service

2.2 Configure Second Tomcat Server

[root@tomcat2 ~]# vim /usr/local/tomcat/conf/server.xml
<Host name="tomcat2.example.com" appBase="/data/webapps" autoDeploy="true">
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
              address="10.0.0.158"
              port="4000"
              autoBind="100"
              selectorTimeout="5000"
              maxThreads="6"/>
</Host>
[root@tomcat2 ~]# systemctl restart tomcat.service

2.3 Configure Web Applications for Clustering

On both Tomcat servers, modify the web.xml file to make the application distributable:

[root@tomcat1 ~]# mkdir -p /data/webapps/ROOT/WEB-INF/
[root@tomcat1 ~]# cp -a /usr/local/tomcat/webapps/ROOT/WEB-INF/* /data/webapps/ROOT/WEB-INF/
[root@tomcat1 ~]# vim /data/webapps/ROOT/WEB-INF/web.xml
<web-app>
    ...
    <description>Sample web application</description>
    <distributable/>
</web-app>
[root@tomcat1 ~]# chown -R tomcat.tomcat /data/webapps/
[root@tomcat1 ~]# systemctl restart tomcat.service

[root@tomcat2 ~]# mkdir -p /data/webapps/ROOT/WEB-INF/
[root@tomcat2 ~]# cp -a /usr/local/tomcat/webapps/ROOT/WEB-INF/* /data/webapps/ROOT/WEB-INF/
[root@tomcat2 ~]# vim /data/webapps/ROOT/WEB-INF/web.xml
<web-app>
    ...
    <description>Sample web application</description>
    <distributable/>
</web-app>
[root@tomcat2 ~]# chown -R tomcat.tomcat /data/webapps/
[root@tomcat2 ~]# systemctl restart tomcat.service

JVM Garbage Collection Algorithms and Memory Generations

  1. Mark-Sweep Algorithm

This algorithm consists of two phases: marking and sweeping.

  • Marking phase: Identifies all accessible objects and marks them.
  • Sweeping phase: Removes all unmarked objects (garbage) from memory.

Characteristics:

  • Advantage: Simple algorithm implementation
  • Disadvantage: Creates memory fragments, though it doesn't waste memory space
  • Efficiency: Can be affected when there are many objects to remove
  1. Mark-Compact Algorithm

This algorithm also has two phases: marking and compacting.

  • Marking phase: Identifies and marks all accessible objects.
  • Compacting phase: Moves objects to one end of memory and compacts them.

Characteristics:

  • Advantage: Eliminates memory fragmentation by creating contiguous blocks of free memory
  • Disadvantage: The compacting process consumes additional CPU resources
  • Efficiency: Lower than mark-sweep due to the overhead of moving objects
  1. Copying Algorithm

This algorithm divides memory into two equal-sized spaces (A and B). Only one space is used at a time.

  • When space A is filled, live objects are copied to space B, and space A is cleared.
  • The roles of A and B are then swapped for the next cycle.

Characteristics:

  • Advantage: No memory fragmentation, efficient garbage collection regardless of object count
  • Disadvantage: Wastes 50% of memory capacity as only half is available for use
  1. Heap Memory Generations

The Java heap is divided into three generations:

  • Young Generation: Where new objects are allocated
  • Old Generation: Where long-lived objects reside
  • Metaspace: Stores class metadata (replaced PermGen in Java 8+)

Young Generation Structure

  • Eden Space: Where all new objects are initial created
  • Survivor Spaces (S0 and S1): Two spaces of equal size where objects survive after garbage collection

Minor GC (Young Generation Collection)

  1. When Eden space is full, a Minor GC is triggered.
  2. Live objects in Eden are copied to one Survivor space (S0 or S1).
  3. Eden is then cleared.
  4. When Eden fills again, another Minor GC copies live objects from both Eden and the active Survivor space to the other Survivor space.
  5. The process repeats, with objects being copied between Survivor spaces as they survive multiple collections.

Major GC (Old Generation Collection)

  • Occurs less frequently than Minor GC as objects in the Old Generation have longer lifespans.
  • Typically uses Mark-Compact algorithm due to the higher number of surviving objects.
  • When the Old Generation fills up, it triggers a Major GC (also known as Full GC).
  • A Major GC often includes a Minor GC first for better efficiency.

Memcached Usage, Installation, and MSM Principles

  1. Common Memcached Command Options

-u username    # Run memcached as the specified user (must be non-privileged)
-p port         # Network port to listen on (default: 11211)
-m num          # Maximum memory size in MB (default: 64)
-c num          # Maximum simultaneous connections (default: 1024)
-d              # Run as a daemon
-f factor       # Memory allocation growth factor (default: 1.25)
-v              # Verbose output
-vv             # Even more verbose output
-M              # Return error when memory is exhausted instead of LRU eviction
-U UDP_port     # UDP port number (0 to disable UDP)

  1. Basic Memcached Commands

Connect to memcached using telnet:

[root@server ~]# telnet localhost 11211

# Add a key-value pair
add mykey 1 60 4
test
STORED

# Retrieve a value
get mykey
VALUE mykey 1 4
test
END

# Update a value
set mykey 1 60 5
test1
STORED
get mykey
VALUE mykey 1 5
test1
END

# Delete a key
delete mykey
DELETED
get mykey
END

# Flush all data
flush_all
OK
quit

  1. Compiling and Installing Memcached

[root@server ~]# apt update && apt install gcc make libevent-dev -y
[root@server ~]# tar xf memcached-1.6.20.tar.gz 
[root@server ~]# cd memcached-1.6.20/
[root@server ~]# ./configure --prefix=/usr/local/memcached
[root@server ~]# make && make install
[root@server ~]# ln -s /usr/local/memcached/bin/memcached /usr/local/bin
[root@server ~]# useradd -r -s /sbin/nologin memcached
[root@server ~]# memcached -u memcached -d -f 2 -vv

Verify the installation:

[root@server ~]# ss -ntl | grep 11211
LISTEN 0      1024            127.0.0.1:11211      0.0.0.0:*
LISTEN 0      1024                 [::]:11211         [::]:*

  1. MSM (Memcached Session Manager) Principles

MSM is a component that enables Tomcat to store session data in memcached or Redis, providing:

  • Session replication across multiple Tomcat instances
  • High availability by preventing session loss if a server fails
  • Scalability by allowing horizontal scaling of application servers

MSM works by intercepting session operations and storing them in the memcached cluster instead of memory. When a request arrives at any Tomcat instance, the session is retrieved from memcached if it's not already in local memory.

To configure MSM in Tomcat:

  1. Add the MSM library to Tomcat's lib directory
  2. Configure the MSM parameters in context.xml
  3. Ensure the web application is marked as distributable in web.xml

Tags: Tomcat JVM garbage collection Memcached Clustering

Posted on Sat, 17 Oct 2026 16:25:17 +0000 by uniboy86