分散ロックの見解

6313 ワード

分散ロックを実装するには、共通コンポーネントRedisを使用します.
  • redisのsetnx : key value key , 1, 0
  • 最も簡単なのは、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解放ロック
  • に入る
  • これに基づいて改良され、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)
    
  • 問題:
  • シーン:期限切れは10 sで、あるリクエストが15秒で完了すると、10 sでRedisサービスがこのキーを解放し、2番目のリクエストが来てからキーを要求し、5秒後、1番目のリクエストはアクティブにキーを解放したが、2番目のリクエストはまだ完了していない可能性があり、3番目のリクエストが来て、リクエストキー、2番目のリクエストはアクティブにキーを解放した. :後で要求されたredis_keyは前者に解放され、失効を招いた.
  • スキーム:設定時にキーは一意であるが、値は現在のスレッドの情報に設定でき、アクティブ解放時に現在のスレッドが持つロックであるか否かを判断する.
  • 不足:タイムアウト時に2つのスレッドが同じロックを持っていることが発生します.
  • 補完不足:setnxに成功した後、ガードスレッドを開き、現在のスレッドにロックがあるかどうかを判断し、ある場合は期限切れ時間を再設定します.そうしないと、プライマリスレッドがロックを解除したことを示します.コードロジックは簡単であるが、実装には様々なバグが発生する可能性があり、redis-pyを使用できるロックの使用方法はロックの方法である:lock=Lock()lock.acquire