Redis — an in-memory distributed key-value store. Spring Boot uses it for sessions, caching, and queues.
Simple analogy: Redis is like a shared fridge for all office employees. Everyone takes and puts food. Fast, accessible to all, but you need to share space. Or think of it as a whiteboard in a meeting room: anyone can write and read instantly, but the board is finite and everything disappears when the power goes out (data lives in memory only, unless you enable persistence).
Why it matters: When you run multiple instances of your app behind a load balancer, each instance needs access to the same session data. Storing sessions in-memory on one instance means user X hits server A, logs in, then gets routed to server B and is logged out. Redis solves this by providing a shared, fast data store that all instances read from. The same principle applies to caching — avoiding redundant database queries across all instances.
1. Redis for sessions:
1# application.yml2spring:3 session:4 store-type: redis5 timeout: 30m6 redis:7 flush-mode: on_save8 namespace: spring:session9 data:10 redis:11 host: localhost12 port: 637913 password: ${REDIS_PASSWORD}14 timeout: 2000ms
Now HTTP sessions are stored in Redis, and any server in the cluster can read them.
2. Redis as cache:
1@Configuration2@EnableCaching3public class RedisCacheConfig {4 @Bean5 public RedisCacheManager cacheManager(RedisConnectionFactory factory) {6 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()7 .entryTtl(Duration.ofMinutes(30))8 .serializeValuesWith(9 RedisSerializationContext.SerializationPair.fromSerializer(10 new GenericJackson2JsonRedisSerializer()11 )12 );1314 Map<String, RedisCacheConfiguration> cacheConfigs = Map.of(15 "users", config.entryTtl(Duration.ofHours(1)),16 "products", config.entryTtl(Duration.ofMinutes(10)),17 "sessions", config.entryTtl(Duration.ofMinutes(30))18 );1920 return RedisCacheManager.builder(factory)21 .cacheDefaults(config)22 .withInitialCacheConfigurations(cacheConfigs)23 .build();24 }25}2627@Cacheable(value = "users", key = "#id")28public User findById(Long id) { ... }2930@CacheEvict(value = "users", key = "#id")31public void deleteUser(Long id) { ... }
3. Redis for Rate Limiting:
1public boolean isAllowed(String userId, int maxRequests, Duration window) {2 String key = "rate:" + userId;3 Long count = redisTemplate.opsForValue().increment(key);4 if (count == 1) {5 redisTemplate.expire(key, window);6 }7 return count <= maxRequests;8}
4. Redis Pub/Sub:
1@Bean2public RedisMessageListenerContainer container(RedisConnectionFactory factory) {3 RedisMessageListenerContainer container = new RedisMessageListenerContainer();4 container.setConnectionFactory(factory);5 container.addMessageListener((message, pattern) -> {6 System.out.println("Received: " + new String(message.getBody()));7 }, new PatternTopic("events.*"));8 return container;9}
Production pitfalls:
@Cacheable with sync = true to prevent this.maxmemory-policy (e.g., allkeys-lru) to evict old keys when Redis runs out of memory.