提到 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 解决过什么难题?欢迎在评论区分享,也可以提问题,我帮你出方案!