在分布式系统中,Session共享是一个经典难题。传统方案如Session复制或粘性Session都存在明显缺陷,而Redis的String类型为解决这一问题提供了优雅方案。
核心实现步骤:
java复制// 存储Session
public void setSession(String sessionId, User user, int expireSeconds) {
String key = "session:" + sessionId;
String value = JSON.toJSONString(user);
redisTemplate.opsForValue().set(key, value, expireSeconds, TimeUnit.SECONDS);
}
// 获取Session
public User getSession(String sessionId) {
String key = "session:" + sessionId;
String value = redisTemplate.opsForValue().get(key);
return StringUtils.isEmpty(value) ? null : JSON.parseObject(value, User.class);
}
关键设计考量:
性能优化技巧:
实际案例:某电商平台采用此方案后,Session相关性能提升8倍,服务器资源消耗降低60%
电商购物车是典型的多字段对象,Hash结构的field-value特性使其成为理想选择。
数据结构设计:
| 键格式 | 字段 | 值 |
|---|---|---|
| cart:userId | productId1 | |
| cart:userId | productId2 |
核心操作代码:
java复制// 添加商品到购物车
public void addToCart(Long userId, Long productId, CartItem item) {
String key = "cart:" + userId;
String field = productId.toString();
String value = JSON.toJSONString(item);
redisTemplate.opsForHash().put(key, field, value);
}
// 获取购物车全部商品
public Map<Long, CartItem> getCart(Long userId) {
String key = "cart:" + userId;
Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
return entries.entrySet().stream()
.collect(Collectors.toMap(
e -> Long.parseLong(e.getKey().toString()),
e -> JSON.parseObject(e.getValue().toString(), CartItem.class)
));
}
高级特性应用:
HINCRBY命令实现商品数量增减业务扩展思考:
List结构的LPUSH+BRPOP组合是构建简单消息队列的利器,特别适合订单日志这类时效性要求不高的场景。
基础架构设计:
code复制订单服务 → LPUSH → Redis List → BRPOP → 日志处理服务
Spring Boot实现示例:
java复制// 生产者端
public void pushOrderLog(OrderLog log) {
String queueKey = "order:log:queue";
redisTemplate.opsForList().leftPush(queueKey, JSON.toJSONString(log));
}
// 消费者端
@Scheduled(fixedDelay = 1000)
public void processOrderLogs() {
String queueKey = "order:log:queue";
String logJson = redisTemplate.opsForList().rightPop(queueKey, 10, TimeUnit.SECONDS);
if (logJson != null) {
OrderLog log = JSON.parseObject(logJson, OrderLog.class);
logService.process(log);
}
}
关键参数调优:
| 参数 | 建议值 | 说明 |
|---|---|---|
| 阻塞超时 | 10-30秒 | 平衡响应速度与资源消耗 |
| 批量处理 | 每次10-100条 | 提升吞吐量 |
| 错误重试 | 3次+死信队列 | 保证可靠性 |
与专业消息队列对比:
| 特性 | Redis List | RabbitMQ/Kafka |
|---|---|---|
| 吞吐量 | 10万+/秒 | 1万-10万/秒 |
| 持久化 | 可选 | 强保证 |
| 功能丰富度 | 简单 | 丰富 |
| 适用场景 | 轻量级 | 企业级 |
Set集合的交并差运算为社交关系分析提供了天然支持,性能远超数据库JOIN操作。
共同好友实现:
java复制// 添加好友关系
public void addFriend(Long userId, Long friendId) {
String key = "user:friends:" + userId;
redisTemplate.opsForSet().add(key, friendId.toString());
}
// 获取共同好友
public Set<Long> getCommonFriends(Long userId1, Long userId2) {
String key1 = "user:friends:" + userId1;
String key2 = "user:friends:" + userId2;
Set<String> result = redisTemplate.opsForSet().intersect(key1, key2);
return result.stream().map(Long::valueOf).collect(Collectors.toSet());
}
兴趣标签推荐系统设计:
SADD user:tags:userId tag1 tag2SADD tag:users:tag1 userId1 userId2java复制// 找出与当前用户标签相似的其他用户
Set<String> similarUsers = redisTemplate.opsForSet().intersect(
Arrays.asList("tag:users:tag1", "tag:users:tag2")
);
性能对比测试:
| 数据量 | MySQL JOIN(ms) | Redis Set(ms) |
|---|---|---|
| 1万用户 | 1200 | 15 |
| 10万用户 | 超时(>30s) | 180 |
| 100万用户 | 无法执行 | 1200 |
有序集合(ZSet)的分数机制天然适合排行榜场景,相比数据库方案有数量级的性能提升。
热榜实现方案:
java复制// 文章热度更新
public void incrementArticleScore(Long articleId, double increment) {
String key = "article:hot";
redisTemplate.opsForZSet().incrementScore(key, articleId.toString(), increment);
}
// 获取TOP10热文
public List<Article> getTopArticles(int limit) {
String key = "article:hot";
Set<ZSetOperations.TypedTuple<String>> tuples =
redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, limit-1);
return tuples.stream()
.map(tuple -> {
Article article = getArticleById(Long.parseLong(tuple.getValue()));
article.setHotScore(tuple.getScore());
return article;
})
.collect(Collectors.toList());
}
多维度排行榜设计技巧:
article:hot:20230501高级应用场景:
在多年Redis实战中,我们总结了以下关键经验:
数据结构选型原则:
| 场景 | 推荐结构 | 优势 |
|---|---|---|
| 简单KV缓存 | String | 读写O(1) |
| 对象属性存储 | Hash | 节省内存 |
| 时间序列数据 | List | 保持顺序 |
| 关系运算 | Set | 高效集合操作 |
| 加权排序 | ZSet | 自动排序 |
常见性能陷阱及解决方案:
大Key问题:
热Key问题:
管道与事务:
java复制// 管道批量操作示例
List<Object> results = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
for (int i = 0; i < 100; i++) {
connection.stringCommands().set(("key:" + i).getBytes(), ("value"+i).getBytes());
}
return null;
});
监控与调优建议:
关键指标监控:
配置优化:
properties复制# 最大内存限制
spring.redis.jedis.pool.max-active=200
# 连接池配置
spring.redis.jedis.pool.max-idle=50
spring.redis.jedis.pool.min-idle=10
慢查询分析:
bash复制# 设置慢查询阈值(微秒)
config set slowlog-log-slower-than 10000
# 查看慢查询日志
slowlog get 10
Spring Boot集成Redis完整配置:
java复制@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Key序列化
template.setKeySerializer(RedisSerializer.string());
// Value序列化
template.setValueSerializer(RedisSerializer.json());
// Hash Key序列化
template.setHashKeySerializer(RedisSerializer.string());
// Hash Value序列化
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
}
}
单元测试方案设计:
java复制@SpringBootTest
public class RedisServiceTest {
@Autowired
private RedisService redisService;
@Test
public void testSessionOperations() {
User user = new User("testUser", "user@example.com");
String sessionId = UUID.randomUUID().toString();
// 测试Session存储
redisService.setSession(sessionId, user, 1800);
User cachedUser = redisService.getSession(sessionId);
assertEquals(user.getUsername(), cachedUser.getUsername());
// 测试Session过期
Thread.sleep(2000); // 需要配置较短的TTL进行测试
assertNull(redisService.getSession(sessionId));
}
@Test
public void testShoppingCartOperations() {
Long userId = 1L;
CartItem item1 = new CartItem(1001L, 2, true);
CartItem item2 = new CartItem(1002L, 1, false);
// 测试购物车添加
redisService.addToCart(userId, item1.getProductId(), item1);
redisService.addToCart(userId, item2.getProductId(), item2);
Map<Long, CartItem> cart = redisService.getCart(userId);
assertEquals(2, cart.size());
// 测试购物车更新
item1.setQuantity(3);
redisService.addToCart(userId, item1.getProductId(), item1);
cart = redisService.getCart(userId);
assertEquals(3, cart.get(1001L).getQuantity());
}
}
性能测试建议:
基准测试工具:
测试场景设计:
监控指标:
bash复制# 内存信息
info memory
# 命令统计
info commandstats
# 持久化信息
info persistence