redis常见使用场景

文章目录

    • redis常见使用场景
    • 全局ID
    • 位统计
    • 购物车
    • 用户消息时间线timeline
    • 抽奖
    • 商品筛选
    • 分布式锁
    • 限流
    • redis实现计数器
    • 排行榜
    • 消息队列
      • redis 如何实现延时队列
    • redis生产常用的场景

redis常见使用场景

Redis 是一种高性能的内存数据库,广泛应用于各种场景中。以下是 Redis 的常见使用场景:

  1. 缓存:作为缓存层,将频繁访问的数据存储在内存中,以加速数据访问速度。Redis 提供了丰富的数据结构和缓存策略,可以用于实现各种灵活的缓存方案。
  2. 会话存储:将用户会话数据存储在 Redis 中,用于实现分布式会话管理,提高系统的可扩展性和容错性。
  3. 计数器:用于实现各种计数器功能,比如网站访问量统计、点赞数统计等。
  4. 消息队列:利用 Redis 的发布订阅功能或者列表数据结构,实现简单的消息队列,用于异步处理任务、事件驱动等场景。
  5. 分布式锁:利用 Redis 的原子性操作和过期时间特性,实现分布式锁,用于解决并发访问时的资源竞争问题。
  6. 地理位置应用:利用 Redis 的地理位置数据结构,实现地理位置相关的应用,比如附近的人功能、地理位置搜索等。
  7. 实时排行榜:利用有序集合数据结构,实现实时排行榜功能,用于排名、统计等应用场景。
  8. 缓存预热:在系统启动或者高峰期前,通过 Redis 预先加载数据,以提高系统的响应速度和稳定性。
  9. 分布式会议管理:用于实现分布式锁、分布式信号量等功能,用于分布式系统的协调和同步。
  10. 实时数据分析:通过 Redis 提供的数据结构和原子性操作,支持实时数据分析、统计等功能。
    总的来说,Redis 在缓存、会话存储、消息队列、分布式锁等方面具有广泛的应用场景,可以帮助构建高性能、可扩展的应用系统。然而在使用 Redis 时,需要考虑数据持久化、高可用性、安全性等方面的问题,以及合理设计和优化 Redis 的使用方式。

缓存
String类型
例如:热点数据缓存(例如报表、明星出轨),对象缓存、全页缓存、可以提升热点数据的访问数据。

数据共享分布式
String 类型,因为 Redis 是分布式的独立服务,可以在多个应用之间共享
例如:分布式Session

 
    org.springframework.session 
    spring-session-data-redis 
    

全局ID

nt类型,incrby,利用原子性
incrby userid 1000
分库分表的场景,一次性拿一段

位统计

String类型的bitcount(1.6.6的bitmap数据结构介绍)
字符是以8位二进制存储的
setk1 a
setbit k1 6 1
setbit k1 7 0
get k1
/* 6 7 代表的a的二进制位的修改
a 对应的ASCII码是97,转换为二进制数据是01100001
b 对应的ASCII码是98,转换为二进制数据是01100010

因为bit非常节省空间(1 MB=8388608 bit),可以用来做大数据量的统计。
*/
例如:在线用户统计,留存用户统计

购物车

String 或hash。所有String可以做的hash都可以做

用户消息时间线timeline

list,双向链表,直接作为timeline就好了。插入有序

抽奖

自带一个随机获得值
spop myset

商品筛选

sdiffset1 set2
//获取交集(intersection )
sinter set1 set2
//获取并集
sunion set1 set2

分布式锁

 String 类型setnx方法,只有不存在时才能添加成功,返回true  
public static boolean getLock(String key) {
    Long flag = jedis.setnx(key, "1");
    if (flag == 1) {
        jedis.expire(key, 10);
    }
    return flag == 1;
}
 
public static void releaseLock(String key) {
    jedis.del(key);
}

代码要执多个redis命令,不加锁的情况下如何保证原子性 --分布式锁
lua脚本:https://segmentfault.com/a/1190000009811453
Redis 中执行 Lua 脚本
Lua脚本功能为Redis开发和运维人员带来如下三个好处:
●Lua脚本在Redis中是原子执行的,执行过程中间不会插入其他命令。
●Lua脚本可以帮助开发和运维人员创造出自己定制的命令,并可以将这些命令常驻在Redis内存中,实现复用的效果。
●Lua脚本可以将多条命令一次性打包,有效地减少网络开销。

限流

int类型,incr方法
以访问者的ip和其他信息作为key,访问一次增加一次计数,超过次数则返回false

redis实现计数器

int类型,increment()方法
例如:文章的阅读量、微博点赞数、允许一定的延迟,先写入Redis再定时同步到数据库
使用场景: 一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等

 /**
     * 利用redis做计数器
     * 可以处理业务上面的的一些访问次数之类的
     * 例如:文章的点赞数,阅读量,允许有一点的延迟效果,先保存到redis中,然后在同步到数据库当中
     */
    @RequestMapping("hello")
    public void count() {
        /**
         * 判断是否到达次数
         */
        Boolean aBoolean = invokeExceededTimes("time_key2",1,3);
        if (aBoolean) {
            LOGGER.info("可以访问");
        }else {
            LOGGER.info("请求次数达标了");
        }
    }

    /**
     * 判断同一个key在规定时间内访问次数是否到达了最高值
     * @param key   键
     * @param days  时间
     * @param count 一定时间内的访问次数
     * @return
     */
    public Boolean invokeExceededTimes(String key, int days, int count) {

        LOGGER.info("key值:{}",key);
        // 判断在redis中是否有key值
        Boolean redisKey = stringRedisTemplate.hasKey(key);
        if (redisKey) {
            // 获取key所对应的value
            Integer hasKey =Integer.parseInt((String)stringRedisTemplate.opsForValue().get(key));
            if (hasKey >= count) {
                return false;
            }
            // 对value进行加1操作
            stringRedisTemplate.opsForValue().increment(key,1);
            return true;
        }else {
            // 如果没有key值,对他进行添加到redis中
            stringRedisTemplate.opsForValue().set(key,"1",days,TimeUnit.DAYS);
        }
        return true;
    }

