Distributed Session, Transaction, and Lock Strategies in Java Applications

This article explains how to manage sessions, implement distributed transactions, and coordinate distributed locks in Java-based distributed systems, covering practical solutions with Tomcat‑Redis, Spring Session, CAP theory, XA, TCC, message‑based consistency, Redis locks, RedLock, and Zookeeper locks, complete with configuration and code examples.

Architect
Architect
Architect
Distributed Session, Transaction, and Lock Strategies in Java Applications

The article introduces techniques for handling session management, distributed transactions, and distributed locking in Java applications running in a distributed environment.

1. Distributed Session

It explains the basics of HTTP session using jsessionid cookie and the challenges when scaling to multiple servers.

Three solutions are presented:

Use JWT tokens to store user identity and retrieve other data from a database or cache.

Tomcat + Redis: keep the original servlet code and store session data in Redis via Tomcat RedisSessionManager. Example configuration:

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
         host="{redis.host}" port="{redis.port}" database="{redis.dbnum}" maxInactiveInterval="60"/>

Spring Session + Redis: decouple the web container from session storage. Maven dependency:

<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
  <version>1.2.1.RELEASE</version>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.8.1</version>
</dependency>

Spring bean configuration:

<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
  <property name="maxInactiveIntervalInSeconds" value="600"/>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
  <property name="maxTotal" value="100"/>
  <property name="maxIdle" value="10"/>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
  <property name="hostName" value="${redis_hostname}"/>
  <property name="port" value="${redis_port}"/>
  <property name="password" value="${redis_pwd}"/>
  <property name="timeout" value="3000"/>
  <property name="usePool" value="true"/>
  <property name="poolConfig" ref="jedisPoolConfig"/>
</bean>

Controller example using the native session API:

@RestController
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/putIntoSession")
    public String putIntoSession(HttpServletRequest request, String username) {
        request.getSession().setAttribute("name", "leo");
        return "ok";
    }
    @RequestMapping("/getFromSession")
    public String getFromSession(HttpServletRequest request, Model model){
        String name = request.getSession().getAttribute("name");
        return name;
    }
}

2. Distributed Transaction

The article discusses why traditional ACID transactions do not scale across sharded databases and introduces the CAP theorem (Consistency, Availability, Partition tolerance) as a guiding principle.

It then outlines five common approaches:

XA (two‑phase commit) – coordinated by a transaction manager; suitable for monolithic apps but inefficient for high‑concurrency microservices.

TCC (Try‑Confirm‑Cancel) – explicit try, confirm, and cancel phases; often used in financial scenarios where strict consistency is required.

Local message table – insert a message record in the same transaction and later deliver it via MQ, ensuring eventual consistency.

Reliable message with eventual consistency – use MQ transactional messages (e.g., RocketMQ) to guarantee that a prepared message is either committed or rolled back based on the local transaction outcome.

Max‑effort notification – after a local transaction, send a message to a dedicated service that retries calling the downstream service until success.

Practical advice is given on when to choose TCC (strict monetary operations) versus reliable message approaches (e.g., order‑stock updates).

3. Distributed Lock

Two implementations are compared:

Redis Distributed Lock

Basic lock using the SET command with NX and PX options:

SET my:lock <span>random-value</span> NX PX 30000

Release via a Lua script that deletes the key only if the stored value matches:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

Notes on the need for random values and the limitations of a single‑instance Redis.

RedLock Algorithm

Describes the steps for acquiring a lock across a Redis cluster of five masters, requiring a majority (3) of nodes to grant the lock and handling timeout calculations.

Zookeeper Distributed Lock

Uses temporary znodes: a client creates an EPHEMERAL node to acquire the lock; others watch the predecessor node and wait for its deletion.

Java implementation example:

public class ZooKeeperSession {
    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
    private ZooKeeper zookeeper;
    // ... constructor establishes connection ...
    public Boolean acquireDistributedLock(Long productId) {
        String path = "/product-lock-" + productId;
        try {
            zookeeper.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            return true;
        } catch (Exception e) {
            // watch predecessor and retry
        }
        return true;
    }
    public void releaseDistributedLock(Long productId) {
        String path = "/product-lock-" + productId;
        zookeeper.delete(path, -1);
    }
    // watcher and singleton helpers omitted for brevity
}

The article concludes that Redis locks require active polling, while Zookeeper locks rely on watches, making Zookeeper generally more reliable when a client crashes because the EPHEMERAL node disappears automatically.

Overall, the piece provides a practical guide for Java architects to choose appropriate session storage, transaction coordination, and locking mechanisms in distributed systems.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaredisZooKeeperSession Management
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.