redis分布式锁的实现

最近项目中出现一个问题,就是在我的项目中,实现了一个商品抢购的功能,当项目运行起来后,用户请求进来会去占用商品,并下单抢购商品,开发完成后,没有使用任何机制通过接口测试,ok没问题,部署测试环境,开始测试后,发现会有多个人同时抢到我的这一件商品,这是脑子第一想到的是出现了线程安全问题,多个线程去争取共享资源,然后就会出现这种超卖的现象,也就是我们所说的出现了线程不安全,这时候的处理方式是对县城加锁,假的是jdk中自带的lock锁,在进入执行的线程的时候,先去加上一把锁,再去做里边的操作,然后最后在finally里边释放锁,ok在测试环境解决了超卖问题,但是我们的项目是集群部署的,当项目部署到两台服务器后,超卖问题又出现了,这次是什么问题呢,排查后发现是因为jdk的lock锁是在当前的jvm中式可以做到对线程加锁的,但是两台服务器后,那么其实就有了两个jvm。如果只剩下一件商品,两个人抢购,每台服务器都接收到一个抢购请求,那么就会出现两个人都抢到了锁,就又出现了超卖现象。这时候就可以引进这片文章的主题了   

不对的地方请大佬指出,小弟感激不尽

分布式锁

分布式锁的加锁流程我们可以分为:抢锁,加锁,阻塞,释放。

分布式锁的实现可以简单分为三种方式:

1.通过数据库实现分布式锁。

mysql使我们常用的数据库,对于mysql的行级锁我们也是很清楚的。对于数据库的分布式锁就是基于行级锁实现的,还是我们上边说的那种场景,两个请求通过两台服务器抢购同一件商品,在线程最开始的时候,我们可以向数据库的一张表中插入一条id为1的数据,如果我们成功插入了那么就认为加锁成功,由于mysql的id不可重复这个时候另一个人的插入操作就会变成失败的额,这个过程就是抢锁和加锁的步骤,然后去做你的业务,商品数量减一,这时候其他请求过来因为没有抢到锁会一直做不了任何事情在这里就防止了超卖(阻塞),做完后,释放锁(释放锁就是把这条数据删除就可以了),这时候另一个请求来查询发现锁已经被释放了,这个请求进去后看到的是已经被买完的商品。这样,就简单呢的防止了超卖。这种方式是简单,但是性能不是很高,不推荐使用。

 

2.通过redis实现分布式锁。

实现思想有点类似于mysql的,但是是基于redis,redis有一个叫做setNX的命令

这个命令就是想redis里边插入一条数据

key:redis数据的key值   uuid:就是对应的value 

“NX”表示使用nx模式 :若给定的 key 已经存在,则 SETNX 不做任何动作。SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。

“PX” 表示超时时间以毫秒为单位,后边的100000表示100秒的超时时间

ok,看过上边参数的解读对于setnx命令也应该有了了解,其实就是我们上边使用数据库行级锁的插入数据那一步操作,如果已经存在就返回失败(加锁失败),不存在就插入并返回ok(加锁成功),这个时候其他请求进来都会显示加锁失败,保证了线程的安全。

解锁操作我们会使用一个lua脚本实现,保证我们的操作原子性,也为了避免误删

这个就是在删除的时候吧我们当时进去的value和现在的value做对比,如果一直就删除,这是为了防止误删锁。

下边直接上代码:

不对的地方请大佬指出,小弟感激不尽

3第三种就是使用zokkerper做分布式锁

目前小弟正在研究中,后期贴出来

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值