Redis 有哪些常见的应用场景?如何实现这些场景?
Redis 凭借其高性能和丰富的数据结构,在实际项目中有着广泛的应用场景。以下是 Redis 的主要应用场景及实现方式。1. 缓存应用场景热点数据缓存:缓存频繁访问的数据,减轻数据库压力查询结果缓存:缓存复杂查询的结果,提高查询性能页面缓存:缓存页面渲染结果,减少服务器计算实现方式// 读取缓存public User getUserById(Long id) { String key = "user:" + id; User user = redis.get(key); if (user != null) { return user; } // 缓存未命中,查询数据库 user = db.queryUserById(id); // 写入缓存 redis.set(key, user, 3600); // 缓存 1 小时 return user;}// 更新缓存public void updateUser(User user) { db.updateUser(user); redis.del("user:" + user.getId()); // 删除缓存}注意事项设置合理的过期时间,避免缓存雪崩使用缓存穿透、缓存击穿、缓存雪崩的解决方案监控缓存命中率,及时调整缓存策略2. 会话存储应用场景用户登录状态:存储用户的登录状态和会话信息分布式会话:在分布式系统中共享会话信息临时数据存储:存储临时数据,如验证码、临时令牌等实现方式// 用户登录public String login(String username, String password) { User user = db.authenticate(username, password); if (user != null) { String sessionId = generateSessionId(); String key = "session:" + sessionId; // 存储会话信息 redis.set(key, user, 1800); // 30 分钟过期 return sessionId; } return null;}// 验证会话public User validateSession(String sessionId) { String key = "session:" + sessionId; User user = redis.get(key); if (user != null) { // 刷新过期时间 redis.expire(key, 1800); return user; } return null;}3. 计数器应用场景文章阅读量:统计文章的阅读次数视频播放量:统计视频的播放次数点赞数:统计点赞数量访问量统计:统计网站访问量实现方式// 增加计数public long incrementViewCount(Long articleId) { String key = "article:view:" + articleId; return redis.incr(key);}// 获取计数public long getViewCount(Long articleId) { String key = "article:view:" + articleId; return redis.get(key);}// 批量获取计数public Map<Long, Long> getViewCounts(List<Long> articleIds) { String[] keys = articleIds.stream() .map(id -> "article:view:" + id) .toArray(String[]::new); return redis.mget(keys);}4. 排行榜应用场景游戏排行榜:实时显示玩家排名文章排行榜:显示热门文章排行商品销量排行:显示商品销量排行用户积分排行:显示用户积分排行实现方式// 增加分数public void addScore(Long userId, double score) { String key = "leaderboard:user"; redis.zadd(key, score, userId.toString());}// 获取排行榜public List<User> getLeaderboard(int start, int end) { String key = "leaderboard:user"; // 获取排名和分数 Set<Tuple> tuples = redis.zrevrangeWithScores(key, start, end); // 转换为用户列表 return tuples.stream() .map(tuple -> { Long userId = Long.parseLong(tuple.getElement()); User user = db.getUserById(userId); user.setScore(tuple.getScore()); user.setRank(redis.zrevrank(key, userId.toString()) + 1); return user; }) .collect(Collectors.toList());}// 获取用户排名public long getUserRank(Long userId) { String key = "leaderboard:user"; Long rank = redis.zrevrank(key, userId.toString()); return rank != null ? rank + 1 : 0;}5. 消息队列应用场景异步任务:将耗时任务放入队列,异步处理任务调度:实现定时任务和任务调度事件通知:实现发布订阅模式日志收集:收集和分发日志实现方式// 生产者:发送消息public void sendMessage(String queue, String message) { redis.lpush(queue, message);}// 消费者:消费消息public String consumeMessage(String queue) { return redis.brpop(queue, 0); // 阻塞式消费}// 批量消费public List<String> consumeMessages(String queue, int count) { List<String> messages = new ArrayList<>(); for (int i = 0; i < count; i++) { String message = redis.rpop(queue); if (message == null) { break; } messages.add(message); } return messages;}6. 分布式锁应用场景库存扣减:防止超卖订单创建:防止重复创建订单资源竞争:解决并发竞争问题限流控制:实现接口限流实现方式// 获取锁public boolean tryLock(String key, String value, int expireTime) { String result = redis.set(key, value, "NX", "EX", expireTime); return "OK".equals(result);}// 释放锁public void unlock(String key, String value) { String script = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end"; redis.eval(script, Collections.singletonList(key), Collections.singletonList(value));}// 使用锁public void deductStock(Long productId, int quantity) { String lockKey = "lock:product:" + productId; String lockValue = UUID.randomUUID().toString(); try { // 获取锁 if (tryLock(lockKey, lockValue, 10)) { // 扣减库存 db.deductStock(productId, quantity); } } finally { // 释放锁 unlock(lockKey, lockValue); }}7. 限流器应用场景API 限流:限制 API 调用频率防刷接口:防止恶意刷接口用户限流:限制用户操作频率系统保护:保护系统不被过载实现方式// 固定窗口限流public boolean allowRequest(String key, int limit, int expireTime) { String count = redis.get(key); if (count == null) { redis.set(key, "1", expireTime); return true; } int currentCount = Integer.parseInt(count); if (currentCount < limit) { redis.incr(key); return true; } return false;}// 滑动窗口限流public boolean allowRequestSliding(String key, int limit, int windowSize) { long currentTime = System.currentTimeMillis(); long windowStart = currentTime - windowSize; // 移除窗口外的数据 redis.zremrangeByScore(key, 0, windowStart); // 添加当前请求 redis.zadd(key, currentTime, UUID.randomUUID().toString()); // 统计窗口内的请求数 long count = redis.zcard(key); return count <= limit;}8. 标签系统应用场景文章标签:为文章添加标签用户标签:为用户添加标签标签查询:根据标签查询内容标签推荐:基于标签推荐内容实现方式// 添加标签public void addTags(Long articleId, Set<String> tags) { String key = "article:tags:" + articleId; redis.sadd(key, tags.toArray(new String[0]));}// 获取标签public Set<String> getTags(Long articleId) { String key = "article:tags:" + articleId; return redis.smembers(key);}// 根据标签查询文章public Set<Long> getArticlesByTag(String tag) { String key = "tag:articles:" + tag; return redis.smembers(key);}// 获取共同标签public Set<String> getCommonTags(Long articleId1, Long articleId2) { String key1 = "article:tags:" + articleId1; String key2 = "article:tags:" + articleId2; return redis.sinter(key1, key2);}9. 地理位置应用场景附近的人:查找附近的人附近的位置:查找附近的位置距离计算:计算两个位置的距离位置服务:提供位置相关服务实现方式// 添加位置public void addLocation(String key, double longitude, double latitude) { redis.geoadd(key, longitude, latitude, key);}// 查找附近的位置public List<Location> getNearbyLocations(String key, double longitude, double latitude, double radius) { return redis.georadius(key, longitude, latitude, radius, GeoUnit.KM);}// 计算距离public double getDistance(String key, String member1, String member2) { return redis.geodist(key, member1, member2, GeoUnit.KM);}10. 实时统计应用场景在线人数:统计在线用户数UV 统计:统计独立访客数PV 统计:统计页面浏览量实时数据:实时统计业务数据实现方式// UV 统计(使用 HyperLogLog)public long getUV(String key) { return redis.pfcount(key);}public void addUV(String key, String userId) { redis.pfadd(key, userId);}// PV 统计(使用计数器)public long getPV(String key) { String count = redis.get(key); return count != null ? Long.parseLong(count) : 0;}public void addPV(String key) { redis.incr(key);}总结Redis 在实际项目中有广泛的应用场景,包括缓存、会话存储、计数器、排行榜、消息队列、分布式锁、限流器、标签系统、地理位置、实时统计等。每个应用场景都有其特定的实现方式和注意事项。在实际开发中,需要根据具体的业务需求,选择合适的应用场景和实现方式,充分发挥 Redis 的优势。