上一篇我们详解了Redis监控工具(Redis-Stat+Redis-Exporter),搭建了全天候监控体系,能提前预警故障、快速定位问题。但Redis的核心价值,远不止做缓存和监控,更是支撑高并发、实现复杂业务的利器。

无论是电商秒杀、接口限流防刷,还是社区排行榜、热度排序,这些高频业务场景都离不开Redis。本篇就聚焦秒杀、接口限流、实时排行榜三大真实业务,从业务痛点、方案设计、核心代码到避坑指南,手把手教你用Redis落地实战,直接复用进生产项目。

核心思路:利用Redis高性能、原子操作、丰富数据类型的特性,承接高并发流量、分担数据库压力,实现业务的高效稳定运行。

一、场景一:电商秒杀 —— 扛住瞬时高并发,杜绝超卖

秒杀业务痛点极其突出:瞬时QPS暴涨、库存超卖、数据库被打垮、恶意刷单,传统数据库架构完全扛不住。Redis凭借内存读写、原子操作、分布式锁三大特性,成为秒杀架构的核心。

1. 秒杀核心方案设计

  • 库存预热:活动开始前,将商品库存从MySQL同步到Redis(String结构存储),提前加载热点数据
  • 流量拦截:Redis层做限流、库存校验、用户限购校验,提前拦截无效请求,避免流量击穿到数据库
  • 原子扣减:用Redis DECRBY原子命令扣减库存,单线程执行无锁竞争,从根源避免超卖
  • 异步下单:扣减成功后,将请求写入MQ异步同步数据库,削峰填谷,保护数据库稳定性

2. 核心代码实现(Java)

/**
 * 秒杀核心逻辑:Redis原子扣减库存
 */
public Result secKill(Long userId, Long goodsId) {
    // 1. 构造规范Key,便于后续维护和排查
    String stockKey = "seckill:stock:" + goodsId;
    String userLimitKey = "seckill:user:" + goodsId + ":" + userId;

    // 2. 判断用户是否已抢购(限购1件,防止恶意刷单)
    Boolean hasBuy = redisTemplate.hasKey(userLimitKey);
    if (Boolean.TRUE.equals(hasBuy)) {
        return Result.fail("您已抢购过该商品,限购1件");
    }

    // 3. 原子扣减库存(核心:DECRBY保证原子性,杜绝超卖)
    Long remainStock = redisTemplate.opsForValue().decrement(stockKey, 1);

    // 4. 库存不足判断,及时回滚避免库存负数
    if (remainStock < 0) {
        redisTemplate.opsForValue().increment(stockKey, 1);
        return Result.fail("商品已售罄");
    }

    // 5. 标记用户已抢购,设置过期时间(活动结束后自动清理)
    redisTemplate.opsForValue().set(userLimitKey, "1", 24, TimeUnit.HOURS);

    // 6. 异步发送MQ,同步数据库订单,避免同步写库阻塞
    mqSender.sendSecKillMsg(userId, goodsId);

    return Result.success("抢购成功,请尽快支付");
}

/**
 * 活动前:库存预热到Redis,提前加载避免活动时卡顿
 */
public void initStockToRedis(Long goodsId, Integer stock) {
    String stockKey = "seckill:stock:" + goodsId;
    redisTemplate.opsForValue().set(stockKey, stock);
}

3. 秒杀避坑要点

  • 严禁直接用数据库扣减库存,必须在Redis层完成库存校验与扣减,杜绝数据库雪崩
  • 强制加入用户限购逻辑,结合用户ID/设备ID做限制,防范恶意刷单
  • 库存扣减为负时,立即执行回滚操作,避免库存数据异常
  • 配合分布式锁加固,防止极端并发下同一用户重复抢购
  • 活动结束后及时清理Redis临时数据,释放内存空间

二、场景二:接口限流 —— 防刷防攻击,保护服务稳定性

接口被恶意刷请求、爬虫频繁调用,会导致服务资源耗尽、正常请求无法响应。利用Redis的计数器+过期时间,可快速实现多种限流策略,成本低、见效快,适配绝大多数业务场景。

1. 常用限流策略:固定窗口计数器(Redis实现)

核心逻辑:单位时间内,限制单个用户/IP的请求次数,超过阈值直接拦截,实现简单、性能高效,适用于绝大多数接口防刷、防攻击场景。

2. 核心代码实现(通用限流)

/**
 * Redis接口限流:固定窗口计数器
 * @param key 限流标识(用户ID/IP+接口路径,保证唯一性)
 * @param limitCount 单位时间限制次数
 * @param time 窗口时间(秒)
 */
public boolean allowRequest(String key, int limitCount, int time) {
    String redisKey = "request:limit:" + key;
    // 1. 原子自增计数,无并发安全问题
    Long count = redisTemplate.opsForValue().increment(redisKey);
    // 2. 首次请求设置过期时间,窗口关闭后自动重置计数
    if (count == 1) {
        redisTemplate.expire(redisKey, time, TimeUnit.SECONDS);
    }
    // 3. 判断是否超过阈值,返回是否放行
    return count <= limitCount;
}

