分布式锁的见解

实现分布式锁可以利用公共组件Redis

  • redis的setnx:设置key value 当且仅当key不存在,设置成功返回1,失败返回0
  1. 最简单得就是获取在redis上获取一个key,然后根据返回结果处理逻辑
# 伪代码
ret = redis.setnx(key,value)
if ret:
   stock = redis.get('stock')   # 100
   if stock > 0:
       stock -= 1
   else:
       return Response('库存不足')
else:
   return Response('忙')
redis.del(key)
  • 问题:如果程序运行时报错,锁没有被释放,死锁产生。
  • 方案:在finally中释放锁,程序运行报错会进入finally释放锁
  1. 在此基础上改进,加入try,finally
try:
	ret = redis.setnx(key,value)
	if ret:
		stock = redis.get('stock')   # 100
		if stock > 0:
		    stock -= 1
		else:
		    return Response('库存不足')
	else:
		return Response('忙')
finally:
	redis.del(key)
	
  • 问题:如果应用被kill了,那么就不会进入finally释放锁
  • 方案:加过期时间,死锁一小段时间可以接受

try:
	ret = redis.set(key, value, ex=10,nx=True)  #  10秒后锁释放,产生死锁也会解除
	if ret:
		stock = redis.get('stock')   # 100
		if stock > 0:
		    stock -= 1
		else:
		    return Response('库存不足')
	else:
		return Response('忙')
finally:
	redis.del(key)
  • 问题:

场景:过期时间为10s,若某个请求需要15秒完成,在10s的时候Redis服务就会将这个key释放掉,第二个请求来了之后请求key,过了5秒钟,第一个请求完成主动的释放了key,但是第二个请求可能还未完成,第三个请求来了,请求key,第二个请求完成主动释放key。

后果: 后请求的redis_key被前者释放,导致失效。

  • 方案:设置时,键是唯一的,但是值可以设置为当前线程的信息,在主动释放的时候判断是否为当前线程持有的锁。

  • 不足:在超时的时候还是会发生两个线程持有同一个锁。

  • 弥补不足:当成功setnx后,开一个守护线程,判断当前线程是否还持有锁,如果有,就重新设置过期时间,否则,说明主线程释放了锁。代码逻辑很简单,但是实现可能会出现各种Bug,可以使用redis-py的锁
    使用方式就是锁的方式:lock = Lock() lock.acquire

你可能感兴趣的:(随笔)