系统部署架构
如果同时有多个请求访问,对存入redis中的数据进行减操作,但是由于业务中存在着一些逻辑,导致无法使用redis提供的原子性的decr操作。则会存在数据一致性的问题,即使在业务代码中加锁。
处理方式一
此时最简单的方式是在操作逻辑中使用redis的setnx操作设置一个值,并设置超时时间。在减操作完成后,删除相关的键。
但是这会存在一个问题,并发量不大的情况下,这一切都会好好运行,但是可能某个意外,导致:
当前线程在删除相关的键之前,超时时间已经到了,然后别的线程又运行的很快,别人又把这把锁给删除了。此时会存在空档期,导致又被别的线程获取到锁,总之会存在不一致的问题。
处理方式二
出现上面问题的原因是自己获取的锁被别人删除了。此时可以在获取锁之前设置UUID,将setnx的value设置成UUID,在删除锁时,判断一下,这个锁必须可以和这个UUID对应,才让删除。
但是安装上面的玩法还是可能存在问题,这个问题的根本原因是超时时间引起的,比如删除锁的伪代码是如下写法,即非原子性操作:
if uuid == redis.get('key'): // 在此时锁超时
delete key
处理方式三
在当前处理逻辑中再开一个线程,去检测当前线程是否还持有这把锁,如果有,则延长锁的超时时间。真实使用可以使用redission
但是上面的处理方式还是可能会存在问题。此时问题并不是出现在server端上,而是出现在redis上,因为一般情况下可能使用的是redis集群,但是如果你的redis集群使用的是master-slave架构,如果在master节点同步过程中master挂掉,还是会导致数据不一致问题,此时就需要引入zookeeper了,让它去管理redis集群,实现数据的一致性。CAP原则
处理方式四
通过上面的这些操作可以看到,为了实现数据的一致性,会导致性能降低。但是我们回过头来重新来审视这个问题:
对
存
入
r
e
d
i
s
中
的
数
据
进
行
减
操
作
对存入redis中的数据进行减操作
对存入redis中的数据进行减操作
为提高并发,我们可以对原始数据重新组织一下:也就是分段,比如我们需要对100进行减操作。但是完全可以把这个数据分成5个20,显然,在这种情况下我们从原先的只能获取一把锁,变成了可以获取5把锁。
不过,这样分段的做法也会引入问题,比如,在某个段中的值为2,但是业务中导致此时要减3,此时无法减完。大家可以根据具体的业务自行思考优化的方法