Skip to main content

Redis-based Session Sharing

Redis is an in-memory data store capable of handling hundreds of thousands of reads/writes per second. When all Tomcat instances share a single Redis as a common session store, any server can access the same session regardless of which server handled the original login.


Redis Session Architecture​

[Client]
β”‚
[Load Balancer]
β”œβ”€β”€ [App1: Tomcat] ─▢ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”œβ”€β”€ [App2: Tomcat] ─▢ β”‚ Redis β”‚
└── [App3: Tomcat] ─▢ β”‚ Session β”‚
β”‚ Store β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

All Tomcat instances save and retrieve sessions from the same Redis. No matter which server handles a request, it reads the same session from Redis.


Redis Installation and Configuration​

# Ubuntu
sudo apt-get install redis-server

# CentOS
sudo yum install redis

# Start
sudo systemctl enable --now redis

# Verify connection
redis-cli ping
# PONG

Optimized Redis Configuration for Sessions​

# /etc/redis/redis.conf

# Allow external connections (if needed)
bind 0.0.0.0

# Set password (required)
requirepass your-strong-password-here

# Auto-clean sessions when memory is full
maxmemory 2gb
maxmemory-policy allkeys-lru

# Disable persistence (not needed for session-only use)
save ""
appendonly no

Option 1: Tomcat Redis Session Manager​

Replaces Tomcat's default session manager with a Redis-backed one.

Add Dependencies​

# Copy JARs to Tomcat lib folder
wget https://github.com/jcoleman/tomcat-redis-session-manager/releases/download/2.0.0/tomcat-redis-session-manager-2.0.0.jar
cp tomcat-redis-session-manager-2.0.0.jar /opt/tomcat/lib/

wget https://repo1.maven.org/maven2/redis/clients/jedis/4.4.3/jedis-4.4.3.jar
cp jedis-4.4.3.jar /opt/tomcat/lib/

wget https://repo1.maven.org/maven2/org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1.jar
cp commons-pool2-2.11.1.jar /opt/tomcat/lib/

context.xml Configuration​

<!-- /opt/tomcat/conf/context.xml -->
<Context>

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve"/>

<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="10.0.0.10"
port="6379"
password="your-strong-password-here"
database="0"
maxInactiveInterval="1800"
sessionPersistPolicies="SAVE_ON_CHANGE"
/>
</Context>

The easiest and most reliable approach for Spring Boot applications. One annotation switches the session store to Redis.

Dependencies (build.gradle)​

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.session:spring-session-data-redis'
}

application.yml​

spring:
data:
redis:
host: 10.0.0.10
port: 6379
password: your-strong-password-here
timeout: 2000ms
lettuce:
pool:
max-active: 10
max-idle: 5
min-idle: 1
max-wait: 1000ms

session:
store-type: redis
timeout: 30m
redis:
namespace: myapp
flush-mode: on-save

SessionConfig.java​

@Configuration
@EnableRedisHttpSession(
maxInactiveIntervalInSeconds = 1800,
redisNamespace = "myapp:session"
)
public class SessionConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory connectionFactory) {

RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);

template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());

GenericJackson2JsonRedisSerializer jsonSerializer =
new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);

template.afterPropertiesSet();
return template;
}
}

Controller Example​

@RestController
public class AuthController {

@PostMapping("/login")
public ResponseEntity<String> login(
@RequestBody LoginRequest request,
HttpSession session) {

User user = authService.authenticate(request.getUsername(), request.getPassword());

// Stored in session β†’ automatically saved to Redis
session.setAttribute("userId", user.getId());
session.setAttribute("username", user.getUsername());
session.setAttribute("role", user.getRole());
session.setMaxInactiveInterval(1800);

return ResponseEntity.ok("Login successful");
}

@GetMapping("/profile")
public ResponseEntity<UserProfile> getProfile(HttpSession session) {
Long userId = (Long) session.getAttribute("userId");

if (userId == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

// Same session retrieved from Redis regardless of which server handles this
UserProfile profile = userService.findById(userId);
return ResponseEntity.ok(profile);
}

@PostMapping("/logout")
public ResponseEntity<Void> logout(HttpSession session) {
session.invalidate(); // Deletes session from Redis
return ResponseEntity.ok().build();
}
}

Inspecting Redis Session Data​

# List session keys in Redis
redis-cli -h 10.0.0.10 -a your-password KEYS "myapp:session*"

# View session contents
redis-cli -h 10.0.0.10 -a your-password HGETALL "myapp:session:sessions:1a2b3c4d"

# Check session TTL (seconds remaining until expiry)
redis-cli -h 10.0.0.10 -a your-password TTL "myapp:session:sessions:1a2b3c4d"

# Force-delete a specific session (admin action)
redis-cli -h 10.0.0.10 -a your-password DEL "myapp:session:sessions:1a2b3c4d"

Redis High Availability: Sentinel and Cluster​

Redis Sentinel (Automatic Failover)​

# application.yml
spring:
data:
redis:
sentinel:
master: mymaster
nodes:
- 10.0.0.10:26379
- 10.0.0.11:26379
- 10.0.0.12:26379
password: sentinel-password
password: redis-password

Redis Cluster (Horizontal Scaling)​

spring:
data:
redis:
cluster:
nodes:
- 10.0.0.10:7001
- 10.0.0.10:7002
- 10.0.0.11:7003
- 10.0.0.11:7004
- 10.0.0.12:7005
- 10.0.0.12:7006
max-redirects: 3
password: redis-cluster-password

Performance Comparison: Session Strategies​

Local session (single server)  : ~0.1ms  (direct memory access)
Tomcat clustering : ~1~5ms (includes network replication)
Redis session (local) : ~0.5ms (Redis loopback)
Redis session (remote) : ~1~2ms (one network round trip)
Redis Cluster : ~2~5ms (includes cluster routing)

The additional latency from Redis session lookups β€” typically 1~2ms β€” is negligible compared to business logic processing time (tens to hundreds of milliseconds).

The next page covers session serialization principles and performance optimization.