Oracle WebLogic Session Replication: Cluster-Aware Session Management Without Load Balancer Dependency

WebLogic's built-in session replication gives you high availability session management at the application tier — no Redis, no sticky sessions, no load balancer dependency.

Oracle WebLogic Session Replication: Cluster-Aware Session Management Without Load Balancer Dependency

The previous two posts in this series covered Nginx Plus sticky sessions and Redis-based session externalisation. Both solve the session affinity problem at different layers. This post covers a third approach — one that lives entirely within the WebLogic cluster itself.

WebLogic’s in-memory session replication means sessions are automatically copied to a secondary Managed Server in the cluster. If the primary server fails, the secondary takes over immediately — with the full session intact. No Redis cluster. No Nginx sticky routing. No user interruption.

Done correctly, it is one of the most elegant session HA solutions available on the Java EE stack.


How WebLogic Session Replication Works

WebLogic uses a primary/secondary replication model. When a session is created on a Managed Server, WebLogic designates:

  • A primary server — where the session is actively used and stored in JVM heap
  • A secondary server — a different Managed Server in the cluster that holds a replicated backup copy

Every time a session is modified and the request completes, WebLogic replicates the delta to the secondary server. The secondary holds a shadow copy in its own heap — ready to take over instantly if the primary fails.

Client Request
      │
      ▼
[Load Balancer — any routing algorithm]
      │
      ▼
[ManagedServer1 — Primary for this session]
  Session: { userId: 42, cart: [...] }  ← Active
      │
      │ Replication (end of request)
      ▼
[ManagedServer2 — Secondary for this session]
  Session: { userId: 42, cart: [...] }  ← Shadow copy

When ManagedServer1 goes down, the load balancer routes the next request to any available server. ManagedServer2 recognises it holds the secondary for this session ID, promotes itself to primary, and serves the request without loss. The user never knew anything happened.

No sticky routing required. No external store required.


Session Replication Modes in WebLogic

WebLogic supports several persistence store types. Choose based on your consistency vs performance requirements:

ModeDescriptionUse Case
replicatedSynchronous in-memory replication to secondaryProduction clusters, strong consistency
replicated_if_clusteredReplication when clustered, memory-only when notDev/prod parity without config change
async-replicatedAsynchronous replication — faster writes, slight inconsistency windowHigh-throughput, tolerable brief inconsistency
async-replicated-if-clusteredAsync version of the aboveSame as above with dev/prod parity
jdbcPersisted to a databaseCross-datacenter HA, long-lived sessions
memoryNo replication (default)Single server or stateless apps

For most production WebLogic clusters, replicated_if_clustered is the right default. It gives you full synchronous replication in production and works without replication in standalone/development mode without a config change.


Requirements: Making Your Application Cluster-Aware

This is where most WebLogic session replication implementations fail. The cluster and WebLogic configuration can be perfect — but if the application isn’t cluster-aware, sessions will not replicate correctly, and you’ll see inconsistent state or silent data loss after failover.

There are four hard requirements.

1. The <distributable/> Tag in web.xml

This is the signal to the container that the application is designed for distributed deployment. Without it, WebLogic will not replicate sessions regardless of what you configure in weblogic.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
         https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <!-- This tag is mandatory for session replication -->
    <distributable/>

    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>

</web-app>

Missing this tag is the single most common reason WebLogic session replication “doesn’t work.”

2. All Session Attributes Must Implement java.io.Serializable

For WebLogic to replicate a session to the secondary server, it must serialise every object stored in the session and transmit it over the network. Any session attribute that does not implement Serializable will either cause a replication failure silently or throw a runtime exception depending on your WebLogic version.

// WRONG — will break replication
public class UserContext {
    private Connection dbConnection; // Not serializable — never store this
    private HttpServletRequest request; // Not serializable
}

// CORRECT — all fields serializable
public class UserContext implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long userId;
    private String username;
    private List<String> roles;
    private Map<String, Object> preferences;

    // getters/setters
}