排行榜

Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(SortedSet)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的 10 个用户–我们称之为“user_scores”,
我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games 就是一个很好的例子,用 Ruby 实现的,它的排行榜就是使用 Redis 来存储数据的,你可以在这里看到

消息队列

List提供了两个阻塞的弹出操作:blpop/brpop,可以设置超时时间
blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
brpop:brpop key1 timeout 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
上面的操作。其实就是java的阻塞队列。学习的东西越多。学习成本越低
● 队列:先进先除:rpush blpop,左头右尾,右边进入队列,左边出队列
● 栈:先进后出:rpush brpop
发布订阅
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
客户端向频道中发布消息,多个订阅者可以同时收到
Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis 能作为一个很好的消息队列平台来使用。Redis 作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
如果你快速的在 Google 中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用 Redis 创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用 Redis 作为 broker,你可以从这里去查看。

Redis 异步队列
答:一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候, 要适当
sleep 一会再重试。
如果对方追问可不可以不用 sleep 呢?
list 还有个指令叫 blpop,在没有消息的时候,它会阻塞住直到消息到来。如果对方追问能不能生产一
次消费多次呢? 使用 pub/sub 主题订阅者模式, 可以实现1:N 的消息队列。
如果对方追问 pub/sub 有什么缺点?
在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 RabbitMQ 等。
如果对方追问 redis 如何实现延时队列?
我估计现在你很想把面试官一棒打死如果你手上有一根棒球棍的话, 怎么问的这么详细。但是你很克制,然后神态自若的回答道:使用 sortedset,拿时间戳作为score,消息内容作为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。到这里, 面试官暗地里已经对你竖起了大拇指。但是他不知道的是此刻你却竖起了中指, 在椅子背后。

redis 如何实现延时队列

redis过期监听
redis的zset
redisson
redis延迟队列 的原理
基于上述原理,Redis延迟队列的工作流程通常如下:
● 将待执行的任务或消息以有序集合的形式存储在Redis中,其中成员为消息内容,分数为消息的执行时间。
● 使用定时任务轮询机制,定期检查有序集合中是否有到期的任务。可以通过Redis的定时任务调度器或外部定时任务程序实现。
● 当检测到有任务的执行时间已到达时,从有序集合中取出该任务,并执行相应的处理逻辑。
通过以上流程,可以实现延迟处理任务或消息的功能。Redis延迟队列通常具有较高的性能和可靠性,并且易于实现和部署。然而,需要注意的是,Redis延迟队列通常只能提供基本的延迟功能,如果需要更复杂的消息队列功能(如消息重试、消息持久化等),可能需要结合其他消息中间件来实现。
Redis延迟队列是一种常用的消息队列模式,用于延迟处理任务或消息。其原理通常基于两个主要组件:有序集合(Sorted Set)和定时任务轮询。

  1. 有序集合(Sorted Set):
    ○ Redis中的有序集合是一种数据结构,其中的每个成员都关联了一个分数(score)。有序集合的特性之一是按照分数从小到大排序。在延迟队列中,可以将消息或任务的执行时间作为分数,将消息内容作为成员存储在有序集合中。
  2. 定时任务轮询:
    ○ 定时任务轮询是一种机制,用于定期检查有序集合中是否有到期的任务或消息。通过定期轮询有序集合,可以检查是否有任务的执行时间已到达,从而将其取出并执行。
    基于上述原理,Redis延迟队列的工作流程通常如下:
    ● 将待执行的任务或消息以有序集合的形式存储在Redis中,其中成员为消息内容,分数为消息的执行时间。
    ● 使用定时任务轮询机制,定期检查有序集合中是否有到期的任务。可以通过Redis的定时任务调度器或外部定时任务程序实现。
    ● 当检测到有任务的执行时间已到达时,从有序集合中取出该任务,并执行相应的处理逻辑。
    通过以上流程,可以实现延迟处理任务或消息的功能。Redis延迟队列通常具有较高的性能和可靠性,并且易于实现和部署。然而,需要注意的是,Redis延迟队列通常只能提供基本的延迟功能,如果需要更复杂的消息队列功能(如消息重试、消息持久化等),可能需要结合其他消息中间件来实现。

redis生产常用的场景

分布式锁
限流
计数器
我们项目中有用到,主要用了3个场景:
1.缓存相关的场景,我们是做在线教育的,内容模板会有很多课程相关,这些数据在DB单表有5.600W;如果走mysql查询会很比较慢,用户体验感比较差,并发也上不去。所以我们做了些接口缓存、课程内容的对象缓存。提升了性能的同时,还解决了本地缓存不一致问题。
2.同时,我们由于它是分布式的,并且可以设置过期时间,也会用来保存用户token。因为token也是有过期时间的,用Redis来保存刚好满足。
3.我们还用它去基于日期+incr自增指令实现了一个分布式ID。因为我们的课程ID比较大,需要分库分表,数据库自增满足不了我们需求。

你可能感兴趣的:(#,Redis-缓存,redis,缓存)