2021SC@SDUSC
分布式锁
如果不用分布式锁,有哪些问题?
现在的架构基本都是先分布式再集群化:比如,有库存服务集群,下单服务集群等等。
一个集群中的所有服务器,干的事都是一样的,用户的请求会被分散到集群中的某些服务器上。
最主要的问题就是数据库压力太大
当这些服务器对一些共享资源做读写请求的时候,就可能会出问题。为什么说是可能,因为我们可以通过优化sql的写法,写带锁的sql语句,以及限定某些字段不能为负值等方法,去解决问题,但是带来的问题就是数据库的压力炒鸡大,炒鸡大!其次的是数据共享问题
为什么是其次,因为,即使是单机,不加互斥锁,多线程下环境下,如果业务逻辑上有错误,也会导致问题,比如并发的减库存java代码是这么写的
int num = dao(select num from goods where goods_id = 1;) int num = num - 100; dao(update set num = #{num} where goods_id =1;)
并发情况下,就有可能出问题了,假设两个请求并发执行,原来800 并发减完 有可能只是是700
但是这种错误,我感觉在开发阶段就不会出现这样的错误,所以我认为,如果不加锁最大的问题就是数据库压力太大的问题
分布式锁有什么用?
1:把锁的环节提前了,降低了数据库的压力:
如果真的是所有请求都去修改数据库中的同一个字段,即使到了数据库层面也是串行化写,因为数据库通过互斥锁,保证了同一时刻只能有一个事务在修改同一数据,但是我们的访问请求却都到达了数据库,这样给数据库带来的压力炒鸡大!!!
2:比如现在有1000个商品,分布式锁做到了针对同一商品的集群级别的串行化写
我们通过一个集群级别的互斥锁,让同一时刻只能有一个请求去数据库中修改同一商品我们不用在service层加同步锁,因为不同的请求的请求的可能不是同一个商品!!!
实现的方式
1:redis分布式锁
对一个商品加锁,就是在redis里set一个key是goods_id,value是对应这个请求的唯一的值 的数据,解锁的时候把该数据删掉就行了
1:set goods_id unique_value NX PX 30000(加锁和设置过期时间 必须放在一条指令里,保证是操作原子的)
goods_id 表示锁的对象unique_value 用来区别请求,防止其它请求去解锁不是他创建的锁
NX表示 key不存在的时候这条语句才有用,PX表示过期时间的单位是 毫秒 30000 表示30000毫秒
2:解锁
redis保证执行lua脚本是原子的,解锁可以用lua脚本//判断 redis 中 goods_id 对应的 unique_value 是否等于客户端传进来的value if redis.call("get","goods_id") == "value" then return redis.call("del",KEYS[1]) else return 0