Mastering Distributed Caching with Redis: Strategies, Types, and Pitfalls
Redis serves as a powerful in‑memory key‑value store for distributed caching, offering various data structures, persistence options, deployment modes, eviction policies, and update strategies, while addressing consistency challenges, cache miss scenarios, and failure modes such as penetration, breakdown, and avalanche.
Distributed Cache with Redis
Cache is a key weapon for improving service performance, especially under high concurrency and request volume. Relying solely on relational databases quickly creates bottlenecks, so both local and distributed caches are used. Local caches (e.g., Guava, Caffeine) store data in a single server’s memory but cannot be shared across processes and lack persistence. Distributed caches (e.g., Redis, Couchbase) centralize data, allow sharing, provide replication, and support persistence, though they add operational cost and potential consistency issues.
Redis Overview
Redis is an open‑source, in‑memory key‑value database known for rich data types, high‑performance I/O, command serialization, and persistence mechanisms, making it ideal for distributed caching.
String : basic string type, suitable for session IDs, global IDs, etc.
Hash : similar to Java HashMap; stores configuration data.
List : implemented with ziplist or linkedlist; often used as a message queue.
Set : implemented with intset or hashtable; stores unique elements.
Sorted Set : implemented with ziplist or skiplist; used for ranking (e.g., product sales, hot searches).
Bitmap : bit‑level storage, similar to Bloom filter.
HyperLogLog : cardinality estimation.
Geo : stores geographic location data.
Redis provides two persistence mechanisms: RDB (snapshot) and AOF (append‑only file). RDB restores faster but may lose recent data; AOF retains more recent commands. Newer versions support a hybrid approach.
Redis Deployment Modes
Common modes include master‑slave, Sentinel for high availability, and cluster (sharding) with 16384 slots for horizontal scaling.
Spring Boot Integration
public class RedisCacheConfiguration {
/** 配置Redis连接工厂 */
@Bean
public JedisConnectionFactory getJedisConnectionFactory(RedisConfigProperties redisConfigProperties) {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(redisConfigProperties.getHost(),
redisConfigProperties.getPort());
redisStandaloneConfiguration.setPassword(redisConfigProperties.getPassword());
redisStandaloneConfiguration.setDatabase(redisConfigProperties.getDatabase());
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
jedisConnectionFactory.getPoolConfig().setMaxTotal(50);
jedisConnectionFactory.getPoolConfig().setMaxIdle(50);
jedisConnectionFactory.getPoolConfig().setMaxWaitMillis(redisConfigProperties.getTimeout());
} catch (RedisConnectionFailureException e) {
e.getMessage();
}
return jedisConnectionFactory;
}
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}Distributed Cache Update Strategies
When data changes, the cache must be synchronized. Common strategies include:
Cache‑aside: read from cache first; on miss, fetch from DB and populate cache; on write, update DB then delete cache.
Read/Write‑through: cache proxy handles read/write logic.
Write‑behind: update cache first, then asynchronously persist to DB.
To mitigate consistency issues, use distributed locks, delayed double‑delete, or asynchronous delete via message queues.
Distributed Cache Failure Issues
Cache failures can cause three major problems:
Cache Penetration : requests miss both cache and DB; mitigated by caching null values or using Bloom filters.
Cache Breakdown : a hot key expires, causing a surge of DB requests; mitigated by disabling expiration for hot keys, rate limiting, or locking.
Cache Avalanche : many keys expire simultaneously, overwhelming the DB; mitigated by high‑availability configurations, sharding, and request throttling.
When strong consistency is required, distributed caching may be unsuitable; otherwise, preload hot keys based on usage statistics.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
