分布式锁问题

文章讨论了在分布式系统中如何使用Redis解决一人一单问题,通过设置内部锁在单机环境下可以解决问题,但在集群环境中需要分布式锁。初步方案是利用Redis的互斥性设置过期锁,但存在并发删除问题。优化方案是为锁添加唯一标识以防止误删,进一步通过Lua脚本来保证删除锁操作的原子性,以提高锁的安全性和互斥性。
摘要由CSDN通过智能技术生成

针对一人一单问题,采用锁的方式可以解决在单机部署下此问题。

但是在面对集群部署情况,单独的内部监视锁会出现并发问题。

在多线程访问时,可能会发生同时获取到以用户ID作为锁的情况,

因为在不同机器内部,锁并非同一把,所以针对分布式情况下,不同集群部署的机器,

无法共用同一把锁的情况,使用需要使用分布式锁来解决此问题。

本次采用REDIS实现分布式锁

1-初级实现

利用redis的互斥特性实现获取和释放锁

  1. 向redis中存入以userId为标志的互斥锁,同时设置过期时间(以防止系统奔溃引起的永远无法获取到互斥锁)

  1. 如果设置锁失败,则返回错误

  1. 如果设置锁成功则执行业务

  1. 执行成功后释放锁,删除掉redis中的互斥锁,完成分布式锁的步骤

初步完成的分布式锁可以解决分布式系统中存在的并发问题,

但是仍旧不完美存在系统在并发情况下的误删问题,

在访问集群的情况下,当某线程获取到互斥锁发生线程堵塞,该线程在redis中的互斥锁会在达到过期时间后失效,释放掉锁,此时其他先线程可以获取到互斥锁执行任务,但是已经堵塞的线程在死灰复燃后,依旧向下执行会执行到删除redis中互斥锁的操作,于是其余线程发生了可以再次获取到锁执行的情况,总结发生了非一人一单的情况,针对于此,对初步实现的redis互斥锁进行优化。

解决方案

在存入redis互斥锁的时候,对redis互斥锁的value做标识,一般使用uuid或者其他随机数字,生成当前线程的唯一标识作为自己的互斥锁,在删除释放锁的时候,对value值进行判断,如果锁值不一致,则证明不是同一个线程的互斥锁,不允许进行删除释放。

执行逻辑

  1. 判断锁是否存在

  1. 如果存在证明已经有线程获取到了锁,此时直接返回错误

  1. 如果不存在,则执行在redis中插入锁,

  1. 执行业务逻辑后,在删除互斥锁之前进行判断,判断互斥锁的value值是否和时本系统的生成的值相等,如果不相等不允许删除互斥锁,如果相对则删除redis中的互斥锁。

(即通过uuid随机数生成的随机值+线程ID)

至此解决大部分问题

然而依旧存在原子性问题,

当线程1在执行过程中,判断互斥锁的value值相同后,做出是当前线程的判断后,线程发生阻塞(一般发生在垃圾回收),,此时线程2同样可以获取到锁,执行任务,在此时线程1,死灰复燃后继续执行,会去删除不属于自己线程的锁,会造成其他线程依旧可以获取到锁的情况,使一人一单的互斥锁失效。

解决方法

提高互斥锁的原子性,利用Lua脚本解决多条命令原子性的问题。

redis分布式锁的基本实现思路

利用set nx ex 获取互斥锁,并设置过期时间,

同时保存线程标识

释放互斥锁时先判断线程标识与自己是否一致,一致则删除锁

特性:

利用set nx满足互斥性

利用set ex保证故障时锁依旧能释放,避免死锁发生

,提高安全性

利用redis集群部署保证高可用和高并发特性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值