业务场景举例
场景一:秒杀/限量抢购
涉及工具: RLock + RAtomicLong
问题: 库存只有 100 件,瞬间几万请求涌入,如何保证不超卖?
思路:
1. 系统启动时:RAtomicLong stock = 100
2. 请求进来先 tryLock(非阻塞,抢不到直接返回"已售罄")
3. 拿到锁后:
- 读取 stock.get()
- 若 > 0 则 stock.decrementAndGet(),写订单
- 若 = 0 直接返回售罄
4. finally 释放锁也可以用
RSemaphore替代,许可证数量 = 库存数量,acquire 成功即代表抢到,语义更自然。
场景二:用户登录 Session 共享
涉及工具: RMapCache
问题: 多台服务器部署,用户登录后请求可能打到不同机器,Session 不能只存本地。
思路:
1. 用户登录成功,生成 token
2. RMapCache<String, UserInfo> sessionMap
sessionMap.put(token, userInfo, 30, TimeUnit.MINUTES)
// 自带 TTL,30 分钟无操作自动过期
3. 每次请求拦截器中:
- sessionMap.get(token) 取用户信息
- 取到则 sessionMap.updateEntryExpiration() 续期
- 取不到则跳转登录比手写
RedisTemplate更省心,TTL 续期、序列化都封装好了。
场景三:接口防重复提交
涉及工具: RMapCache 或 RBucket + RLock
问题: 用户快速点击两次"提交订单",后端收到两条相同请求,如何幂等?
思路:
1. 前端提交时携带一个幂等 key(如表单 token)
2. 后端收到请求:
- RLock lock = redisson.getLock("idempotent:" + idempotentKey)
- tryLock 失败 → 说明有相同请求正在处理,直接返回"请勿重复提交"
- tryLock 成功 →
检查 RBucket<Boolean> processed 是否已存在
存在 → 返回上次结果
不存在 → 执行业务,完成后 set processed=true(TTL 24h)
3. finally 释放锁场景四:排行榜(积分榜/销量榜)
涉及工具: RScoredSortedSet
问题: 游戏积分实时排行,支持查询某用户排名、前 N 名列表。
思路:
1. 用户得分时:
scoredSortedSet.addScore("userId_123", deltaScore)
// 底层是 Redis ZINCRBY,原子操作无需加锁
2. 查前 10 名:
scoredSortedSet.entryRangeReversed(0, 9)
// 返回 ScoredEntry 列表,包含 userId 和 score
3. 查某用户排名:
scoredSortedSet.reverseRank("userId_123")
// 从高到低的名次,O(log N)场景五:分布式任务调度(同一任务只跑一次)
涉及工具: RLock / RScheduledExecutorService
问题: 定时任务部署了 3 个节点,每天凌晨对账,只能跑一次,不能重复执行。
思路:
// 方案 A:用锁抢占
@Scheduled(cron = "0 0 2 * * ?")
public void reconcile() {
RLock lock = redisson.getLock("task:reconcile:lock");
// 抢到锁的节点执行,其他节点 tryLock 返回 false 直接跳过
if (lock.tryLock()) {
try {
doReconcile();
} finally {
lock.unlock();
}
}
}
// 方案 B:用 RScheduledExecutorService
// 把任务提交给集群,由 Redisson 选一个节点执行,天然单次
RScheduledExecutorService executor = redisson.getExecutorService("task-pool");
executor.scheduleAtFixedRate(new ReconcileTask(), 0, 1, TimeUnit.DAYS);场景六:限流(API 调用频率控制)
涉及工具: RRateLimiter
问题: 对外开放的 API,每个用户每分钟最多调用 100 次。
思路:
// 初始化(通常在用户首次调用时)
RRateLimiter limiter = redisson.getRateLimiter("ratelimit:userId:" + userId);
limiter.trySetRate(RateType.PER_CLIENT, 100, 1, RateIntervalUnit.MINUTES);
// 每次请求进来
if (!limiter.tryAcquire()) {
throw new TooManyRequestsException("调用频率超限");
}
// 通过则正常执行业务底层是令牌桶算法,由 Redisson 用 Lua Script + Redis 实现,天然分布式,多节点共享同一个限流器。
场景七:缓存击穿防护
涉及工具: RLock + RMapCache
问题: 热点 key 过期瞬间,大量请求同时穿透到数据库(缓存击穿)。
思路:
public UserInfo getUserInfo(Long userId) {
String cacheKey = "user:" + userId;
// 1. 先查缓存
UserInfo info = cache.get(cacheKey);
if (info != null) return info;
// 2. 缓存未命中,用互斥锁防止击穿
RLock lock = redisson.getLock("rebuild:" + cacheKey);
lock.lock();
try {
// 3. Double Check(可能锁等待期间已被其他线程重建)
info = cache.get(cacheKey);
if (info != null) return info;
// 4. 真正查数据库并回填缓存
info = userDao.findById(userId);
cache.put(cacheKey, info, 10, TimeUnit.MINUTES);
return info;
} finally {
lock.unlock();
}
}整体规律总结
| 场景类型 | 核心工具 | 关键思想 |
|---|---|---|
| 库存/名额竞争 | RLock / RSemaphore | 互斥或许可证控制并发 |
| 状态共享 | RMapCache / RBucket | 替代本地缓存,加 TTL |
| 幂等/防重 | RLock + RBucket | 锁保原子,桶记状态 |
| 排行/计数 | RScoredSortedSet / RAtomicLong | 原子更新,无需额外锁 |
| 单次任务 | RLock / RScheduledExecutorService | 抢锁即抢执行权 |
| 频率控制 | RRateLimiter | 令牌桶,开箱即用 |
| 缓存保护 | RLock + 双重检查 | 用锁串行化重建过程 |