系统不崩的秘籍:Redis的六大非缓存玩法,支撑高并发流量就靠它!

一、分布式锁

秒杀高并发排队神器,

当年做电商秒杀,数据库行锁直接被打到 奄奄一息

Redis 一出马,线程乖乖排队,老板再也不用担心超卖。

复制
// Maven 依赖 <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.23.4</version> </dependency> Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); RLock lock = redisson.getLock("stock:1001"); try { // **30 秒内抢锁,锁 30 秒后自动释放** if (lock.tryLock(30, 30, TimeUnit.SECONDS)) { updateStockInDB(); // 真正的减库存逻辑 } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); // **一定记得手动释放** } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.

注解

1. tryLock 带时间参数,防止死锁。

2. finally 释放锁,避免“占着茅坑不拉屎”。

3. 集群场景用 RedLock,主节点挂了也能继续嗨。

二、计数器:2 万 QPS 的救火队长

直播在线人数用数据库 UPDATE

直接 200 QPS 就跪。

Redis 的 INCR 让在线人数 像坐火箭一样飙升

复制
Jedis jedis = new Jedis("redis://127.0.0.1:6379"); String key = "rate_limit:user:" + userId + ":minute"; long count = jedis.incr(key); if (count == 1) { jedis.expire(key, 60); // **首次创建,设 60 秒过期** } if (count > 100) { throw new RuntimeException("手速太快,歇会儿!"); }1.2.3.4.5.6.7.8.9.

注解

1. incr 原子自增,天然抗并发。

2. expire 只在第一次设置,避免每次请求都刷新 TTL。

3. 100 次/分钟阈值可配置,灵活限流

三、排行榜:ZSET 的凡尔赛舞台

年度博主排行?数据库跑 3 小时,ZSET 5 分钟搞定。

关键是还能 实时更新!。

复制
// 点赞一次,分数 +1 redisTemplate.opsForZSet() .incrementScore("blog:like:rank", "user:1001", 1); // 取前 10 Set<ZSetOperations.TypedTuple<String>> top10 = redisTemplate.opsForZSet() .reverseRangeWithScores("blog:like:rank", 0, 9); // 查个人排名 Long rank = redisTemplate.opsForZSet() .reverseRank("blog:like:rank", "user:1001");1.2.3.4.5.6.7.8.9.10.11.12.

注解

1. incrementScore 原子操作,并发点赞不丢分

2. reverseRangeWithScores 一次取出成员和分数,减少网络往返

3. reverseRank 查排行 O(log n),再多人也不怕

四、轻量消息队列:异步快递员

订单高峰 10 倍流量?

把订单先丢 Redis List,后台慢慢消费,爆仓不存在的

复制
// 生产者 jedis.lpush("order_queue", JSON.toJSONString(order)); // 消费者 while (true) { List<String> msg = jedis.brpop(0, "order_queue"); if (msg != null) { try { processOrder(msg.get(1)); } catch (Exception e) { // 失败丢到重试队列 jedis.lpush("order_retry_queue", msg.get(1)); } } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.

注解

1. brpop 阻塞读取,CPU 不空转

2. 失败消息进入 retry 队列,可配合延时策略。

3. List 队列简单可靠,但 没有 ACK,需自己实现重试。

五、会话共享:分布式登录管家

用户在 A 机器登录,跳到 B 机器就掉线?

用 Redis 做 统一 Session 仓库妈妈再也不用担心我踢用户下线

复制
# application.yml spring: session: store-type: redis timeout: 30m redis: host: 127.0.0.1 port: 63791.2.3.4.5.6.7.8.

注解

1. spring-session-data-redis 一行配置搞定。

2. SessionID 随机的 UUID + 签名,防伪造。

3. 每次登录重新生成 SessionID,旧 Session 秒失效

六、地理位置:附近门店秒查

“附近 5 公里有啥好吃的?”

Redis GEO 一出手,5 倍速出结果

复制
// 添加门店坐标 redisTemplate.opsForGeo() .add("shop:locations", new Point(116.4074, 39.9042), "shop:1001"); // 查 5 公里内,由近到远 GeoResults<GeoLocation<String>> results = redisTemplate.opsForGeo() .radius("shop:locations", new Circle(new Point(116.4074, 39.9042), Metrics.KILOMETERS.toMeters(5)), GeoRadiusCommandArgs.newGeoRadiusArgs() .includeDistance() .sortAscending()); results.getContent().forEach(r -> System.out.println(r.getContent().getName() + " 离你 " + r.getDistance().getValue() + " 米"));1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.

注解

1. GEOADD 一次可插多条,批量效率高

2. GEORADIUS 默认 O(N),但 Redis 用 geohash + 跳表N<10W 稳稳的

3. 距离单位支持 m/km/ft/mi国际化项目无压力

七、野路子合集:老码农私货7.1 滑动窗口限流
复制
String key = "rate_limit:user:" + userId; long now = System.currentTimeMillis(); // 清理 60 秒前记录 redisTemplate.opsForZSet() .removeRangeByScore(key, 0, now - 60000); // 记录当前时间戳 redisTemplate.opsForZSet().add(key, String.valueOf(now), now); // 统计窗口内请求数 Long cnt = redisTemplate.opsForZSet().zCard(key); if (cnt > 50) throw new RuntimeException("刷太快,小黑屋见!");1.2.3.4.5.6.7.8.9.10.

注解

1. ZSET 按时间排序,天然滑动窗口。

2. removeRangeByScore 批量清理,O(log n)

3. zCard 计数,内存占用极低

7.2 乐观锁抢购
复制
jedis.watch("stock:1001"); int stock = Integer.parseInt(jedis.get("stock:1001")); if (stock > 0) { Transaction tx = jedis.multi(); tx.decr("stock:1001"); List<Object> res = tx.exec(); if (res == null) { // **被其他客户端改了,重试** } }1.2.3.4.5.6.7.8.9.10.

注解

1. watch + multi + exec 保证 原子减库存

2. exec 返回 null 即版本冲突,自旋重试即可

3. 适合 秒杀库存少、冲突高 的场景。

至此分享完毕,希望以上内容对你有所帮助!

阅读剩余
THE END