Redis分布式锁实现简单秒杀功能
Posted 森林木马
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis分布式锁实现简单秒杀功能相关的知识,希望对你有一定的参考价值。
这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题。
主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了。这样就处理了多线程并发问题的同时也保证了服务器的性能的稳定。
接下来我们使用redis的分布式锁来进行枷锁处理:
我们可以在进入下单的方法后将核心的方法加锁,然后离开后进行解锁
主要三步:
加锁
核心方法
解锁
首页分布式加锁解锁工具类:
@Component public class RedisLock { private static Logger logger = LoggerFactory.getLogger(RedisLock.class); @Autowired private StringRedisTemplate redisTemplate; /** * 加锁 * @param key * @param value 当前事件+超时事件 * @return */ public boolean lock(String key,String value){ //加锁成功 if (redisTemplate.opsForValue().setIfAbsent(key,value)){ return true; } //假如currentValue=A先占用了锁 其他两个线程的value都是B,保证其中一个线程拿到锁 String currentValue = redisTemplate.opsForValue().get(key); //锁过期 防止出现死锁 if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){ //获取上一步锁的时间 String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){ return true; } } return false; } /** * 解锁 * @param key * @param value */ public void unlock(String key,String value){ try { String currentValue = redisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){ redisTemplate.opsForValue().getOperations().delete(key); } }catch (Exception e){ logger.error("【redis分布式锁】 解锁异常,{}",e); } } }
具体使用的逻辑代码功能:
@Service public class SecKillService { private static Logger logger = LoggerFactory.getLogger(SecKillService.class); /** 超时时间 */ private static final int TIMEOUT = 10000; @Autowired private RedisLock redisLock; @Autowired private RedisClient redisClient; @Autowired private RestTemplate restTemplate; /** * @Description: 秒杀商品接口 * @param weddingExpoAppoint * @return JsonObject * @exception * @author mazhq * @date 2018/11/18 13:46 */ private JsonObject seckillProduct(long productId) { long time = System.currentTimeMillis() + TIMEOUT; String stockKey = RedisKeysManager.getWeddingExpoSeckillStockKey(productId); //加锁 String lockKey = "weddingExpo:seckill:"+productId; if (!redisLock.lock(lockKey,String.valueOf(time))){ return BaseCode.retCode(100, "没抢到,换个姿势再来一遍"); } String stockNumStr = redisClient.getStr(stockKey); int stockNum = 0; if(StringUtils.isNotBlank(stockNumStr)){ stockNum = Integer.valueOf(stockNumStr); } JsonObject respJson = BaseCode.retCode(ResultCode.failure); if (stockNum == 0) { //库存不足 return BaseCode.retCode(100, "商品已经被抢光了,请留意下次活动"); } else { try { String resp = doseckill(productId); if(null != resp){ respJson = new JsonObject(resp); if(respJson.getInteger("retcode") == 0){ redisClient.increment(stockKey, -1); } Thread.sleep(100); } } catch (InterruptedException ex) { ex.printStackTrace(); } } //解锁 redisLock.unlock(lockKey, String.valueOf(time)); return respJson; } }
主要功能描述就是:
秒杀商品时候先加锁,如果没有获取到锁就释放请求。
加锁后先进行库存判断如果不足释放请求。
进行秒杀下单流程,如果成功库存做减一操作。
最后释放分布式锁。
这样简单的分布式锁处理秒杀功能的方法就搞定了。这种只是处理高并发下多个请求如果有人在秒杀后面的直接不需排队直接释放请求,解放服务器压力(处理流程时间较短,高并发下没有排序要求)。
如果要根据请求时间进行排序,这个方式还需借助队列处理。
以上是关于Redis分布式锁实现简单秒杀功能的主要内容,如果未能解决你的问题,请参考以下文章
Redis进阶学习03---Redis完成秒杀和Redis分布式锁的应用