Audit every object you put in HttpSession. If it holds a database connection, a thread, a file handle, or any non-serializable reference — it cannot go in the session when replication is enabled.

3. Always Call setAttribute() Again After Mutating Session Objects

This is the subtle one that catches experienced developers. WebLogic tracks session modifications by watching setAttribute() calls. If you retrieve a mutable object from the session, modify it in place, and never call setAttribute() again, WebLogic does not know the session changed — and the replication to the secondary never happens.

// WRONG — mutation without re-setAttribute
// The secondary server never sees this change
HttpSession session = request.getSession();
List<CartItem> cart = (List<CartItem>) session.getAttribute("cart");
cart.add(newItem); // Direct mutation
// No setAttribute call — replication misses this update

// CORRECT — always re-setAttribute after mutation
HttpSession session = request.getSession();
List<CartItem> cart = (List<CartItem>) session.getAttribute("cart");
cart.add(newItem);
session.setAttribute("cart", cart); // Triggers replication delta

This is particularly important for collections, maps, and custom objects. The rule is simple: if you changed it, set it back.

4. No Server-Affine Resources in Session

Sessions replicated to a secondary server will be picked up by that server on failover. If your session holds any resource that is tied to the original server — an open JMS session, a stateful EJB reference specific to a JVM, a cached local file path — those resources will be unavailable or invalid on the secondary. Design sessions to hold data only, not server-specific resource handles.


The Configuration: XML Files

weblogic.xml — Session Descriptor

This is the primary configuration file for session replication. It lives in WEB-INF/weblogic.xml of your WAR.

WebLogic supports two syntax styles for the session descriptor. The <session-param> style is the older format commonly found in WebLogic 10.x and 11g deployments — it uses explicit <param-name> / <param-value> pairs and is still fully supported in WebLogic 12c and 14c:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app
    xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
    http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">

    <session-descriptor>

        <!-- session-param style: compatible with WebLogic 10.x / 11g / 12c / 14c -->

        <session-param>
            <param-name>PersistentStoreType</param-name>
            <param-value>replicated</param-value>
        </session-param>

        <session-param>
            <param-name>TimeoutSecs</param-name>
            <param-value>3600</param-value>
        </session-param>

        <session-param>
            <param-name>InvalidationIntervalSecs</param-name>
            <param-value>60</param-value>
        </session-param>

        <session-param>
            <param-name>CookieName</param-name>
            <param-value>JSESSIONID</param-value>
        </session-param>

        <session-param>
            <param-name>CookiePath</param-name>
            <param-value>/</param-value>
        </session-param>

        <session-param>
            <param-name>CookieSecure</param-name>
            <param-value>true</param-value>
        </session-param>

        <session-param>
            <param-name>CookieHttpOnly</param-name>
            <param-value>true</param-value>
        </session-param>

        <session-param>
            <param-name>URLRewritingEnabled</param-name>
            <param-value>false</param-value>
        </session-param>

        <session-param>
            <param-name>MaxInMemorySessions</param-name>
            <param-value>10000</param-value>
        </session-param>

    </session-descriptor>

</weblogic-web-app>

Note: PersistentStoreType accepts replicated, replicated_if_clustered, async-replicated, async-replicated-if-clustered, jdbc, file, or memory. Using replicated (without the _if_clustered suffix) enforces replication unconditionally — WebLogic will throw a deployment error if the server is not part of a cluster, which makes misconfiguration visible early rather than silently falling back to in-memory behaviour.

WebLogic 14.1.1 compatibility note: The <session-param> style is fully valid in WLS 14.1.1. Oracle has maintained this syntax across all major versions for backward compatibility. The correct schema version for 14.1.1 is 1.9 — which is what the xsi:schemaLocation above references. No changes needed.

WLS 14.1.1 ships with Java EE 8 support using the standard javax namespace. The weblogic.xml namespace and <session-param> / <session-descriptor> structure are completely unaffected — identical across WLS 12c, 12.2.1.x, and 14.1.1. Your web.xml should use the Java EE 8 (javax) declaration:

