乐闻世界logo
搜索文章和话题

Redis 有哪些常见的应用场景?如何实现这些场景?

2月19日 19:35

Redis 凭借其高性能和丰富的数据结构,在实际项目中有着广泛的应用场景。以下是 Redis 的主要应用场景及实现方式。

1. 缓存

应用场景

  • 热点数据缓存:缓存频繁访问的数据,减轻数据库压力
  • 查询结果缓存:缓存复杂查询的结果,提高查询性能
  • 页面缓存:缓存页面渲染结果,减少服务器计算

实现方式

java
// 读取缓存 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. 会话存储

应用场景

  • 用户登录状态:存储用户的登录状态和会话信息
  • 分布式会话:在分布式系统中共享会话信息
  • 临时数据存储:存储临时数据,如验证码、临时令牌等

实现方式

java
// 用户登录 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. 计数器

应用场景

  • 文章阅读量:统计文章的阅读次数
  • 视频播放量:统计视频的播放次数
  • 点赞数:统计点赞数量
  • 访问量统计:统计网站访问量

实现方式

java
// 增加计数 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. 排行榜

应用场景

  • 游戏排行榜:实时显示玩家排名
  • 文章排行榜:显示热门文章排行
  • 商品销量排行:显示商品销量排行
  • 用户积分排行:显示用户积分排行

实现方式

java
// 增加分数 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. 消息队列

应用场景

  • 异步任务:将耗时任务放入队列,异步处理
  • 任务调度:实现定时任务和任务调度
  • 事件通知:实现发布订阅模式
  • 日志收集:收集和分发日志

实现方式

java
// 生产者:发送消息 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. 分布式锁

应用场景

  • 库存扣减:防止超卖
  • 订单创建:防止重复创建订单
  • 资源竞争:解决并发竞争问题
  • 限流控制:实现接口限流

实现方式

java
// 获取锁 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 调用频率
  • 防刷接口:防止恶意刷接口
  • 用户限流:限制用户操作频率
  • 系统保护:保护系统不被过载

实现方式

java
// 固定窗口限流 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. 标签系统

应用场景

  • 文章标签:为文章添加标签
  • 用户标签:为用户添加标签
  • 标签查询:根据标签查询内容
  • 标签推荐:基于标签推荐内容

实现方式

java
// 添加标签 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. 地理位置

应用场景

  • 附近的人:查找附近的人
  • 附近的位置:查找附近的位置
  • 距离计算:计算两个位置的距离
  • 位置服务:提供位置相关服务

实现方式

java
// 添加位置 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 统计:统计页面浏览量
  • 实时数据:实时统计业务数据

实现方式

java
// 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 的优势。

标签:Redis