Redis最常用的 8种场景

大家好,我是猿java

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

1. 缓存/数据库

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

举例:

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

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

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

2. 分布式锁

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

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

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

java 复制代码
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 限流:

java 复制代码
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中。

举例:

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

5. 发布/订阅

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

举例:

  • 群聊,在实时聊天应用中,利用 Redis的发布/订阅功能实现消息广播。
  • 实现事件通知系统,如新订单通知、新邮件提醒等。
bash 复制代码
# 订阅频道
SUBSCRIBE channel_xxx
# 向频道中发送消息
PUBLISH channel_xxx "Message content"

6. 排名/排行榜

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

举例:

  1. 记录网站访问次数或文章阅读次数。
shell 复制代码
# 添加文章的点击量#将 Article1 的值增加1。如果Article1 不存在于有序集合中,# 该命令会将 Article1 添加到集合,并设置值为1
ZINCRBY leaderboard 1 "Article1"
ZINCRBY leaderboard 1 "Article2"
ZINCRBY leaderboard 1 "Article3"

# 获取 Article2的排名(从高到低排名)
ZREVRANK leaderboard "Article2" 

# 获点击量 Top10 的文章和点击量
ZREVRANGE leaderboard 0 9 WITHSCORES 
  1. 实现用户积分排行榜。

7. 计数

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

常用计数命令:

shell 复制代码
# 对 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. 点过外卖的小伙伴肯定不陌生,外卖平台上,附近商家搜索功能。
shell 复制代码
# 查找经度12.087269,纬度39.412669 附近5 km的距离范围
GEORADIUS locations 12.087269 39.412669 5 km
  1. 打车平台,比如一些网约车平台,就可以把司机,乘客的位置信息(经纬度)通过Redis的Geo来实现距离计算等功能。
shell 复制代码
# 添加经纬度信息,经纬度是编造的,不一定真实
GEOADD locations 12.322389 39.125356 "Driver"
GEOADD locations 12.087269 39.412669 "Passenger"

# 计算司机和乘客两地点间的距离
GEODIST locations Driver Passenger

总结

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

  1. 缓存/数据库

  2. 分布式锁

  3. 限流

  4. 会话存储

  5. 发布/订阅

  6. 排名/排行榜

  7. 计数

  8. 地理位置应用

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

相关推荐
Hello.Reader21 小时前
Flink SQL「SHOW / SHOW CREATE」元数据巡检、DDL 复刻与排障速查(含 Java 示例)
java·sql·flink
czlczl2002092521 小时前
Spring Boot + Redis :如何设计“登出”功能
spring boot·redis·后端
Doris_LMS21 小时前
接口、普通类和抽象类
java
重生之我是Java开发战士1 天前
【数据结构】优先级队列(堆)
java·数据结构·算法
菜鸟233号1 天前
力扣216 组合总和III java实现
java·数据结构·算法·leetcode
dodod20121 天前
Ubuntu24.04.3执行sudo apt install yarnpkg 命令失败的原因
java·服务器·前端
Evan芙1 天前
搭建 LNMT 架构并配置 Tomcat 日志管理与自动备份
java·架构·tomcat
AuroraWanderll1 天前
类和对象(三)-默认成员函数详解与运算符重载
c语言·开发语言·数据结构·c++·算法
青云交1 天前
Java 大视界 -- Java+Spark 构建企业级用户画像平台:从数据采集到标签输出全流程(437)
java·开发语言·spark·hbase 优化·企业级用户画像·标签计算·高并发查询
阿华hhh1 天前
数据结构(树)
linux·c语言·开发语言·数据结构