写点什么

Redis 常用的八种场景

作者:高端章鱼哥
  • 2023-11-20
    福建
  • 本文字数:3645 字

    阅读完需:约 12 分钟

作为一名 Java 后端人员,对 Redis 肯定并不陌生,Redis 作为一种内存数据库,以其速度之快在编程的舞台上纵横多年,那么,Redis 到底适合哪些业务场景?今天就来聊一聊。

1. 缓存/数据库

缓存(Cache)是 Redis 使用最广泛的场景之一,也是很多小伙伴结识 Redis 的重要原因,在 8 种 10 倍提升 API 性能的方式 文章中我们也强调了 Redis 可以作为缓存的来加速 API 性能。如下图,在 WebServer 和数据库之间会增加一层 Redis 缓存,这样 WebServer 可以直接从 Redis 中快速拿到数据返回,加快了 WebServer 的响应速度。


举例:

  • 电商领域,可以缓存一些热门商品的静态信息或用户数据,这样,在大流量访问时,不用查询数据库,加速访问速度。

  • 配置中心,业务开发中,经常会使用一些全局配置,而且配置更改的频率很低,因此,可以把配置都加载到 Redis 内存中,加快查询数据。


需要说明的是:很多时候,我们都会把 Redis 的持久化功能打开,因此,在把 Redis 当作缓存的同时,同样把 Redis 当作数据库在使用。

2. 分布式锁

分布式锁(Distributed Lock)也是 Redis 使用最广泛的场景之一,分布式系统中,当我们在处理有并发的业务场景时,为了保证线程安全,通常通常会使用分布式锁,单机下,Redis 通常使用 SET NX(if Not Exist)和 PX(过期时间)来创建锁,指令如下:


# 如果key不存,set key=value,# 失效时间是 expiration毫秒SET key value NX PX expiration
复制代码


在 Java 中,Redission 是一个基于 Redis 的分布式 Java 对象映射(Java Redis Client),它提供了丰富的特性和工具,示例代码展示了如何在 Redission 框架中使用 Redis 分布式锁:


import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;
public class RedissonExample { public static void main(String[] args) { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config);
// 使用分布式锁 String lockKey = "lockKey"; boolean isLocked = redisson.getLock(lockKey).tryLock(); if (isLocked) { // 获得锁,执行相关操作 System.out.println("Lock acquired successfully"); redisson.getLock(lockKey).unlock(); // 释放锁 } else { System.out.println("Failed to acquire lock"); } redisson.shutdown(); // 关闭连接 }}
复制代码


需要说明的是:除了 Redis,Zookeeper 也是实现分布式锁比较常用的一种技术方案。

3. 限流

限流(Rate Limiter)也是 Redis 使用比较多的一个场景,限流是保护系统免受过载的一种方法,它可以确保在指定时间内对系统的请求进行限制。在 Redis 中,可以使用 SET、EXPIRE 和 Lua 脚本来实现简单的限流功能。


示例代码展示了 Java Jedis 库实现基于令牌桶算法的 Redis 限流:


import redis.clients.jedis.Jedis;import redis.clients.jedis.Response;import redis.clients.jedis.Transaction;
public class RateLimiter { private final Jedis jedis; private final String key; private final int capacity; private final int tokensPerSecond;
public RateLimiter(Jedis jedis, String key, int capacity, int tokensPerSecond) { this.jedis = jedis; this.key = key; this.capacity = capacity; this.tokensPerSecond = tokensPerSecond; } /** * 用于检查是否允许请求,根据当前令牌数量和容量进行判断 */ public boolean allowRequest() { long now = System.currentTimeMillis(); Transaction transaction = jedis.multi(); // Add current time with score transaction.zadd(key, now, String.valueOf(now)); // Remove tokens that are older than 1 second transaction.zremrangeByScore(key, 0, now - 1000); // Get current number of tokens Response<Long> sizeResponse = transaction.zcard(key);
transaction.exec();
long size = sizeResponse.get(); // Check if number of tokens is within capacity return size <= capacity; }
public static void main(String[] args) { Jedis jedis = new Jedis("localhost"); // Connect to Redis // Create rate limiter RateLimiter rateLimiter = new RateLimiter(jedis, "RateLimiterKey", 10, 5);
for (int i = 0; i < 15; i++) { boolean allowed = rateLimiter.allowRequest(); if (allowed) { System.out.println("Request allowed"); } else { System.out.println("Request denied"); } }
// Close Redis connection jedis.close(); }}
复制代码

4. 会话存储

会话(Session)也是 Redis 常见的一种功能,熟悉 Spring 的小伙伴肯定知道它也有一个 Session 功能,那么它和 Redis 的 Session 有什么区别呢?


Spring Session 是一个抽象层,提供与存储后端衔接能力,至于后端采用内存、数据库还是 Redis 存储 Spring Session 不关注。而 Redis Session 是 Spring Session 的一种具体实现,将会话数据存储在 Redis 中。


举例:存储用户登录信息:

#将用户的登录信息存储在 Redis中,key:userId, value:user登录信息SET user:userId {"username": "xxx", "password": "xxx",...}
复制代码

5. 发布/订阅

发布/订阅(Sub/Pub)是 Redis 中一个类似于消息中间件(MQ)的功能,当我们的业务中有需要通过事件触发的场景时可以使用该功能,不过 Redis 的 Sub/Pub 功能还是比较简陋,有复杂的业务场景时还是推荐 MQ。


举例:

群聊,在实时聊天应用中,利用 Redis 的发布/订阅功能实现消息广播。

实现事件通知系统,如新订单通知、新邮件提醒等。

#订阅频道SUBSCRIBE channel_xxx# 向频道中发送消息PUBLISH channel_xxx "Message content"
复制代码

6. 排名/排行榜

排名/排行榜(Rank/LeaderBoard)是 Redis 中一个比较实用的功能,在文章热榜、游戏竞技或社区平台中,排行榜(Leaderboard)和排名(Ranking)系统是常见的功能,用于展示用户在特定活动、比赛或指标上的排名情况,而 Redis 的有序集合(Sorted Set)是实现排行榜功能的理想数据结构,因为它可以存储每个成员的分数,并根据分数进行排序。


举例:

(1) 记录网站访问次数或文章阅读次数。

# 添加文章的点击量#将 Article1 的值增加1。如果Article1 不存在于有序集合中,# 该命令会将 Article1 添加到集合,并设置值为1ZINCRBY leaderboard 1 "Article1"ZINCRBY leaderboard 1 "Article2"ZINCRBY leaderboard 1 "Article3"
# 获取 Article2的排名(从高到低排名)ZREVRANK leaderboard "Article2"
# 获点击量 Top10 的文章和点击量ZREVRANGE leaderboard 0 9 WITHSCORES
复制代码

(2) 实现用户积分排行榜。

7. 计数

在 Redis 中,可以使用 INCR、DECR 等命令来进行简单的计数操作。这些命令用于对键的值进行递增或递减操作,常用于实现计数器等功能。


常用计数命令:

# 对 key进行 +1 操作INCR key# 对key 进行 -1 操作DECR key
# 对 key进行 +n 操作INCRBY key n# 对 key进行 -n 操作DECRBY key n
复制代码

另外,在排名/排行榜中,ZINCRBY 是对 Sort set 的一种计数方式。

举例:

  • 网站访问量计数器,可以实时统计网站的访问次数;

  • 点赞/喜欢计数器,对文章或内容的点赞或喜欢次数进行计数;

  • 用户在线状态统计,统计在线用户数量;

8. 地理位置应用

Redis 的地理位置应用功能使用的场景比较有针对性,如果你不是在特定的领域,可能并不会使用该功能,它是 通过 Geo 数据类型支持地理位置存储和检索,可以用于构建位置服务和地理位置相关的应用。


举例:

(1) 点过外卖的小伙伴肯定不陌生,外卖平台上,附近商家搜索功能。

# 查找经度12.087269,纬度39.412669 附近5 km的距离范围GEORADIUS locations 12.087269 39.412669 5 km
复制代码


(2) 打车平台,比如一些网约车平台,就可以把司机,乘客的位置信息(经纬度)通过 Redis 的 Geo 来实现距离计算等功能。

# 添加经纬度信息,经纬度是编造的,不一定真实GEOADD locations 12.322389 39.125356 "Driver"GEOADD locations 12.087269 39.412669 "Passenger"# 计算司机和乘客两地点间的距离GEODIST locations Driver Passenger
复制代码

总结

本文介绍了 Redis 常见的 8 种实用场景:

  • 缓存/数据库

  • 分布式锁

  • 限流

  • 会话存储

  • 发布/订阅

  • 排名/排行榜

  • 计数

  • 地理位置应用


如果你在业务中不确定是否需要引入 Redis 时,可以参考本文,如果场景刚好命中其中一种,那么可以选择使用 Redis。如果你的业务场景不在这 8 种常见场景中,不代表不能使用 Redis,可能需要你更多的技术调研来确认合适的技术方案。

发布于: 刚刚阅读数: 6
用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Redis常用的八种场景_redis_高端章鱼哥_InfoQ写作社区