别再只把 Redis 当缓存!这 5 个妙用,解决 90% 业务难题,性能直接翻倍

提到 Redis,几乎所有开发者第一反应都是 “存热点数据,减轻数据库压力”—— 说白了就是当缓存用。但前阵子帮粉丝优化项目时,发现一个离谱问题:他们用 MySQL 存 “用户在线状态”,每次前端刷新都查库,高并发时接口延迟飙到 800ms,数据库直接被查崩。

我只用 Redis 的 String 类型改了几行代码,延迟瞬间压到 10ms,数据库压力减了 99%。其实 Redis 根本不是 “单一缓存工具”,它的 5 大数据结构藏着太多 “黑科技”,能轻松解决很多 MySQL、RabbitMQ 搞不定的难题。今天就拆解 Redis 的 5 个超实用冷门用法,每个都附代码和案例,看完你会发现:之前踩的很多坑,用 Redis 早就能解决!

一、妙用 1:用户在线状态 —— 比 MySQL 快 100 倍,高并发不崩

业务痛点:社交、IM 类 APP 要显示 “用户是否在线”,用 MySQL 存 is_online 字段,查一次至少 10ms,1 万用户同时查直接卡爆,数据库 CPU 飙升到 90%。

Redis 方案:用 String 类型存 “用户 ID - 在线状态”,配合过期时间自动处理 “用户强杀进程” 等异常离线场景,10ms 内返回结果,数据库零压力。

实操代码(Java):

// 1. 用户登录,标记在线(30秒过期,前端20秒发1次心跳续期)

redisTemplate.opsForValue().set("online:user:" + userId, "1", 30, TimeUnit.SECONDS);

// 2. 心跳续期(避免用户没退出但key过期)

redisTemplate.opsForValue().getAndExpire("online:user:" + userId, 30, TimeUnit.SECONDS);

// 3. 判断用户是否在线(比MySQL快100倍)

boolean isOnline = redisTemplate.hasKey("online:user:" + userId);

System.out.println(isOnline ? "用户在线" : "用户离线");

// 4. 用户主动退出,删除key

redisTemplate.delete("online:user:" + userId);

效果对比:

方案单次查询耗时1 万用户并发延迟数据库压力

MySQL10-50ms800ms100%

Redis0.1-1ms10ms0%

粉丝项目改完后,“在线状态” 接口 QPS 从 500 涨到 10 万,数据库 CPU 直接降到 5%,再也没出现过卡顿。

二、妙用 2:分布式锁 —— 秒杀防超卖,不用额外部署组件

业务痛点:微服务多实例抢资源(比如秒杀扣库存、生成订单号),容易出现超卖、重复订单,用 ZooKeeper 太复杂,中小团队扛不住运维压力。

Redis 方案:用 SetNX(Set if Not Exists)命令实现轻量级分布式锁,谁先存成功谁拿锁,30 秒自动释放防死锁,不用额外部署组件。

实操代码(Java):

// 锁key=资源标识(比如订单ID),value=唯一UUID(防误删别人的锁)

String lockKey = "lock:order:" + orderId;

String lockValue = UUID.randomUUID().toString();

// 1. 尝试拿锁(30秒过期,避免服务崩了锁不释放)

Boolean hasLock = redisTemplate.opsForValue()

        .setIfAbsent(lockKey, lockValue, 30, TimeUnit.SECONDS);

if (hasLock) {

    try {

        // 2. 拿锁成功,执行核心业务(扣库存、创建订单)

        reduceStock(); // 扣减商品库存

        createOrder(); // 生成订单

    } finally {

        // 3. 释放锁(用value判断,避免删错锁)

        String currentValue = redisTemplate.opsForValue().get(lockKey);

        if (lockValue.equals(currentValue)) {

            redisTemplate.delete(lockKey);

        }

    }

} else {

    // 4. 没拿到锁,提示用户稍后再试

    return "当前操作人数过多,请稍后重试";

}

实战案例:

某电商用这个方案做秒杀,10 万用户抢 1000 件商品,零超卖、零重复订单,锁的获取 / 释放延迟都在 1ms 以内,比 RabbitMQ 的分布式锁轻量太多,中小团队直接能用。

三、妙用 3:实时排行榜 —— 销量、积分排名,秒级更新不用等

业务痛点:游戏积分榜、电商销量榜,用 MySQL 的 order by 排序,10 万条数据查一次要 100ms,实时更新根本不可能,用户看到的排名总是滞后。

Redis 方案:用 Sorted Set(有序集合),元素存商品 / 用户 ID,分数存销量 / 积分,Redis 自动按分数排序,查排名只要 2ms,更新销量后排名秒级刷新。

实操代码(Java):

// 1. 初始化商品销量(商品101销量100,商品102销量200)

redisTemplate.opsForZSet().add("rank:sales:product", "prod101", 100);

redisTemplate.opsForZSet().add("rank:sales:product", "prod102", 200);

// 2. 商品101销量+1(实时更新排名)

redisTemplate.opsForZSet().incrementScore("rank:sales:product", "prod101", 1);

// 3. 查销量前10名(降序,分数高的排前面)

Set<String> top10Products = redisTemplate.opsForZSet()

        .reverseRange("rank:sales:product", 0, 9); // 0-9表示前10名

System.out.println("销量前10商品:" + top10Products);

// 4. 查商品101的排名(第1名返回0,加1才是实际排名)

long rank = redisTemplate.opsForZSet()

        .reverseRank("rank:sales:product", "prod101");

System.out.println("商品101排名:第" + (rank + 1) + "名");

// 5. 查商品101的销量(分数就是销量)

Double sales = redisTemplate.opsForZSet().score("rank:sales:product", "prod101");

