您的位置:首页 > 数据库 > Redis

基于Redis实现分布式锁

2016-06-26 00:09 691 查看
分布式锁的基本功能:

1.同一时刻只能存在一个锁

2.需要解决意外死锁问题,也就是锁能超时自动释放

3.支持主动释放锁


分布式锁解决什么问题:


多进程并发执行任务时,需要保证任务的有序性或者唯一性

准备:

redis版本>=2.6

redis是主从+sentinel模式(为了高可用)

原理:

redis2.6之后,SET命令支持超时和key存在检查,这是一个原子操作

获取锁并设置超时时间:

SET key value [EX seconds] [PX milliseconds] [NX|XX]

删除锁:

DEL key

EX:单位是秒

PX:单位是毫秒

NX:如果key存在,返回nil(失败),不存在返回ok

XX:如果key存在,返回ok,不存在返回nil(失败)

基本操作如图示:



案例:

有一个系统,需要对用户信息进行增删改查操作,系统是多进程的,要求对用户的操作是有序的串行的

上测试代码,可以多开进程观看效果:

# -*- coding: utf-8 -*-

import time
import redis

# 获取锁
def get_lock(uid):
# 连接redis
r = redis.StrictRedis(host='localhost', port=6379, db=0, socket_timeout=1, socket_connect_timeout=3)

# 当前时间戳,用于删除锁时check
sec = str(time.time())

# 处理超时时间
timeout = 300

# 试图锁住uid
while True:
res = r.set(uid, sec, ex=timeout, nx=True)
if res == True:
print "get lock succeed, return"
return True, sec
else:
print "get lock failed, lock exist, wait"
time.sleep(0.001)
return False, None

# 释放锁
def del_lock(uid, sec):
# 连接redis
r = redis.StrictRedis(host='localhost', port=6379, db=0, socket_timeout=1, socket_connect_timeout=3)

# 校验
redis_sec = r.get(uid)
if sec != redis_sec:
print "check permission failed :%s" % uid
return False
print "check permission succeed :%s" % uid

#删除
res = r.delete(uid)
if res:
print "del key succeed :%s" % uid
return False
else:
print "del key failed :%s" % uid
return True

if __name__ == '__main__':

uid = "001"

while True:
status, sec = get_lock(uid)
if status:
del_lock(uid, sec)
time.sleep(0.001)


缺陷:

a) 一旦redis发生主从切换,可能会丢失一些锁,

b) 如果对锁的要求很高,可以参考redis官方提供的方案:http://redis.io/topics/distlock

c) 范例代码只能当作原理来理解,实际上有很多需要优化的地方,优化可参考:https://pypi.python.org/pypi/python-redis-lock

End;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息