博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
redis 分布式锁
阅读量:3709 次
发布时间:2019-05-21

本文共 1467 字,大约阅读时间需要 4 分钟。

前言

上一篇写了砸金蛋。但是没有考虑高并发。。。

举个例子,每个用户每天最大砸金蛋次数为100次,超过100次之后就不能再砸了。今日累计砸金蛋次数存在redis中,用户每次砸金蛋请求,都会去取redis中存的累计砸金蛋次数,判断是否超过100次。超过就抛异常,不能再砸金蛋了。

在没有处理高并发的情况下,模拟同一用户,发起200次请求,发现用户砸了103次金蛋!!!预期结果是砸100次!

不难理解,当同一时间,服务器收到多个请求,去判断砸金蛋次数是否超过100?可能会出现多个请求获取到的redis的值都是同一个值。简单点说,用户已经累计砸了99次,还剩余一次。这个时候,用户一瞬间请求了2次,这两次请求获取到的今日砸蛋总数都是99,也就意味着这两次请求都会成功。最后用户砸蛋:99+2=101次

分析

最大的问题还是:多个进程访问同一个共享资源。如果是单系统的话,用synchronized代码块就可以解决上述问题。

目前我们这个项目这用了分布式,并且做了集群。。。传统的加锁的做法(如java的synchronized和Lock)也都没用。。。
然后我想的办法:1.加redis分布式锁 2.走消息队列

Redis分布式锁常见的应用场景:电商项目中的秒杀活动,IP访问限制,以及如大转盘,砸金蛋活动等。

最后用的第一种方法:
大致流程就是:请求入口处先加锁,并设置10s后自动释放锁。try - catch的finally中判断锁是否还存在,存在的话,手动释放锁。
代码如下

/**  * 用户抽奖  *  * @param userId  * @param consumeType 抽奖消耗类型 1:金币 2:次数  */ @RequestMapping("eggs_lottery") @ResponseBody public Map
eggsLottery(Integer userId, Integer consumeType) { if (userId == null || consumeType == null) { throw new BusiException(E.INVALID_PARAMETER); } String key = "eggsLottery_" + userId; // redis 分布式锁 10:10s后自动释放 RLock rlock = RedissonLockUtil.getFairLock(key, 10); if (null == rlock) { // 没拿到锁 throw new BusiException(E.INVALID_REQUEST, "朋友, 人也太多了, 换个姿势再试试~"); } try { if (rlock.isLocked()) { // 砸金蛋.. return goldEggsService.eggsLottery(userId, consumeType); } } finally { // 执行完 锁还存在 主动释放 if (null != rlock) { rlock.unlock(); } } return null; }

转载地址:http://qczjn.baihongyu.com/

你可能感兴趣的文章
STM32—位带操作
查看>>
STM32—时钟树(结合系统时钟函数理解)
查看>>
Keil5中出现中文乱码的解决方法
查看>>
STM32—中断详解(配合按键中断代码,代码亲测)
查看>>
STM32—SysTick系统定时器
查看>>
STM32—重定向printf和getchar函数到串口
查看>>
STM32—串口通讯详解
查看>>
MarkDown编辑器
查看>>
STM32—DMA存储器到外设
查看>>
STM32—IIC通信(软件实现底层函数)
查看>>
Markdown编辑器 数学公式编写
查看>>
复变函数基础概述
查看>>
电路分析基础概述
查看>>
操作系统简析
查看>>
STM32—SPI详解
查看>>
keil_lic.exe注册机使用
查看>>
【写一个操作系统】0—出师未捷身先死
查看>>
【写一个操作系统】1—hello world重出江湖
查看>>
【写一个操作系统】2—VMware创建软盘映像
查看>>
return的各种用法
查看>>