// 业务使用示例:限制单个用户1分钟内最多调用60次
@GetMapping("/api/user/info")
public Result getUserInfo(Long userId, HttpServletRequest request) {
    String ip = IpUtils.getIpAddr(request);
    // 拼接唯一限流Key,区分用户+接口
    String limitKey = userId + "_" + request.getRequestURI();
    // 执行限流校验
    if (!redisLimitService.allowRequest(limitKey, 60, 60)) {
        return Result.fail("请求过于频繁,请稍后再试");
    }
    return Result.success(userService.getUserInfo(userId));
}

3. 拓展限流方案

  • IP限流:针对公共接口,用客户端IP做限流标识,拦截恶意IP批量请求
  • 滑动窗口限流:用Redis Sorted Set实现,解决固定窗口临界值突刺问题,限流更精准
  • 令牌桶限流:结合Redis List实现,支持突发流量控制,兼顾限流与业务体验

三、场景三:实时排行榜 —— 热度排序、积分榜单

游戏积分、主播热度、商品销量、帖子排行、用户等级等业务,需要实时排序、快速查询排名、支持分数动态更新。Redis的Sorted Set(ZSet)有序集合,自带分数排序属性,查询效率极高,完美适配实时排行榜场景。

1. ZSet核心原理

  • 每个元素绑定一个score(分数),Redis根据分数自动完成升序/降序排列
  • 支持分数累加、排名查询、范围榜单查询、元素删除等常用操作
  • 时间复杂度低,百万级数据的排序、查询操作均可实现毫秒级响应
  • 天然支持去重,同一用户多次更新仅保留最新分数,无需额外处理

2. 核心代码实现(积分排行榜)

/**
 * 排行榜通用Key
 */
private static final String RANK_KEY = "rank:user:score";

/**
 * 1. 更新用户积分(支持新增/分数累加)
 */
public void updateUserScore(Long userId, Integer score) {
    redisTemplate.opsForZSet().incrementScore(RANK_KEY, userId.toString(), score);
}

/**
 * 2. 查询用户排名(降序:0为第一名,返回值+1适配日常展示)
 */
public Long getUserRank(Long userId) {
    Long rank = redisTemplate.opsForZSet().reverseRank(RANK_KEY, userId.toString());
    // 未上榜返回-1,上榜则排名+1(0→1,1→2)
    return rank == null ? -1 : rank + 1;
}

/**
 * 3. 查询TopN排行榜(默认前10名,带排名+分数+用户ID)
 */
public List<Map<String, Object>> getTopRank(int topN) {
    // reverseRangeWithScores:降序获取带分数的元素集合
    Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet()
            .reverseRangeWithScores(RANK_KEY, 0, topN - 1);
    if (CollUtil.isEmpty(tuples)) {
        return new ArrayList<>();
    }
    List<Map<String, Object>> result = new ArrayList<>();
    int rank = 1;
    for (ZSetOperations.TypedTuple<String> tuple : tuples) {
        Map<String, Object> map = new HashMap<>();
        map.put("userId", Long.parseLong(tuple.getValue()));
        map.put("score", tuple.getScore());
        map.put("rank", rank++);
        result.add(map);
    }
    return result;
}

/**
 * 4. 清理过期榜单数据(日/周/月榜重置专用)
 */
public void clearRank() {
    redisTemplate.delete(RANK_KEY);
}

3. 排行榜拓展场景

  • 日榜/周榜/月榜:构造带时间维度的Key(如rank:20250620),定时任务重置榜单
  • 商品销量榜:score设为销量值,用户下单后实时更新,展示热销商品
  • 去重榜单:ZSet天然去重,同一用户多次操作仅保留最新分数,无需手动去重

四、三大场景核心选型总结

业务场景Redis数据类型核心命令核心价值
电商秒杀String(库存)+ String(限购标记)DECRBY、INCR、SETNX原子扣减、防超卖、扛高并发
接口限流String(计数器)INCR、EXPIRE防刷防攻击、保护服务
实时排行榜Sorted Set(ZSet)ZINCRBY、ZREVRANK、ZREVRANGE实时排序、快速查排名、高性能

落地口诀:秒杀靠原子扣减防超卖,限流靠计数过期防刷量,排行靠ZSet排序做实时,Redis承接高并发,数据库只做持久化。

总结与下篇预告

秒杀、限流、排行榜是互联网业务的三大高频场景,Redis凭借自身高性能、原子操作、丰富数据类型的特性,用极简的代码实现了高并发、高性能的业务需求,大幅降低了架构复杂度。本篇代码均可直接复用,只需根据业务微调参数、Key规则即可上线使用。

发表回复