• Redis最常见应用场景


    缓存(Cache)

    Redis的第一个应用场景是Redis作为缓存对象来加速Web应用的访问。

    在该场景下,有一些存储于数据库中的数据会被频繁访问,如果频繁的访问数据库,数据库负载会升高,同时由于数据库IO比较慢,应用程序的响应会比较差。此时,如果引入Redis来存储这些被频繁访问的数据,就可以有效的降低数据库的负载,同时提高应用程序的请求响应。

    会话存储(Session) 

    使用Redis来存储会话(Session)数据,可以实现在无状态的服务器之间共享用户相关的状态数据数据。

    当用户登录Web应用时候,将会话数据存储于Redis,并将唯一的会话ID(Session ID)返回到客户端的Cookie中。当用户再向应用发送请求时,会将此会话ID包含在请求中。无状态的Web服务器,根据这个会话ID从Redis中搜索相关的会话数据来进一步请求处理。

    这里需要注意的是,Redis是内存数据库,如果采用单实例部署。那么当Redis服务器故障重启之后,所有的Session会话会消失,用户不得不重新登录来获取新的Session。所以,当拿Redis来存储Session的时候,建议采用主从的集群模式来部署。这样,即使主服务器挂了,马上有从库接管流量,不影响用户的使用。

    分布式锁(Distributed Lock) 

    当我们在应用中部署了多个节点,这些节点需要操作同一个资源的时候会存在竞争。此时,我们可以使用Redis来作为分布式锁,以协调多个节点对共享资源的操作。

     这里主要是用Redis的原子操作命令:SETNX,该命令仅允许key不存在的时候才能设置key。

    下图展示了一个简单用例。Client 1通过SETNX命令尝试创建lock 1234abcd。如果当前还没有这个key,那么将返回1。Client 1获得锁,就可以执行对共享资源的操作,操作完成之后,删除刚刚创建的lock(释放分布式锁)。如果Client 1在执行SETNX命令的时候,返回了0,说明有其他客户端占用了这key,那么等待一段时间(等其他节点释放)之后再尝试。

     上面这个简单实现虽然可以满足很多用例,但它并不具备良好的容错机制。如果要在生产上是用的话,更推荐采用一些更高质量的分布式锁实现。比如,Java平台的话,可以选择:Redisson。

    速率限制器(Rate Limiter)

    由于Redis提供了计数器功能,所以我们可以通过该能力,配合超时时间,来实现速率限制器,最常见的场景就是服务端是用的请求限流。

    一个基本的限速实现如下图:

    根据用户id或者ip来作为key,使用INCR命令来记录用户的请求数量。然后将该请求数量与允许的请求上限数量做比较,只有低于限制的时候,才会执行请求处理。如果超过限制,就拒绝请求。

    同时,请求数量的计数器需要设置一个时间窗口,比如:1分钟。也就是没过一分钟时间,计数器将被清零,重新计数。所以,当一个时间窗口中被限流之后,等到下一个时间窗口,就能恢复继续请求。以实现限制速率的效果。

    分布式限流

    补充用法:Redis DECR 命令将 key 中储存的数字值减一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。

     

    1. incr key
    2. expire key 1

    这种简单的实现,通常来说不会有问题,但在流量比较大的情况下,在时间跨度上会有流量突然飙升的风险。根本原因,就是这种时间切分方式太固定了,没有类似滑动窗口这种平滑的过度方案。

    同样是redisson的RRateLimiter,实现了与guava中类似的分布式限流工具类,使用非常便捷。下面是一个简短的例子:

    1. RRateLimiter limiter = redisson.getRateLimiter("xjjdogLimiter");
    2. // 只需要初始化一次
    3. // 每2秒钟5个许可
    4. limiter.trySetRate(RateType.OVERALL, 5, 2, RateIntervalUnit.SECONDS);
    5. // 没有可用的许可,将一直阻塞
    6. limiter.acquire(3);

     

    排行榜(Rank/Leaderboard) 

    由于Redis提供了排序集合(Sorted Sets)的功能,所以很多游戏应用采用Redis来实现各种排行榜功能。

    排序集合是唯一元素(比如:用户id)的集合,每个元素按分数排序,这样可以快速的按分数来检索元素:

    统计活跃用户数

    类似统计每天的活跃用户、用户签到、用户在线状态,这种零散的需求,实在是太多了。如果为每一个用户存储一个bool变量,那占用的空间就太多了。这种情况下,我们可以使用bitmap结构,来节省大量的存储空间。

    1. >SETBIT online:2021-07-23 3876520333 1
    2. >SETBIT online:2021-07-24 3876520333 1
    3. >GETBIT online:2021-07-23 3876520333
    4. 1
    5. >BITOP AND active online:2021-07-23 online:2021-07-24
    6. >GETBIT active 3876520333
    7. 1
    8. >DEBUG OBJECT online:2021-07-23
    9. Value at:0x7fdfde438bf0 refcount:1 encoding:raw serializedlength:5506446 lru:16410558 lru_seconds_idle:5
    10. (0.96s)

     注意,如果你的id很大,你需要先进行一次预处理,否则它会占用非常多的内存。

    bitmap包含一串连续的2进制数字,使用1bit来表示真假问题。在bitmap上,可以使用and、or、xor等位操作(bitop)。

    消息队列

    Redis可以实现简单的队列。在生产者端,使用LPUSH加入到某个列表中;在消费端,不断的使用RPOP指令取出这些数据,或者使用阻塞的BRPOP指令获取数据,适合小规模的抢购需求。

    Redis还有PUB/SUB模式,不过pubsub更适合做消息广播之类的业务。

    在Redis5.0中,增加了stream类型的数据结构。它比较类似于Kafka,有主题和消费组的概念,可以实现多播以及持久化,已经能满足大多数业务需求了。

    ​​​​​​​

    LBS应用 

    早早在Redis3.2版本,就推出了GEO功能。通过GEOADD指令追加lat、lng经纬数据,可以实现坐标之间的距离计算、包含关系计算、附近的人等功能。

    关于GEO功能,最强大的开源方案是基于PostgreSQL的PostGIS,但对于一般规模的GEO服务,redis已经足够用了。

     

    小结 

    Redis的应用非常广泛,这里仅总结了一些常见的用法。除此之外,还有很多有意思的应用,这取决于业务场景。大家可以举一反三。

  • 相关阅读:
    STL中map介绍
    用飞书写博客,并自动部署
    运行vue,浏览器出错
    米哈游(原神)一面算法原题
    【代码随想录】算法训练营 第十一天 第五章 栈与队列 Part 2
    oracle学习43-oracle导出空表
    NSS [HNCTF 2022 WEEK2]ohmywordpress(CVE-2022-0760)
    java简介
    Linux下NFS共享存储安装详细步骤
    L2-052 吉利矩阵
  • 原文地址:https://blog.csdn.net/summer_fish/article/details/133604078