工作中用Redis最多的10种场景

作者:苏三说技术
链接:https://juejin.cn/post/7325132133168971813

前言

Redis是一种非常优秀的基于KV的键值对缓存数据库,有非常不错的性能和稳定性,无论是在工作中,还是在面试中,都经常会出现。因此,有必要深入研究并在工作中使用它。今天,我将与大家分享我在实际工作中如何使用Redis的。

1. 统计访问次数

官方网站首页需统计访问次数,使用Redis可简化操作。
定义Key值为OFFICIAL_INDEX_VISIT_COUNT,使用incr命令给value加1

incr OFFICIAL_INDEX_VISIT_COUNT

可以用incrby命令加1,如下一次性加5:

incrby OFFICIAL_INDEX_VISIT_COUNT 5

2. 获取分类树菜单

在很多网站都有分类树的功能,菜单的树展示形式,如果没有静态html页面的话就需要调用接口,树一般都会递归去实现获取,为了性能考虑一般我们都会将菜单树的数据缓存,将树的json数据缓存到Redis中,后面再读取菜单的时候就不用重新计算,直接读取Redis即可。不过,如果是菜单树经常变动的场景不适合此。

所以我们可以使用定时将菜单树的数据异步缓存到Redis中。
定义一个key,比如:MALL_CATEGORY_TREE

然后接口中直接使用 MALL_CATEGORY_TREE 这个key从缓存中获取数据即可。

可以直接用key/value字符串保存数据。

不过需要注意的是,如果分类树的数据非常多可能会出现大key的问题。

3. 做分布式锁

使用Redis做分布式锁应该是Redis的使用者最经常听说的一个场景了,Redis实现的分布式锁相对于其他的分布式锁,性能更好,相信大家也听过什么Redis+Lua王炸组合什么的。

我们使用下面这段代码可以加锁:

try{
  String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
  if ("OK".equals(result)) {
      return true;
  }
  return false;
} finally {
    unlock(lockKey);
}  

但上面这段代码在有些场景下,会有一些问题,释放锁可能会释放了别人的锁。所以优化的点还有很多,比如区分谁加的锁,就释放自己的锁,不能释放别人的锁,可以在锁信息里加入线程ID来区分。

说实话Redis分布式锁虽说很常用,但坑也挺多的,如果用不好的话,很容易踩坑。

4. 做排行榜

网站的排行版,微博的排版行、各种社交APP的排行榜,商城的销量排行榜,游戏的巅峰排名等等。

通常情况下,我们可以使用Sorted Set保存排行榜的数据。

使用ZADD可以添加排行榜的数据,使用ZRANGE可以获取排行榜的数据。

例如:

ZADD rank:score 100 "奈飞"
ZADD rank:score 90 "youtobe"
ZADD rank:score 80 "小破站"
ZRANGE rank:score 0 -1 WITHSCORES

返回数据:

1) "奈飞"
2) "100"
3) "youtobe"
4) "90"
5) "小破站"
6) "80"

5. 记录用户登录状态

系统登录态缓存。用户登录系统之后,缓存用户登录信息。

使用Redis保存用户登录状态,有个好处是它可以设置一个过期时间,这样可以实现用户Token的到期已经后续的续期操作等。
比如:该时间可以设置成30分钟。

jedis.set(userId, userInfo, 1800);

在Redis内部有专门的job,会将过期的数据删除,也有获取数据时实时删除的逻辑。

后面本文更新Redis过期策略,欢迎关注。

6. 限流

使用Redis也可以实现限流

最简单的,保存用户IP,限制该IP一分钟内的访问次数,超过该次数限制该IP访问,设置过期时间,一天之后到期允许该IP继续访问。

7. 位统计

在网站的统计页面中,统计一周连续登录用户或者一个月内登录过的用户。
如果使用关系型数据库的话很麻烦,但是使用Redis的Bitmap可以很方便的实现类似功能。

bitmap 是二进制的 byte 数组,也可以简单理解成是一个普通字符串。它将二进制数据存储在byte数组中以达到存储数据的目的。

保存数据命令使用setbit,语法:

setbit key offset value

具体示例:

setbit user:view:2024-04-01 123456 1

bitmap数组中设置了用户 id=123456 的登录状态为1,标记2024-04-01已登录。
然后通过命令getbit获取数据,语法:

getbit key offset

具体示例:

getbit user:view:2024-04-01 123456

如果获取的值是1,说明这一天登录了。

如果我们想统计一周内连续登录的用户,只需要遍历用户id,根据日期中数组中去查询状态即可。

8. 缓存加速

这个和上面分类的菜单树缓存差不多,都是把需要使用频繁访问的数据缓存在Redis中,通过缓存读取策略进行控制缓存的读取存入。

1、查询订单,缓存中存在,直接返回数据。

2、缓存中不存在,查询数据库,如果数据库中数据存在,将数据保存到缓存中,返回数据。

3、如果数据库数据不存在,返回用户数据不存在。

流程图如下:

但使用缓存加速的业务场景,需要注意一下,可能会出现:缓存击穿、穿透和雪崩等问题,感兴趣的小伙伴,可以看看我的另一篇文章《美团面试拷打:Redis 缓存穿透、缓存击穿、缓存雪崩区别和解决方案》,里面有非常详细的介绍。

9. 做消息队列

我们说起队列经常想到是:KafkaRabbitMQRocketMQ 等这些分布式消息队列。

Redis 实现消息队列是使用的PubSub功能,PubSub(发布订阅)是 Redis2.0 版本引入的消息传递模型。

顾名思义,消费者可以订阅一个或多个channel,生产者向对应channel发送消息后,所有订阅者都能收到相关消息。对应channel发送消息后,所有订阅者都能收到相关消息。

java 代码中可以实现MessageListener接口,来消费队列中的消息。

@Slf4j
@Component
public class RedisMessageListenerListener implements MessageListener {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String channel = new String(pattern);
        RedisSerializer<?> valueSerializer = redisTemplate.getValueSerializer();
        Object deserialize = valueSerializer.deserialize(message.getBody());
        if (deserialize == null) return;
        String md5DigestAsHex = DigestUtils.md5DigestAsHex(deserialize.toString().getBytes(StandardCharsets.UTF_8));
        Boolean result = redisTemplate.opsForValue().setIfAbsent(md5DigestAsHex, "1", 20, TimeUnit.SECONDS);
        if (Boolean.TRUE.equals(result)) {
            log.info("接收的结果:{}", deserialize.toString());
        } else {
            log.info("其他服务处理中");
        }
    }
}

10. 生成全局ID

在有些需要生成全局ID的业务场景,其实也可以使用Redis。

可以使用 incrby 命令,利用原子性操作,可以执行下面这个命令:

incrby userid 10000

在分库分表的场景,对于有些批量操作,我们可以从Redis中,一次性拿一批id出来,然后给业务系统使用。

如果这篇文章对您有所帮助,或者有所启发的话,帮忙点个关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

wx 搜索《醉鱼Java》,回复面试、获取2024面试资料

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值