<!-- web.xml — Java EE 8 / WLS 14.1.1 with javax namespace -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- Required for session replication -->
    <distributable/>

    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>

</web-app>

The modern element-based syntax (WebLogic 12c+) achieves the same result with cleaner XML:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app
    xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
    http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">

    <session-descriptor>

        <!-- Use in-memory replication when deployed to a cluster -->
        <persistent-store-type>replicated_if_clustered</persistent-store-type>

        <!-- Session timeout in seconds (60 minutes) -->
        <timeout-secs>3600</timeout-secs>

        <!-- How often WebLogic checks for and invalidates expired sessions -->
        <invalidation-interval-secs>60</invalidation-interval-secs>

        <!-- Session cookie configuration -->
        <cookie-name>JSESSIONID</cookie-name>
        <cookie-path>/</cookie-path>
        <cookie-domain>.yourdomain.com</cookie-domain>
        <cookie-secure>true</cookie-secure>
        <cookie-http-only>true</cookie-http-only>

        <!-- Disable URL rewriting — forces cookie-only session tracking -->
        <url-rewriting-enabled>false</url-rewriting-enabled>

        <!-- Allow session sharing across web apps in the same EAR -->
        <sharing-enabled>false</sharing-enabled>

        <!-- Maximum sessions in memory per server before oldest are invalidated -->
        <max-in-memory-sessions>10000</max-in-memory-sessions>

    </session-descriptor>

</weblogic-web-app>

weblogic-application.xml — EAR-Level Session Sharing

If you have multiple web applications in an EAR that need to share the same session (common in large WebLogic deployments), configure session sharing at the EAR level in META-INF/weblogic-application.xml:

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application
    xmlns="http://xmlns.oracle.com/weblogic/weblogic-application"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-application
    http://xmlns.oracle.com/weblogic/weblogic-application/1.8/weblogic-application.xsd">

    <!-- Enable session sharing across web modules in this EAR -->
    <session-descriptor>
        <persistent-store-type>replicated_if_clustered</persistent-store-type>
        <sharing-enabled>true</sharing-enabled>
        <timeout-secs>3600</timeout-secs>
        <cookie-name>JSESSIONID</cookie-name>
        <cookie-domain>.yourdomain.com</cookie-domain>
        <cookie-secure>true</cookie-secure>
        <cookie-http-only>true</cookie-http-only>
    </session-descriptor>

</weblogic-application>

Domain config.xml — Cluster and Replication Group Configuration

The cluster is configured in the WebLogic domain’s config.xml. The replication group settings control which server becomes the secondary for each primary — typically you want the secondary on a different physical host or rack for genuine HA.

<!-- Cluster definition -->
<cluster>
    <name>AppCluster</name>

    <!-- Unicast preferred over multicast for modern datacentres -->
    <cluster-messaging-mode>unicast</cluster-messaging-mode>

    <!-- Address used for cluster communication -->
    <cluster-address>ms1.internal,ms2.internal,ms3.internal,ms4.internal</cluster-address>

    <!-- Channel used for session replication traffic -->
    <cluster-broadcast-channel>ReplicationChannel</cluster-broadcast-channel>

    <!-- Replication type: man = in-memory -->
    <session-flush-interval>-1</session-flush-interval>
    <session-flush-threshold>-1</session-flush-threshold>
</cluster>

<!-- Managed Server 1 — Rack A -->
<server>
    <name>ManagedServer1</name>
    <listen-address>ms1.internal</listen-address>
    <listen-port>7001</listen-port>
    <cluster>AppCluster</cluster>

    <!-- This server belongs to replication group RackA -->
    <replication-group>RackA</replication-group>

    <!-- Secondary copies for this server's sessions go to RackB -->
    <preferred-secondary-group>RackB</preferred-secondary-group>
</server>