System.out.println("商品101销量:" + sales.intValue() + "件");

核心优势:

实时性:销量变了分数跟着变,排名秒级刷新,用户看到的永远是最新数据;

灵活性:既能查前 N 名,也能查某商品的排名和销量,不用写复杂 SQL。

四、妙用 4:接口限流 —— 防止被刷爆,短信费、数据库都保住

业务痛点:短信验证码、登录接口被恶意刷,短信费一天烧几千,数据库被频繁查询拖垮,正常用户反而用不了。

Redis 方案:用 String 做固定窗口限流,或用 Sorted Set 做滑动窗口限流,1 分钟最多允许 N 次请求,超了直接拒绝,从源头防刷。

场景 1:固定窗口限流(1 分钟最多 10 条短信)

// 限流key:接口名+用户ID(按用户限流,避免误伤正常用户)

String limitKey = "limit:sms:" + userId;

// 1. 计数+1,第一次请求设置1分钟过期

Long count = redisTemplate.opsForValue().increment(limitKey, 1);

if (count == 1) {

    redisTemplate.expire(limitKey, 1, TimeUnit.MINUTES);

}

// 2. 超过限制,拒绝请求

if (count > 10) {

    return "1分钟内最多发送10条短信,请稍后再试";

}

// 3. 没超限制,发送短信

sendSms();

场景 2:滑动窗口限流(更精准,避免 “窗口切换突发请求”)

String limitKey = "limit:login:" + userId;

long now = System.currentTimeMillis(); // 当前时间戳

int windowSize = 60 * 1000; // 窗口大小1分钟(60000毫秒)

int maxCount = 5; // 1分钟最多5次登录请求

// 1. 删除1分钟前的旧请求(只保留窗口内的数据)

redisTemplate.opsForZSet().removeRangeByScore(limitKey, 0, now - windowSize);

// 2. 统计当前窗口内的请求数

Long count = redisTemplate.opsForZSet().zCard(limitKey);

if (count >= maxCount) {

    return "登录请求过于频繁,请1分钟后再试";

}

// 3. 记录当前请求时间戳

redisTemplate.opsForZSet().add(limitKey, UUID.randomUUID().toString(), now);

// 设置key过期时间(比窗口大一点,避免内存占用)

redisTemplate.expire(limitKey, 2, TimeUnit.MINUTES);

// 4. 执行登录逻辑

login();

实际效果:

某 APP 用这个方案防刷后,短信接口被刷量从每天 10 万次降到 1 万次,短信费省了 90%,登录接口延迟从 500ms 降到 20ms,正常用户体验大幅提升。

五、妙用 5:轻量级消息队列 —— 不用 RabbitMQ,中小团队直接用

业务痛点:订单创建后要发通知、写日志,用 RabbitMQ 要部署集群,运维成本高;用同步调用又会拖慢接口,用户下单要等好几秒。

Redis 方案:用 List 类型做消息队列,lpush(左推)往队列存消息,brpop(右阻塞拉取)从队列取消息,不用额外部署组件,轻量又好用。

实操代码:

1. 生产者(发消息,比如订单创建后发通知)

// 消息队列key

String queueKey = "queue:order:notify";

// 消息内容:订单ID、用户ID(JSON格式,方便消费者解析)

String message = "{\"orderId\":\"123456\",\"userId\":\"789\"}";

// 左推消息到队列(生产者)

redisTemplate.opsForList().leftPush(queueKey, message);

System.out.println("订单通知消息发送成功:" + message);

2. 消费者(拉消息,异步处理)

// 启动消费者线程,循环拉取消息

new Thread(() -> {

    String queueKey = "queue:order:notify";

    while (true) {

        try {

            // 右阻塞拉取消息(没消息时阻塞,避免空轮询浪费资源)

            // 第三个参数0秒:表示一直等,直到有消息才返回

            List<String> messages = redisTemplate.opsForList()

                    .rightPop(queueKey, 0, TimeUnit.SECONDS);


            if (messages != null && !messages.isEmpty()) {

                String msg = messages.get(0);

                // 解析消息,执行异步任务(发短信/推送通知)

                sendOrderNotify(msg);

                System.out.println("处理订单通知消息:" + msg);

            }

        } catch (Exception e) {

            // 出错后睡1秒再重试,避免死循环

            e.printStackTrace();

            try {

                Thread.sleep(1000);

            } catch (InterruptedException ie) {

                ie.printStackTrace();

            }

        }

    }

}).start();

适合场景:

轻量级异步需求:通知、日志、统计,不用复杂的消息确认机制;

中小团队:省去 RabbitMQ 的部署和运维成本,降低技术栈复杂度。

我之前做的小项目,用这个方案每天处理 10 万条订单通知,零丢失、零延迟,用户下单后秒返回,体验比同步调用好太多。

最后:Redis 这些用法,你可能也需要

除了上面 5 个,Redis 还有很多实用功能:

Hash 存用户信息:比 String 省 50% 内存,比如存用户昵称、头像、手机号;

Set 做好友关系:查共同好友用 intersect 命令,比 MySQL 的 join 快 10 倍;

Geo 做附近的人:外卖、打车 APP 查 “周边商家 / 司机”,秒级返回结果;

但核心是别把 Redis 局限在 “缓存” 里。它本质是 “高性能键值数据库”,不同数据结构对应不同业务场景 —— 很多时候你熬夜解决的问题,可能用 Redis 几行代码就搞定了。

当然 Redis 也不是万能的:要强事务、消息必达的场景,还是得用 MySQL、RabbitMQ;但中小团队 80% 的业务场景,Redis 完全能扛住,还能少踩很多坑。

你之前用 Redis 解决过什么难题?欢迎在评论区分享,也可以提问题,我帮你出方案!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容