
🍃 予枫 :个人主页
📚 个人专栏 : 《Java 从入门到起飞》《读研码农的干货日常》
💻 Debug 这个世界,Return 更好的自己!
引言
做电商或社交开发的同学,大概率都遇到过这样的痛点:购物车商品实时更新、点赞功能秒级响应、排行榜实时排序,既要扛住十万级并发请求,又要保证核心数据不丢失------这时候,Redis 准存储就是破局关键。不同于纯缓存的"临时存储",准存储既保留了Redis的高性能优势,又通过合理的设计实现数据安全,完美适配电商、社交等核心业务场景。本文将从准存储定义出发,结合购物车、点赞、排行榜三大高频场景,拆解实现逻辑与高并发优化方案,干货满满,建议收藏慢慢看!
文章目录
- 引言
- 一、什么是Redis准存储?
- 二、电商场景实战:购物车(Hash结构实现)
-
- [2.1 实现逻辑拆解](#2.1 实现逻辑拆解)
- [2.2 核心代码实现(Java示例)](#2.2 核心代码实现(Java示例))
- [2.3 高并发优化点](#2.3 高并发优化点)
- 三、社交场景实战:点赞功能(Set结构实现)
-
- [3.1 实现逻辑拆解](#3.1 实现逻辑拆解)
- [3.2 核心代码实现(Java示例)](#3.2 核心代码实现(Java示例))
- [3.3 高并发优化点](#3.3 高并发优化点)
- [四、通用场景实战:排行榜(Sorted Set结构实现)](#四、通用场景实战:排行榜(Sorted Set结构实现))
-
- [4.1 实现逻辑拆解](#4.1 实现逻辑拆解)
- [4.2 核心代码实现(Java示例)](#4.2 核心代码实现(Java示例))
- [4.3 高并发优化点](#4.3 高并发优化点)
- 五、高并发下的性能优化核心:Pipeline批量操作
-
- [5.1 Pipeline原理](#5.1 Pipeline原理)
- [5.2 核心代码实现(批量查询点赞状态示例)](#5.2 核心代码实现(批量查询点赞状态示例))
- [5.3 Pipeline使用注意事项](#5.3 Pipeline使用注意事项)
- 六、全文总结
一、什么是Redis准存储?
首先,我们要明确:Redis准存储≠缓存,也≠数据库,而是介于两者之间的"高性能数据载体"。
核心定义:准存储是指基于Redis的高性能特性,将核心业务数据(非核心但对响应速度要求极高)以特定数据结构存储,通过持久化配置+数据同步策略,实现"高性能访问"与"数据安全兜底"的平衡,适用于对实时性要求高、数据一致性要求中等的场景(如购物车、点赞、排行榜等)。
准存储的核心特性(3大关键点)
- 高性能优先:基于Redis内存操作特性,读写响应时间控制在毫秒级,支撑高并发场景;
- 数据安全兜底:开启AOF/RDB持久化,配合定时同步到数据库,避免Redis宕机导致数据丢失;
- 适配特定场景:针对非核心交易数据(购物车未支付商品、点赞关系、临时排行榜),无需强事务支持,允许短时间数据不一致(可通过同步机制补偿)。
🌟 提示:准存储的核心价值的是"取舍"------牺牲极致一致性,换取超高并发与响应速度,这也是电商、社交场景的核心诉求。觉得有收获的同学,欢迎点赞+收藏,后续实战代码可直接复用!
二、电商场景实战:购物车(Hash结构实现)
购物车是电商平台的核心场景之一,要求支持"添加商品、修改数量、删除商品、查询商品列表"等操作,同时要保证用户切换设备时数据同步,且在高并发(如双十一)时不卡顿。Redis的Hash结构(键值对集合)天然适配购物车场景。
2.1 实现逻辑拆解
- 核心思路:以用户ID作为Redis的Key(如
cart:user:10086),Hash的Field为商品ID,Hash的Value为商品详情(JSON格式,包含商品名称、单价、数量、选中状态等); - 数据安全:开启AOF持久化(每秒同步一次),同时后台定时任务(如每分钟)将购物车数据同步到MySQL数据库(兜底存储);
- 核心操作:添加/修改商品(hset)、删除商品(hdel)、查询所有商品(hgetall)、清空购物车(del)。
2.2 核心代码实现(Java示例)
java
/**
* 购物车Redis操作工具类
*/
@Component
public class CartRedisUtil {
@Autowired
private StringRedisTemplate redisTemplate;
// 购物车Key前缀
private static final String CART_KEY_PREFIX = "cart:user:";
// 过期时间:7天(用户未操作自动清理)
private static final Long EXPIRY_TIME = 7 * 24 * 60 * 60L;
/**
* 添加/修改购物车商品
* @param userId 用户ID
* @param productId 商品ID
* @param productInfo 商品详情(JSON字符串)
*/
public void addOrUpdateCart(Long userId, Long productId, String productInfo) {
String key = CART_KEY_PREFIX + userId;
redisTemplate.opsForHash().put(key, productId.toString(), productInfo);
// 设置过期时间(重置过期时间,用户操作后延续7天)
redisTemplate.expire(key, EXPIRY_TIME, TimeUnit.SECONDS);
}
/**
* 删除购物车商品
* @param userId 用户ID
* @param productId 商品ID
*/
public void deleteCartItem(Long userId, Long productId) {
String key = CART_KEY_PREFIX + userId;
redisTemplate.opsForHash().delete(key, productId.toString());
}
/**
* 查询用户购物车所有商品
* @param userId 用户ID
* @return 商品列表(Map<商品ID, 商品详情>)
*/
public Map<String, String> getCartList(Long userId) {
String key = CART_KEY_PREFIX + userId;
return redisTemplate.opsForHash().entries(key);
}
/**
* 清空购物车
* @param userId 用户ID
*/
public void clearCart(Long userId) {
String key = CART_KEY_PREFIX + userId;
redisTemplate.delete(key);
}
}
2.3 高并发优化点
- 批量操作:用户批量添加/删除商品时,使用
hmultiSet/hmultiGet替代多次单条操作,减少Redis网络请求; - 过期清理:设置合理的过期时间(如7天),避免无效数据占用内存;
- 缓存预热:双十一等大促前,将高频用户的购物车数据提前加载到Redis内存中。
三、社交场景实战:点赞功能(Set结构实现)
社交平台的点赞功能(如文章点赞、评论点赞),要求支持"点赞、取消点赞、查询点赞状态、统计点赞数量"等操作,特点是并发量极高(单篇热门文章点赞量可达百万级),且对实时性要求极高。Redis的Set结构(无序不重复集合)适合存储点赞用户ID,天然支持去重(避免重复点赞)。
3.1 实现逻辑拆解
- 核心思路:以"业务类型:对象ID"作为Redis的Key(如
like:article:2024,表示文章2024的点赞集合),Set的Value为点赞用户ID; - 点赞状态:判断用户是否点赞(sismember),点赞则添加用户ID(sadd),取消点赞则移除用户ID(srem);
- 点赞数量:直接获取Set集合的大小(scard),无需查询数据库;
- 数据安全:开启AOF持久化,定时(如每5分钟)将点赞数据同步到MySQL(存储点赞关系,用于后续统计分析)。
3.2 核心代码实现(Java示例)
java
/**
* 点赞Redis操作工具类
*/
@Component
public class LikeRedisUtil {
@Autowired
private StringRedisTemplate redisTemplate;
// 点赞Key前缀(article:文章,comment:评论)
private static final String LIKE_KEY_PREFIX = "like:%s:%s";
// 过期时间:永久(点赞数据需长期保留)
private static final Long EXPIRY_TIME = -1L;
/**
* 点赞操作
* @param bizType 业务类型(article/comment)
* @param bizId 业务ID(文章ID/评论ID)
* @param userId 用户ID
* @return true:点赞成功,false:已点赞(重复点赞)
*/
public boolean like(String bizType, Long bizId, Long userId) {
String key = String.format(LIKE_KEY_PREFIX, bizType, bizId);
// sadd返回1表示添加成功(未点赞),返回0表示已存在(重复点赞)
Long result = redisTemplate.opsForSet().add(key, userId.toString());
return result != null && result > 0;
}
/**
* 取消点赞操作
* @param bizType 业务类型
* @param bizId 业务ID
* @param userId 用户ID
* @return true:取消成功,false:未点赞(无需取消)
*/
public boolean cancelLike(String bizType, Long bizId, Long userId) {
String key = String.format(LIKE_KEY_PREFIX, bizType, bizId);
// srem返回1表示移除成功(已点赞),返回0表示不存在(未点赞)
Long result = redisTemplate.opsForSet().remove(key, userId.toString());
return result != null && result > 0;
}
/**
* 查询用户是否点赞
* @param bizType 业务类型
* @param bizId 业务ID
* @param userId 用户ID
* @return true:已点赞,false:未点赞
*/
public boolean isLiked(String bizType, Long bizId, Long userId) {
String key = String.format(LIKE_KEY_PREFIX, bizType, bizId);
return redisTemplate.opsForSet().isMember(key, userId.toString());
}
/**
* 统计点赞数量
* @param bizType 业务类型
* @param bizId 业务ID
* @return 点赞数量
*/
public Long countLike(String bizType, Long bizId) {
String key = String.format(LIKE_KEY_PREFIX, bizType, bizId);
return redisTemplate.opsForSet().size(key);
}
}
3.3 高并发优化点
- 避免缓存穿透:对于未点赞的对象,Redis中不会存储Key,可设置空值缓存(如点赞数为0时,存储Key并设置短期过期时间);
- 批量统计:多篇文章/多条评论的点赞数统计,使用
pipeline批量查询(减少网络往返次数); - 异步同步:点赞数据同步到MySQL时,采用异步线程池(如ThreadPoolExecutor),避免阻塞点赞接口响应。
📌 互动时刻:你在项目中实现点赞功能时,遇到过哪些问题?欢迎在评论区留言交流~
四、通用场景实战:排行榜(Sorted Set结构实现)
排行榜是电商(销量排行)、社交(粉丝排行)、游戏(积分排行)等场景的高频需求,要求支持"实时更新排名、查询TopN、查询用户排名"等操作,且排序结果需实时准确。Redis的Sorted Set结构(有序不重复集合),通过"分数(score)"排序,天然适配排行榜场景。
4.1 实现逻辑拆解
- 核心思路:以"排行榜名称"作为Redis的Key(如
rank:sales:202412,表示2024年12月商品销量排行),Sorted Set的Value为商品ID(或用户ID),Score为排序依据(销量、粉丝数、积分等); - 排名规则:默认按Score降序排序(zrevrange),支持升序排序(zrange);
- 核心操作:更新排名(zadd)、查询TopN(zrevrange)、查询用户排名(zrevrank)、查询用户分数(zscore)。
4.2 核心代码实现(Java示例)
java
/**
* 排行榜Redis操作工具类
*/
@Component
public class RankRedisUtil {
@Autowired
private StringRedisTemplate redisTemplate;
// 过期时间:30天(月度排行榜保留30天)
private static final Long EXPIRY_TIME = 30 * 24 * 60 * 60L;
/**
* 更新排行榜数据(添加/修改分数)
* @param rankKey 排行榜Key(如rank:sales:202412)
* @param member 成员ID(商品ID/用户ID)
* @param score 分数(排序依据)
*/
public void updateRank(String rankKey, String member, Double score) {
redisTemplate.opsForZSet().add(rankKey, member, score);
// 设置过期时间
redisTemplate.expire(rankKey, EXPIRY_TIME, TimeUnit.SECONDS);
}
/**
* 查询TopN排行榜(降序,从高到低)
* @param rankKey 排行榜Key
* @param topN 前N名
* @return List<ZSetOperations.TypedTuple<String>>:包含成员ID和分数
*/
public List<ZSetOperations.TypedTuple<String>> getTopNRank(String rankKey, int topN) {
// 0表示第1名,topN-1表示第N名(闭区间)
return redisTemplate.opsForZSet().reverseRangeWithScores(rankKey, 0, topN - 1);
}
/**
* 查询用户排名(降序,排名从0开始)
* @param rankKey 排行榜Key
* @param member 成员ID
* @return 排名(null表示未上榜)
*/
public Long getMemberRank(String rankKey, String member) {
// reverseRank:降序排名(0为第一名)
return redisTemplate.opsForZSet().reverseRank(rankKey, member);
}
/**
* 查询用户分数
* @param rankKey 排行榜Key
* @param member 成员ID
* @return 分数(null表示未上榜)
*/
public Double getMemberScore(String rankKey, String member) {
return redisTemplate.opsForZSet().score(rankKey, member);
}
}
4.3 高并发优化点
- 批量更新:多成员分数更新时,使用
addAll批量添加,减少Redis请求; - 分数自增:支持分数递增(如销量+1),使用
incrementScore替代add(原子操作,避免并发问题); - 热点分离:热门排行榜(如实时销量榜)可拆分多个Redis实例存储,避免单实例压力过大。
五、高并发下的性能优化核心:Pipeline批量操作
无论是购物车、点赞还是排行榜场景,在高并发请求下,单条Redis操作会因为网络往返次数过多导致响应延迟。Redis Pipeline(流水线)允许将多个命令打包发送到Redis服务器,服务器批量执行后一次性返回结果,可大幅减少网络往返次数,提升吞吐量。
5.1 Pipeline原理
- 传统操作:客户端发送1条命令 → 服务器执行并返回 → 客户端接收结果(1次网络往返);
- Pipeline操作:客户端打包N条命令 → 服务器批量执行 → 客户端一次性接收N条结果(1次网络往返);
- 注意:Pipeline中的命令是批量执行的,但并非原子操作(若其中一条命令失败,其他命令仍会执行),适合非事务性场景。
5.2 核心代码实现(批量查询点赞状态示例)
java
/**
* 批量查询用户点赞状态(使用Pipeline优化)
*/
public Map<Long, Boolean> batchCheckLike(String bizType, Long bizId, List<Long> userIds) {
String key = String.format(LIKE_KEY_PREFIX, bizType, bizId);
Map<Long, Boolean> resultMap = new HashMap<>(userIds.size());
// 使用Pipeline批量执行命令
List<Object> responses = redisTemplate.executePipelined(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
StringRedisConnection stringRedisConnection = (StringRedisConnection) connection;
for (Long userId : userIds) {
// 批量添加sismember命令
stringRedisConnection.sIsMember(key, userId.toString());
}
return null;
}
});
// 处理响应结果
for (int i = 0; i < userIds.size(); i++) {
Long userId = userIds.get(i);
Boolean isLiked = (Boolean) responses.get(i);
resultMap.put(userId, isLiked != null && isLiked);
}
return resultMap;
}
5.3 Pipeline使用注意事项
- 命令打包数量:不宜过多(建议每次100-1000条),避免单次请求数据量过大导致阻塞;
- 适用场景:非事务性、批量读写场景(如批量查询、批量更新),不适合需要原子性的操作;
- 性能提升:高并发场景下,Pipeline可将吞吐量提升5-10倍,大幅降低接口响应时间。
六、全文总结
本文围绕Redis准存储的核心价值,结合电商购物车(Hash)、社交点赞(Set)、通用排行榜(Sorted Set)三大高频业务场景,详细拆解了实现逻辑、核心代码,并重点讲解了高并发下的性能优化方案(Pipeline批量操作、异步同步、过期清理等)。
核心要点总结:
- Redis准存储的核心是"高性能+数据安全"的平衡,适配非核心但实时性要求高的场景;
- 不同业务场景需选择合适的Redis数据结构(Hash适配键值对、Set适配去重、Sorted Set适配排序);
- 高并发优化的关键是减少Redis网络往返次数(Pipeline)、避免无效数据(过期清理)、分散压力(热点分离)。
Redis准存储在电商、社交等领域的应用极为广泛,掌握这些实战技巧,能让你在面对高并发场景时更从容。建议结合实际项目场景多练多总结,将理论转化为实战能力。