<!-- Managed Server 2 — Rack A -->
<server>
    <name>ManagedServer2</name>
    <listen-address>ms2.internal</listen-address>
    <listen-port>7001</listen-port>
    <cluster>AppCluster</cluster>
    <replication-group>RackA</replication-group>
    <preferred-secondary-group>RackB</preferred-secondary-group>
</server>

<!-- Managed Server 3 — Rack B -->
<server>
    <name>ManagedServer3</name>
    <listen-address>ms3.internal</listen-address>
    <listen-port>7001</listen-port>
    <cluster>AppCluster</cluster>
    <replication-group>RackB</replication-group>
    <preferred-secondary-group>RackA</preferred-secondary-group>
</server>

<!-- Managed Server 4 — Rack B -->
<server>
    <name>ManagedServer4</name>
    <listen-address>ms4.internal</listen-address>
    <listen-port>7001</listen-port>
    <cluster>AppCluster</cluster>
    <replication-group>RackB</replication-group>
    <preferred-secondary-group>RackA</preferred-secondary-group>
</server>

The replication group configuration ensures that if ManagedServer1 (Rack A) holds the primary for a session, the secondary is assigned to Rack B. A rack-level failure only affects the primary — the secondary survives and promotes immediately.


What This Means for the Load Balancer

With WebLogic in-memory replication properly configured, your load balancer can run a pure round-robin or least-connections policy with no session affinity at all. The application tier handles session continuity entirely.

upstream weblogic_cluster {
    least_conn;
    server ms1.internal:7001;
    server ms2.internal:7001;
    server ms3.internal:7001;
    server ms4.internal:7001;
    # No sticky directive needed
}

If you are running Nginx Plus with active health checks, you still want that — proactive upstream health detection is always better than passive. But the session affinity constraint is gone.


The Trade-off: Network Overhead and GC Pressure

In-memory replication is not free. For every request that modifies session state, WebLogic serialises the session delta and sends it to the secondary over the cluster network. The costs:

Serialisation overhead. Large sessions with complex object graphs are expensive to serialise on every request. Keep sessions lean — user identity, roles, lightweight state. Push large data (product catalogues, report results) to a cache or database, not the session.

GC pressure. Sessions live in JVM heap on both primary and secondary. At high concurrency with large sessions, this is a meaningful heap consumer. Monitor old-gen usage closely. With max-in-memory-sessions set in weblogic.xml, WebLogic will invalidate the oldest sessions when the limit is hit — tune this to match your heap allocation.

Network bandwidth. At 50,000 concurrent sessions of 10KB each, a full replication sweep is 500MB in-flight. Use async replication if you can tolerate a small inconsistency window, or invest in your cluster network bandwidth.


Comparison: The Three Session HA Approaches

WebLogic ReplicationRedis Session StoreNginx Plus Sticky
Where state livesJVM heap (primary + secondary)External Redis clusterJVM heap (primary only)
Failover behaviourAutomatic, full session preservedAutomatic, full session preservedSession lost if primary dies
Load balancer dependencyNoneNoneSticky routing required
Application changes neededSerializable, setAttribute disciplineSpring Session dependencyNone
Operational complexityWebLogic cluster configRedis cluster + monitoringNginx Plus config
Best fitWebLogic-native, no new infrastructurePolyglot, stateless backendsLegacy apps, short-term fix

The Bottom Line

WebLogic session replication is the right answer when you want genuine session HA without introducing external infrastructure. It lives entirely within the application tier, requires no changes to your load balancer, and provides automatic failover with zero session loss — provided your application is correctly cluster-aware.

The requirements aren’t complex: <distributable/> in web.xml, serializable session attributes, disciplined use of setAttribute(), and proper replication group configuration in config.xml. Get those four things right, and the load balancer becomes a pure traffic distributor — routing requests to any available server, without caring which server owns which session.


Prasad Gujar is a Platform Engineer specialising in Middleware, Kubernetes, and enterprise infrastructure. Views are his own.

Subscribe
Notify of
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments