基于Redis实现分布式锁

分布式锁的基本功能:
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(失败)

基本操作如图示:

基于Redis实现分布式锁_第1张图片


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


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

# -*- 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;


你可能感兴趣的:(高可用,redis,Redis)